学习笔记 --Spring 框架

本贴最后更新于 2747 天前,其中的信息可能已经事过景迁

//概述

轻量级,一站式,开发框架

IoC,Inversion of Control,控制反转

DI,Dependency Injection,依赖注入

AOP,Aspect-Oriented Programming,面向切面编程:业务逻辑与非业务逻辑分离,如日志、安全...

IoC 容器:

对象创建、装配

对象生命周期管理

上下文环境

//IoC 容器

IoC = ApplicationContext (org.springframework.context, spring-context)

初始化

ApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");

ApplicationContext context = new FileSystemXmlApplicationContext("/home/user/conf/application-context.xml");

或在 web.xml 中

<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>classpath:application-context.xml</param-value>
</context-param>

<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

Bean 定义

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context.xsd">

	<bean id="screwDriver" class="com.netease.course.ScrewDriver"></bean>

</beans>

Bean 使用

//初始化容器

ApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");

//获取对象

ScrewDriver screwDriver = context.getBean("screwDriver", ScrewDriver.class);

//使用对象

screwDriver.use();

Bean 作用域

singleton,单例

<bean id="screwDriver" class="com.netease.course.ScrewDriver" scope="singleton"></bean>

默认为单例
prototype,每次引用创建一个实例

<bean id="screwDriver" class="com.netease.course.ScrewDriver" scope="prototype"></bean>

request scope, requestBean
session scope, sessionBean
application scope, appBean
global scope

Bean 生命周期回调

创建,申请资源
可以通过实现接口

public interface InitializingBean {
	void afterPropertiesSet() throws Exception;
}

或者直接在 application-context.xml 中配置

<bean id="screwDriver" class="com.netease.course.ScrewDriver" init-method="init"></bean>

对应代码

public class ScrewDriver {
   public void init() {
		System.out.println("Init screwDriver");
   }
}

销毁
可以通过实现接口

public interface DisposableBean {
	void destroy() throws Exception;
}

或者直接在 application-context.xml 中配置

<bean id="screwDriver" class="com.netease.course.ScrewDriver" destroy-method="cleanup"></bean>

对应代码

public class ScrewDriver {
   public void cleanup() {
		System.out.println("Cleanup screwDriver");
   }
}

关闭 Bean

((ConfigurableApplicationContext) context).close();

依赖注入

构造函数,强依赖

Setter 函数,可选依赖

配置 bean 的类的构造函数的参数

 <bean id="straightHeader" class="com.netease.course.StraightHeader">
	  <constructor-arg value="red"></constructor-arg>
	  <constructor-arg value="15"></constructor-arg>
  </bean>

<bean id="straightHeader" class="com.netease.course.StraightHeader">
    <constructor-arg index="0" value="red"></constructor-arg>
    <constructor-arg index="1" value="15"></constructor-arg>
</bean>

<bean id="straightHeader" class="com.netease.course.StraightHeader">
    <constructor-arg type="java.lang.String" value="red"></constructor-arg>
    <constructor-arg type="int" value="15"></constructor-arg>
</bean>

<bean id="straightHeader" class="com.netease.course.StraightHeader">
    <constructor-arg name="color" value="red"></constructor-arg>
    <constructor-arg name="size" value="15"></constructor-arg>
</bean>

需要传递集合类型的构造函数参数(如 map)时

<bean id="straightHeader" class="com.netease.course.StraightHeader">
    <constructor-arg>
        <map>
            <entry key="color" value="red"></entry>
            <entry key="size" value="15"></entry>
        </map>
    </constructor-arg>
    <constructor-arg name="size" value="15"></constructor-arg>
</bean>

传入 list 时

<bean id="straightHeader" class="com.netease.course.StraightHeader">
    <constructor-arg>
        <list>
            <value>red</value>
            <value>15</value>
        </list>
    </constructor-arg>
    <constructor-arg name="size" value="15"></constructor-arg>
</bean>

传入 Properties 时

<bean id="straightHeader" class="com.netease.course.StraightHeader">
    <constructor-arg>
        <props>
            <prop key="color">red</prop>
            <prop key="size">15</prop>
        </props>
    </constructor-arg>
    <constructor-arg name="size" value="15"></constructor-arg>
</bean>

从外部倒入配置时

  <bean id="straightHeader" class="com.netease.course.StraightHeader">
	  <constructor-arg name="color" value="${color}"></constructor-arg>
	  <constructor-arg name="size" value="${size}"></constructor-arg>
  </bean>
  <bean id="headerProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
	<property name="location" value="classpath:header.properties" />
</bean>

在一个 bean 中添加所依赖的 bean

<bean id="screwDriver" class="com.netease.course.ScrewDriver">
    <constructor-arg>
        <ref bean="straightHeader" />
    </constructor-arg>
</bean>

通过 Setter 方法注入依赖

<bean id="straightHeader" class="com.netease.course.StraightHeader">
    <property name="color" value="${color}"></property>
    <property name="size" value="${size}"></property>
</bean>

自动装配

constructor 是按 byType 方式注入

   <bean id="screwDriver" class="com.netease.course.ScrewDriver" autowire="constructor">
	</bean>

   <bean id="screwDriver" class="com.netease.course.ScrewDriver" autowire="byName">
	</bean>

 <bean id="screwDriver" class="com.netease.course.ScrewDriver" autowire="byType">
  </bean>

Annotation

@Component:定义 Bean,或 @Component("name")

@Value:properties 注入

@Autowired & @Resource:自动装配依赖

@PostConstruct & @PreDestroy:生命周期回调

在 xml 中加入

 <context:component-scan base-package="com.netease.course" />

//AOP 技术

AOP 术语

Aspect:日志、安全等功能

Join point:函数执行或者属性访问

Advice:在某个函数执行点上要执行的切面功能

Pointcut:匹配横切目标函数的表达式

Advice 类型

Before:函数执行之前

After returning:函数正常返回之后

After throwing:函数抛出异常之后

After finally:函数返回之后

Around:函数执行前后

Spring AOP

非完整 AOP 实现

整合 AOP 和与 IoC

XML schema-based AOP

@AspectJ annotation-based AOP

@AspecsJ annotation-based AOP

aspectjweaver.jar

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
	http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

	<aop:aspectj-autoproxy />

</beans>

定义 Aspect

   <bean id="loggingAspect" class="com.netease.course.LoggingAspect">
		   <!-- configure properties of aspect here as normal -->
   </bean>

相应代码中类名前加入 @Aspect

定义 Pointcut

@Pointcut("execution(* com.netease.course.Calculator.*(..))")

private void arithmetic() {}

Pointcut 表达式

designator(modifiers? return-type declaring-type? name(param) throws?)

designator: execution, within

modifiers: public, private

return-type: 返回类型,*

declaring-type: 包名,类名

name: 函数名,*

param: 参数列表,()无参,(..)任意参数

throws: 异常类型

可以组合

定义 Advice

@Before("com.netease.course.LoggingAspect.arithmetic()")

public void doLog() {

  //

}

@Before("execution(* com.netease.course.Calculator.*(..))")

public void doLog() {

    //

}

@AfterReturning("com.netease.course.LoggingAspect.arithmetic()")

public void doLog() {

    //

}

@AfterThrowing("com.netease.course.LoggingAspect.arithmetic()")

public void doLog() {

    //

}

@After("com.netease.course.LoggingAspect.arithmetic()")

public void doLog() {

    //

}

Advice 参数

函数上下文信息

@Before("com.netease.course.LoggingAspect.arithmetic()")

public void doLog(JoinPoint jp) {

    System.out.println(jp.getSignature() + ", " + jp.getArgs());

}

@Around("com.netease.course.LoggingAspect.arithmetic()")

public void doLog(ProceedingJoinPoint pjp) {

    System.out.println("start method: " + pjp.toString());

    Object retVal = pjp.proceed();

    System.out.println("stop method: " + pjp.toString());

}

返回值

@AfterReturning(pointcut="com.netease.course.LoggingAspect.arithmetic()"),

                returning="retVal")

public void doLog(Object retVal) {

    //

}

异常

@AfterThrowing(pointcut="com.netease.course.LoggingAspect.arithmetic()"),

               throwing="ex")

public void doLog(IllegalArgumentException ex) {

    //

}

目标函数参数

@Before("com.netease.course.LoggingAspect.arithmetic() && args(a, ..)")

public void doLog(JoinPoint jp, int a) {

    //

}

XML schema-based AOP

定义 Aspect 和 PointCut

 <aop:config>
	 <aop:aspect id="loggingAspect" ref="loggingBean">
		 <aop:pointcut id="arithmetic" expression="execution(* com.netease.course.Calculator.*(..))" />
	 </aop:aspect>
 </aop:config>

定义 Advice

 <aop:config>
	 <aop:aspect id="loggingAspect" ref="loggingBean">
		 <aop:before pointcut-ref="arithmetic" method="doLog" />
	 </aop:aspect>
 </aop:config>

 <aop:config>
	 <aop:aspect id="loggingAspect" ref="loggingBean">
		 <aop:before pointcut="execution(* com.netease.course.Calculator.*(..))" method="doLog" />
	 </aop:aspect>
 </aop:config>

 <aop:config>
	 <aop:aspect id="loggingAspect" ref="loggingBean">
		 <aop:after-returning pointcut-ref="arithmetic" returning="retVal" method="doLog" />
	 </aop:aspect>
 </aop:config>

 <aop:config>
	 <aop:aspect id="loggingAspect" ref="loggingBean">
		 <aop:after-throwing pointcut-ref="arithmetic" throwing="ex" method="doLog" />
	 </aop:aspect>
 </aop:config>

   <aop:aspect id="loggingAspect" ref="loggingBean">
       <aop:around pointcut-ref="arithmetic" method="doLog" />
   </aop:aspect>

//数据访问

DAO,Data Access Object

数据访问相关接口

ORM,Object Relation Mapping

对象关系映射

DataSource (javax.sql)

DriverManagerDataSource (org.springframework.jdbc.datasource)

BasicDataSource (org.apache.commons.dbcp)

   <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
	   <property name="driverClassName" value="${jdbc.driverClassName}" />
	   <property name="url" value="${jdbc.url}" />
	   <property name="username" value="${jdbc.username}" />
	   <property name="password" value="${jdbc.password}" />
   </bean>

   <context:property-placeholder location="db.properties" />

JdbcTemplate (org.springframework.jdbc.core)
设置 JdbcTemplate 的数据库配置信息

private JdbcTemplate jdbcTemplate;

@Autowired
public void setDataSource(DataSource dataSource) {
    this.jdbcTemplate = new JdbcTemplate(dataSource);
}

查询操作

    int rowCount = this.jdbcTemplate.queryForObject("select count(*) from user", Integer.class);
    int countOfNamedJoe = this.jdbcTemplate.queryForObject("select count(*) from user where first_name = ?", Integer.class, "Joe");
    String lastName = this.jdbcTemplate.queryForObject("select last_name from user where id = ?", new Object[]{1212L}, String.class);

更改操作

this.jdbcTemplate.update("insert into user (first_name, last_name) values (?, ?)", "Meimei", "Han");
或
this.jdbcTemplate.execute("create table user (id integer, first_name varchar(100), last_name varchar(100))");

对象匹配

    User user = this.jdbcTemplate.queryForObject("select last_name from user where id = ?",
            new Object[]{1212L},
            new RowMapper<User>() {
        public User mapRow(ResultSet rs, int rowNum) throws SQLException {
            User user = new User();
            user.setFirstName(rs.getString("first_name"));
            user.setLastName(rs.getString("last_name"));
            return user;
        }
    });

    List<User> users = this.jdbcTemplate.query("select last_name from user where id = ?",
            new Object[]{1212L},
            new RowMapper<User>() {
        public User mapRow(ResultSet rs, int rowNum) throws SQLException {
            User user = new User();
            user.setFirstName(rs.getString("first_name"));
            user.setLastName(rs.getString("last_name"));
            return user;
        }
    });

定义 JdbcTemplate

public class JdbcExampleDao implements ExampleDao {
	private JdbcTemplate jdbcTemplate;
	public void setDataSource(DataSource dataSource) {
		this.jdbcTemplate = new JdbcTemplate(dataSource);
	}
	//...DAO接口实现
}

可以在 xml 中配置相应的 bean
也可以用 annotation 的方法,如下:

@Repository
public class JdbcExampleDao implements ExampleDao {
	private JdbcTemplate jdbcTemplate;
	@Autowired
	public void setDataSource(DataSource dataSource) {
		this.jdbcTemplate = new JdbcTemplate(dataSource);
	}
	//...DAO接口实现
}

NamedParameterJdbcTemplate (org.springframework.jdbc.core)

private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

@Autowired
public void setDataSource(DataSource dataSource) {
    this.namedParameterJdbcTemplate= new NamedParameterJdbcTemplate (dataSource);
}

public int countOfUserByFirstName(String firstName) {
	String sql = "select count(*) from usertest where first_name = :first_name";
	Map<String, String> namedParameters = Collections.singletonMap("first_name", firstName);
	return this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class);
}

其他 api 接口

queryForObject(String sql, Map<String, ?> paramMap, RowMapper<T> rowMapper)
queryForObject(String sql, SqlParameterSource paramSource, Class<T> requiredType)

SqlParameterSource: MapSqlParameterSource, BeanPropertySqlParameterSource (org.springframework.jdbc.core.namedparam)
如:
public int countOfUserByFirstName(User user) {
	String sql = "select count(*) from usertest where first_name = :first_name";
	SqlParameterSource namedParameters = new BeanPropertySqlParameterSource(user);
	return this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class);
}

异常处理

DataAccessException, "unchecked", 是一个基类 (org.springframework.dao)

//事务管理

spring 事务管理

统一的事务编程模型,编程式事务及声明式事务(AOP)

public interface PlatformTransactionManager {

	TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;

	void commit(TransactionStatus status) throws TransactionException;

	void rollback(TransactionStatus status) throws TransactionException;

}

事务管理器

PlatformTransactionManager (org.springframework.transaction):

DataSourceTransactionManager (org.springframework.jdbc.datasource), JDBC

HibernateTransactionManager (org.springframework.orm.hibernate), Hibernate

TransactionDefinition

getName:事务名称

getIsolationLevel:隔离级别

getPropagationBehavior:传播行为

getTimeout:超时时间

isReadOnly:是否只读

TransactionStatus

isNewTransaction:是否是新事务

hasSavePoint:是否有 savepoint(诊断,NESTED)

isCompleted:是否完成

isRollbackOnly:事务结果是否是 rollback-only
setRollbackOnly:设置事务为 rollback-only

隔离级别

ISOLATION_READ_UNCOMMITTED:读未提交

ISOLATION_READ_COMMITTED:读提交

ISOLATION_REPEATABLE_READ:重复读

ISOLATION_SERIALIZABLE:串行化

ISOLATION_DEFAULT:默认

传播行为

PROPAGATION_MANDATORY:必须在一个事务中运行,不存在则抛异常

PROPAGATION_NEVER:不应该在事务中运行,存在则抛异常

PROPAGATION_NOT_SUPPORTED:不应该在事务中运行,存在则挂起

PROPAGATION_SUPPORTS:不需要事务,有则在事务中执行

PROPAGATION_REQUIRED:必须在事务中执行,如果不存在,则启动新事务(内部事务会影响外部事务)

PROPAGATION_NESTED:必须在事务中执行,如果不存在,则启动新事务(事务之间互不影响)

PROPAGATION_REQUIRES_NEW:必须在新事务中执行,挂起当前事务(独立 physical 事务)

声明式事务

添加 schema

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
	http://www.springframework.org/schema/tx
	http://www.springframework.org/schema/tx/spring-tx.xsd
	http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

定义事务管理器

<bean id="txManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">
    <property name="driverClassName" value="${jdbc.driverClassName}" />
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
</bean>
<context:property-placeholder location="db.properties" />

定义事务 Advice

<tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
        <tx:method name="get*" read-only="true" />
        <tx:method name="*" />
    </tx:attributes>
</tx:advice>

定义 Pointcut

<aop:config>
    <aop:pointcut id="daoOperation"
        expression="execution(* com.netease.course.AccountDao.*(..))" />
    <aop:advisor advice-ref="txAdvice" pointcut-ref="daoOperation" />
</aop:config>

配置 <tx:method />

name: 匹配的函数名称,支持*匹配
propagation:事务传播行为
isolation:事务隔离级别
timeout:超时
read-only:是否只读事务
rollback-for:触发回滚的异常,用逗号分隔
no-rollback-for:不触发回滚的异常

采用 annotation 方法
@Transactional
xml 中添加

<tx:annotation-driven transaction-manager="txManager" />

相应代码

@Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
public boolean deleteClusterByClusterId(Sring clusterId) {
	// do work
}

@transactional
value:使用的 TransactionManager
propagation:事务传播行为
isolation:事务隔离级别
timeout:超时
readOnly:是否只读
rollbackFor:触发回滚的异常类对象数组
rollbackForClassName:触发回滚的异常类名称数组
noRollbackFor:不触发回滚的异常类对象数组
noRollbackForClassName:不触发回滚的异常类名称数组

编程式事务

定义 TransactionTemplate

public class SimpleService implements Service {
	private final TransactionTemplate transactionTemplate;
	public SimpleService(PlatformTransactionManager transactionManager) {
		this.transactionTemplate = new TransactionTemplate(transactionManager);
		this.transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
		this.transactionTemplate.setTimeout(30);
	}
}

使用 TransactionTemplate

public Object someMethod() {
    return transactionTemplate.execute(new TransactionCallback() {
        public Object doInTransaction(TransactionStatus status) {
            updateOperation1();
            return resultOfUpdateOperation2();
        }
    });
}

或(不返回结果)

public Object someMethodWithoutResult() {
    return transactionTemplate.execute(new TransactionCallbackWithoutResult() {
        protected void doInTransactionWithoutResult(TransactionStatus status) {
            updateOperation1();
            updateOperation2();
        }
    });
}

或(设置为遇到异常时只能回滚)

public Object someMethodWithoutResult() {
    return transactionTemplate
            .execute(new TransactionCallbackWithoutResult() {
                protected void doInTransactionWithoutResult(
                        TransactionStatus status) {
                    try {
                        updateOperation1();
                        updateOperation2();
                    } catch (SomeBusinessException e) {
                        status.setRollbackOnly();
                    }
                }
            });
}

PlatformTransactionManager 的实现

DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setName("TxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

TransactionStatus status = txManager.getTransaction(def);
try {
    //do something
} catch (MyException ex) {
    txManager.rollback(status);
    throw ex;
}
txManager.commit(status);

整合 MyBatis

SqlSessionFactory
添加 mybatis-spring 依赖

    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>1.2.3</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.3.0</version>
    </dependency>

定义 SqlSessionFactoryBean

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="configLocation" value="classpath:sqlMapConfig.xml" />
    <property name="mapperLocations" value="classpath*:sample/config/mappers/**/*.xml" />
</bean>

定义 Mapper

public interface UserMapper {

	@Select("SELECT * FROM users WHERE id = #{userId}")
	User getUser(@Param("userId") String userId);
}

配置结果映射

@Results({
    @Result(property="id", column="id"),
    @Result(property="firstName", column="first_name"),
    @Result(property="lastName", column="last_name")
})

或者采用 xml 的方法,见 Mybatis 部分

定义 Mapper Bean

<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
    <property name="mapperInterface" value="com.netease.course.UserMapper" />
    <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

或采用自动发现的机制

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:mybatis="http://mybatis.org/schema/mybatis-spring"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans.xsd
	http://mybatis.org/schema/mybatis-spring
	http://mybatis.org/schema/mybatis-spring.xsd">

	<mybatis:scan base-package="com.netease.course" />
</beans>

当需要指定 SqlSessionFactory 时

<mybatis:scan base-package="com.netease.course" factory-ref="sqlSessionFactory" />

或者

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.netease.course" />
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
</bean>

使用 Mapper

public class SomeService {
	@Autowired
	private UserMapper userMapper;
	public User getUser(String userId) {
		return userMapper.getUser(userId);
	}
}

定义 SqlSessionTemplate 使用

<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
    <constructor-arg index="0" ref="sqlSessionFactory" />
</bean>

SqlSessionTemplate 使用

public class UserDao {
	@Autowired
	private SqlSession sqlSession;
	public User getUser(String userId) {
		return (User) sqlSession.selectOne("com.netease.course.UserMapper.getUser", userId);
	}
}

//Web 框架

DispatcherServlet

[servlet-name]-servlet.xml
HandlerMapping
Controllers
View 解析相关

WebApplicationContext

ContextLoaderListener

<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>/WEB-INF/applicationContext*.xml</param-value>
</context-param>

Servlet WebApplicationContext (containing controllers, view resolvers, and other web-related beans)
Root WebAppliacationContext (containing middler-tier services, datasources, etc.)

实现 Controller

  @Controller
  @RequestMapping(value = "/hello")
  public class HelloController {
	  @RequestMapping(value = "/spring")
	  public void spring(HttpServletResponse response) throws IOException {
		  response.getWriter().write("Hello, Spring Web!!");
	  }
  }

定义 Controller

自动发现

 <context:component-scan base-package="com.netease.course" />

@RequestMapping
name: 名称
value & path: 路径,如"/hello"
method: 请求方法,如"GET"
params: 请求参数
headers: 请求头
consumes: 请求的媒体类型,"Content-Type"
produces: 响应的媒体类型,"ACCEPT"

注入路径中的变量

@RequestMapping(value="/users/{userId}")
public String webMethod(@PathVariable String userId) {
    //do work
}

@RequestMapping(value="/users/{userId:[a-z]+}")
public String webMethod(@PathVariable String userId) {
    //do work
}

函数参数
HttpServletRequest / HttpServletResponse, HttpSession (Servlet API)
Reader / Writer
@PathVariable
@RequestParam
@RequestHeader
HttpEntity
@RequestBody
Map / Model / ModelMap

函数返回值
void
String: view 名称,@ResponseBody
HttpEntity
View
Map
Model
ModelAndView

函数实现

@RequestMapping(value="/spring/{user}")

public void helloSpring(

        @PathVariable("user") String user,

        @RequestParam("msg") String msg,

        @RequestHeader("host") String host,

        HttpServletRequest request,

        Writer writer) throws IOException {

    writer.write("URI: " + request.getRequestURI());

    writer.write("Hello, " + user + ": " + msg + ", host=" + host);

}

@RequestMapping(value="/spring/login")

public void login(@ModelAttribute User user, Writer writer) {

    //do work

}

@RequestMapping(value="/users/login")

public String login(@RequestParam("name") String name, @RequestParam("password") String password, ModelMap map) {

    map.addAttribute("name", name);

    map.addAttribute("password", "******");

    return "user";

}

ModelMap
ModelMap 的实例是由 bboss mvc 框架自动创建并作为控制器方法参数传入,用户无需自己创建。

public String xxxxmethod(String someparam,ModelMap model)   
{   
	 //省略方法处理逻辑若干   
	  //将数据放置到ModelMap对象model中,第二个参数可以是任何java类型   
	  model.addAttribute("key",someparam);   
	 ......   
	 //返回跳转地址   
	  return "path:handleok";   
}  

ModelAndView
ModelAndView 的实例是由用户手动创建的,这也是和 ModelMap 的一个区别。

public ModelAndView xxxxmethod(String someparam)   
{   
	 //省略方法处理逻辑若干   
	  //构建ModelAndView实例,并设置跳转地址   
	  ModelAndView view = new ModelAndView("path:handleok");   
	  //将数据放置到ModelAndView对象view中,第二个参数可以是任何java类型   
	  view.addObject("key",someparam);   
	 ......   
	 //返回ModelAndView对象view   
	  return view;   
}  

上传文件

定义 bean

<bean id="multipartResolver"
    class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="100000" />
</bean>

相应代码

@RequestMapping(value="/form", method=RequestMethod.POST)
public String handleFormUpload(@RequestParam("file") MultipartFile file) {
    // save the file
}

相应依赖

<dependency>
  <groupId>commons-fileupload</groupId>
  <artifactId>commons-fileupload</artifactId>
  <version>1.3.1</version>
</dependency>

HttpEntity

@RequestMapping(value="/something")
public ResponseEntity<String> handle(HttpEntity<byte[]> requestEntity) {
    String requestHeader = requestEntity.getHeaders().getFirst("MyRequestHeader");
    byte[] requestBody = requestEntity.getBody();
    // do something with requestHeader and requestBody
    HttpHeaders responseHeaders = new HttpHeaders();
    responseHeaders.set("MyResponseHeader", "MyValue");
    return new ResponseEntity<String>("hello spring", responseHeaders, HttpStatus.CREATED);
}

@RequestBody & @ResponseBody

@RequestMapping(value="/spring")
@ResponseBody
public String spring(@RequestBody String body) throws IOException {
    return "hello" + body;
}

MessageConverter,返回 Java 对象的转化
RequestBody ---> Object: 参数
ResponseBody <--- Object: 返回值

xml 文件配置

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc=“http://www.springframework.org/schema/mvc”
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/mvc
	http://www.springframework.org/schema/mvc/spring-mvc.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context.xsd">
	<context:component-scan base-package="com.netease.course" />
	<mvc:annotation-driven />
</beans>

添加相应依赖,如 JSON 相关依赖

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.6.4</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.6.4</version>
    </dependency>

View 解析

String 名称

View

ModelAndView

Map

Model

ViewResolver (org.springframework.web.servlet):

InternalResourceViewResolver (org.springframework.web.servlet.view)
FreeMarkerViewResolver (org.springframework.web.servlet.view.freemarker)
ContentNegotiatingViewResolver (org.springframework.web.servlet.view)

InternalResourceViewResovler
Servlet, JSP
bean 定义

<bean id="viewResolver"
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/jsp/" />
    <property name="suffix" value=".jsp" />
</bean>

resultView -------> /WEB-INF/jsp/resultView.jsp

FreeMarkerViewResolver
FreeMarker
bean 定义

<bean id="freemarkerConfig"
    class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
    <property name="templateLoaderPath" value="/WEB-INF/freemarker/" />
</bean>
<bean id="viewResolver"
    class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
    <property name="cache" value="true" />
    <property name="prefix" value="" />
    <property name="suffix" value=".ftl" />
    <property name="contentType" value="text/html; charset=utf-8" />
</bean>

ContentNegotiatingViewResolver
ViewResovler 的组合
扩展名:user.json, user.xml, user.pdf
Accept 头(media types):application / json, application / xml
bean 定义

<bean
    class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
    <property name="viewResolvers">
        <list>
            <bean id="viewResolver"
                class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
                <property name="cache" value="true" />
                <property name="prefix" value="" />
                <property name="suffix" value=".ftl" />
            </bean>
        </list>
    </property>
    <property name="defaultViews">
        <list>
            <bean
                class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />
        </list>
    </property>
</bean>

DefaultRequestToViewNameTranslator
example/admin/index.html ---------> admin/index
example/display.html -------> display

ContentNegotiatingViewResolver 根据路径后缀,选择不同视图

方法一:使用扩展名

http://localhost:8080/learn/user.xml 获取 xml 类型数据

http://localhost:8080/learn/user.json 获取 json 类型数据

http://localhost:8080/learn/user 使用默认 view 呈现,如 jsp

方法二:使用 http 请求头的 Accept

GET /user HTTP/1.1

Accept:application/xml

GET /user HTTP/1.1

Accept:application/json

方法三:使用参数

http://localhost:8080/learn/user?format=xml

http://localhost:8080/learn/user?format=json

同一资源,多种表述

<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">  
    <!-- 是否启用扩展名支持,默认为true -->  
    <property name="favorPathExtenion" value="true" />  
    <!-- 是否启用参数支持,默认为true -->  
    <property name="favorParameter" value="false" />  
    <!-- 是否忽略掉accept header,默认为false -->  
    <property name="ignoreAcceptHeader" value="true" />  
      
    <!-- 扩展名到mimeType的映射 -->  
    <property name="mediaTypes">  
        <map>  
            <!-- 例如:/user.json 中的 .json 会映射到 application/json -->  
            <entry key="json" value="application/json" />  
            <entry key="xml" value="application/xml" />          
        </map>  
    </property>  
      
    <!-- 如果所有mediaType都没匹配上,就使用defaultContentType -->  
    <property name="defaultContentType" value="text/html"/>  
</bean>  
  
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">  
    <!-- 解析器的执行顺序 -->  
    <property name="order" value="1" />  
    <property name="contentNegotiationManager" ref="contentNegotiationManager" />  
      
    <property name="defaultViews">  
        <list>  
            <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"></bean>  
            <bean class="org.springframework.web.servlet.view.xml.MarshallingView">  
                <constructor-arg>  
                    <bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">  
                        <property name="classesToBeBound">  
                            <list>  
                                <value>com.learn.model.User</value>  
                            </list>  
                        </property>  
                    </bean>  
                </constructor-arg>  
            </bean>  
        </list>  
    </property>  
      
</bean>  
<!-- 上面没匹配到则会使用这个视图解析器 ,解析为jsp  -->  
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
    <property name="order" value="2" />  
    <property name="prefix" value="/" />   
    <property name="suffix" value=".jsp"/>  
</bean>  

Controller 中可以用 RequestMapping 匹配多个路径后缀

@RequestMapping(value = {"/users", "/users.html", "/users.json"})

public String getUsersInfo(ModelMap map) {

    List users = userServiceImp.getUsers();

    map.addAttribute("users", users);

    return "users";

}

FreeMarker

模板引擎

数据模型

对象:hashes

基本类型:scalars

注释

<#-- 这是注释 -->

插值:表达式

${animal.name}

直接指定值:

字符串,如“Zoo”, 'Zoo'

数字,如123.45

布尔值,如true,false

序列,如["zoo", "bar", 123]

值域,如0..9,0..<10

哈希表,如{"name":"green mouse", "price":150}

检索变量:

顶层变量:user

哈希表数据:user.name, user["name"]

列表数据:products[5]

连接操作:

users + "guest"

passwords + "joe":"secret123"

算术操作

逻辑操作

比较操作

FTL 标签:指令

开始标签:<#directivename parameters>

结束标签:

if 指令

<#if user=="Big Joe">, our beloved leader

list 指令

<#list animals as animal>

  ${animal.name}${animal.price} Euros

include 指令

<#include "/copyright_footer.html">

使用

创建配置

Configuration cfg = new Configuration(Configuration.VERSION_2_3_0);

cfg.setDirectoryForTemplateLoading(new File("/where/you/store/templates"));

cfg.setDefaultEncoding("UTF-8");

cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);

定义模板

定义数据模型

Map root = new HashMap<>();

root.put("user", "Big Joe");

Map latestProduct = new HashMap<>();

root.put("latestProduct", latestProduct);

latestProduct.put("url", "products/greenmouse.html");

latestProduct.put("name", "greenmouse");

添加依赖

  <dependency>

      <groupId>org.freemarkergroupId>

      <artifactId>freemarkerartifactId>

      <version>2.3.23version>

  dependency>

输出结果

    Template ftl = cfg.getTemplate("user.ftl");

    Writer outWriter = new OutputStreamWriter(System.out);

    ftl.process(root, outWriter);

工程模板

一般 java 目录

com.netease.course.dao

com.netease.course.meta

com.netease.course.service

com.netease.course.service.impl

com.netease.course.utils

com.netease.course.web.controller

com.netease.course.web.filter

  • Web
    116 引用 • 433 回帖 • 8 关注
  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    944 引用 • 1459 回帖 • 17 关注
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3187 引用 • 8213 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • 服务器

    服务器,也称伺服器,是提供计算服务的设备。由于服务器需要响应服务请求,并进行处理,因此一般来说服务器应具备承担服务并且保障服务的能力。

    125 引用 • 588 回帖
  • QQ

    1999 年 2 月腾讯正式推出“腾讯 QQ”,在线用户由 1999 年的 2 人(马化腾和张志东)到现在已经发展到上亿用户了,在线人数超过一亿,是目前使用最广泛的聊天软件之一。

    45 引用 • 557 回帖 • 67 关注
  • 机器学习

    机器学习(Machine Learning)是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、算法复杂度理论等多门学科。专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能。

    83 引用 • 37 回帖 • 1 关注
  • 小说

    小说是以刻画人物形象为中心,通过完整的故事情节和环境描写来反映社会生活的文学体裁。

    28 引用 • 108 回帖 • 1 关注
  • CloudFoundry

    Cloud Foundry 是 VMware 推出的业界第一个开源 PaaS 云平台,它支持多种框架、语言、运行时环境、云平台及应用服务,使开发人员能够在几秒钟内进行应用程序的部署和扩展,无需担心任何基础架构的问题。

    5 引用 • 18 回帖 • 168 关注
  • 正则表达式

    正则表达式(Regular Expression)使用单个字符串来描述、匹配一系列遵循某个句法规则的字符串。

    31 引用 • 94 回帖
  • Flutter

    Flutter 是谷歌的移动 UI 框架,可以快速在 iOS 和 Android 上构建高质量的原生用户界面。 Flutter 可以与现有的代码一起工作,它正在被越来越多的开发者和组织使用,并且 Flutter 是完全免费、开源的。

    39 引用 • 92 回帖
  • JetBrains

    JetBrains 是一家捷克的软件开发公司,该公司位于捷克的布拉格,并在俄国的圣彼得堡及美国麻州波士顿都设有办公室,该公司最为人所熟知的产品是 Java 编程语言开发撰写时所用的集成开发环境:IntelliJ IDEA

    18 引用 • 54 回帖
  • 单点登录

    单点登录(Single Sign On)是目前比较流行的企业业务整合的解决方案之一。SSO 的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。

    9 引用 • 25 回帖
  • 小薇

    小薇是一个用 Java 写的 QQ 聊天机器人 Web 服务,可以用于社群互动。

    由于 Smart QQ 从 2019 年 1 月 1 日起停止服务,所以该项目也已经停止维护了!

    34 引用 • 467 回帖 • 743 关注
  • CSDN

    CSDN (Chinese Software Developer Network) 创立于 1999 年,是中国的 IT 社区和服务平台,为中国的软件开发者和 IT 从业者提供知识传播、职业发展、软件开发等全生命周期服务,满足他们在职业发展中学习及共享知识和信息、建立职业发展社交圈、通过软件开发实现技术商业化等刚性需求。

    14 引用 • 155 回帖
  • Gitea

    Gitea 是一个开源社区驱动的轻量级代码托管解决方案,后端采用 Go 编写,采用 MIT 许可证。

    4 引用 • 16 回帖 • 6 关注
  • DNSPod

    DNSPod 建立于 2006 年 3 月份,是一款免费智能 DNS 产品。 DNSPod 可以为同时有电信、网通、教育网服务器的网站提供智能的解析,让电信用户访问电信的服务器,网通的用户访问网通的服务器,教育网的用户访问教育网的服务器,达到互联互通的效果。

    6 引用 • 26 回帖 • 510 关注
  • gRpc
    11 引用 • 9 回帖 • 73 关注
  • FlowUs

    FlowUs.息流 个人及团队的新一代生产力工具。

    让复杂的信息管理更轻松、自由、充满创意。

    1 引用 • 3 关注
  • LeetCode

    LeetCode(力扣)是一个全球极客挚爱的高质量技术成长平台,想要学习和提升专业能力从这里开始,充足技术干货等你来啃,轻松拿下 Dream Offer!

    209 引用 • 72 回帖
  • 创业

    你比 99% 的人都优秀么?

    84 引用 • 1399 回帖
  • 运维

    互联网运维工作,以服务为中心,以稳定、安全、高效为三个基本点,确保公司的互联网业务能够 7×24 小时为用户提供高质量的服务。

    149 引用 • 257 回帖
  • 尊园地产

    昆明尊园房地产经纪有限公司,即:Kunming Zunyuan Property Agency Company Limited(简称“尊园地产”)于 2007 年 6 月开始筹备,2007 年 8 月 18 日正式成立,注册资本 200 万元,公司性质为股份经纪有限公司,主营业务为:代租、代售、代办产权过户、办理银行按揭、担保、抵押、评估等。

    1 引用 • 22 回帖 • 762 关注
  • Pipe

    Pipe 是一款小而美的开源博客平台。Pipe 有着非常活跃的社区,可将文章作为帖子推送到社区,来自社区的回帖将作为博客评论进行联动(具体细节请浏览 B3log 构思 - 分布式社区网络)。

    这是一种全新的网络社区体验,让热爱记录和分享的你不再感到孤单!

    132 引用 • 1114 回帖 • 124 关注
  • OAuth

    OAuth 协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式不同之处是 oAuth 的授权不会使第三方触及到用户的帐号信息(如用户名与密码),即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权,因此 oAuth 是安全的。oAuth 是 Open Authorization 的简写。

    36 引用 • 103 回帖 • 9 关注
  • Sym

    Sym 是一款用 Java 实现的现代化社区(论坛/BBS/社交网络/博客)系统平台。

    下一代的社区系统,为未来而构建

    524 引用 • 4601 回帖 • 699 关注
  • WiFiDog

    WiFiDog 是一套开源的无线热点认证管理工具,主要功能包括:位置相关的内容递送;用户认证和授权;集中式网络监控。

    1 引用 • 7 回帖 • 587 关注
  • Facebook

    Facebook 是一个联系朋友的社交工具。大家可以通过它和朋友、同事、同学以及周围的人保持互动交流,分享无限上传的图片,发布链接和视频,更可以增进对朋友的了解。

    4 引用 • 15 回帖 • 453 关注
  • C

    C 语言是一门通用计算机编程语言,应用广泛。C 语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。

    85 引用 • 165 回帖 • 2 关注
  • CAP

    CAP 指的是在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可兼得。

    11 引用 • 5 回帖 • 608 关注
  • Caddy

    Caddy 是一款默认自动启用 HTTPS 的 HTTP/2 Web 服务器。

    12 引用 • 54 回帖 • 164 关注