//概述
轻量级,一站式,开发框架
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
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于