学习笔记 --Spring 框架

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

//概述

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

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
    118 引用 • 433 回帖 • 8 关注
  • Spring

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

    947 引用 • 1460 回帖 • 1 关注
  • Java

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

    3201 引用 • 8217 回帖 • 1 关注

相关帖子

欢迎来到这里!

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

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

推荐标签 标签

  • Spark

    Spark 是 UC Berkeley AMP lab 所开源的类 Hadoop MapReduce 的通用并行框架。Spark 拥有 Hadoop MapReduce 所具有的优点;但不同于 MapReduce 的是 Job 中间输出结果可以保存在内存中,从而不再需要读写 HDFS,因此 Spark 能更好地适用于数据挖掘与机器学习等需要迭代的 MapReduce 的算法。

    74 引用 • 46 回帖 • 566 关注
  • 印象笔记
    3 引用 • 16 回帖 • 2 关注
  • 倾城之链
    23 引用 • 66 回帖 • 165 关注
  • 浅吟主题

    Jeffrey Chen 制作的思源笔记主题,项目仓库:https://github.com/TCOTC/Whisper

    1 引用 • 28 回帖
  • V2Ray
    1 引用 • 15 回帖 • 3 关注
  • 知乎

    知乎是网络问答社区,连接各行各业的用户。用户分享着彼此的知识、经验和见解,为中文互联网源源不断地提供多种多样的信息。

    10 引用 • 66 回帖
  • SOHO

    为成为自由职业者在家办公而努力吧!

    7 引用 • 55 回帖 • 1 关注
  • Markdown

    Markdown 是一种轻量级标记语言,用户可使用纯文本编辑器来排版文档,最终通过 Markdown 引擎将文档转换为所需格式(比如 HTML、PDF 等)。

    172 引用 • 1538 回帖
  • Hadoop

    Hadoop 是由 Apache 基金会所开发的一个分布式系统基础架构。用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。

    93 引用 • 122 回帖 • 619 关注
  • Jenkins

    Jenkins 是一套开源的持续集成工具。它提供了非常丰富的插件,让构建、部署、自动化集成项目变得简单易用。

    54 引用 • 37 回帖
  • OpenShift

    红帽提供的 PaaS 云,支持多种编程语言,为开发人员提供了更为灵活的框架、存储选择。

    14 引用 • 20 回帖 • 661 关注
  • wolai

    我来 wolai:不仅仅是未来的云端笔记!

    2 引用 • 14 回帖 • 3 关注
  • IDEA

    IDEA 全称 IntelliJ IDEA,是一款 Java 语言开发的集成环境,在业界被公认为最好的 Java 开发工具之一。IDEA 是 JetBrains 公司的产品,这家公司总部位于捷克共和国的首都布拉格,开发人员以严谨著称的东欧程序员为主。

    181 引用 • 400 回帖 • 1 关注
  • Excel
    31 引用 • 28 回帖
  • V2EX

    V2EX 是创意工作者们的社区。这里目前汇聚了超过 400,000 名主要来自互联网行业、游戏行业和媒体行业的创意工作者。V2EX 希望能够成为创意工作者们的生活和事业的一部分。

    16 引用 • 236 回帖 • 242 关注
  • 周末

    星期六到星期天晚,实行五天工作制后,指每周的最后两天。再过几年可能就是三天了。

    14 引用 • 297 回帖
  • SEO

    发布对别人有帮助的原创内容是最好的 SEO 方式。

    36 引用 • 200 回帖 • 36 关注
  • 大数据

    大数据(big data)是指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合,是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。

    89 引用 • 113 回帖
  • Ngui

    Ngui 是一个 GUI 的排版显示引擎和跨平台的 GUI 应用程序开发框架,基于
    Node.js / OpenGL。目标是在此基础上开发 GUI 应用程序可拥有开发 WEB 应用般简单与速度同时兼顾 Native 应用程序的性能与体验。

    7 引用 • 9 回帖 • 406 关注
  • 微服务

    微服务架构是一种架构模式,它提倡将单一应用划分成一组小的服务。服务之间互相协调,互相配合,为用户提供最终价值。每个服务运行在独立的进程中。服务于服务之间才用轻量级的通信机制互相沟通。每个服务都围绕着具体业务构建,能够被独立的部署。

    96 引用 • 155 回帖
  • React

    React 是 Facebook 开源的一个用于构建 UI 的 JavaScript 库。

    192 引用 • 291 回帖 • 368 关注
  • Q&A

    提问之前请先看《提问的智慧》,好的问题比好的答案更有价值。

    10058 引用 • 45707 回帖 • 68 关注
  • 单点登录

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

    9 引用 • 25 回帖 • 2 关注
  • OneNote
    1 引用 • 3 回帖
  • 学习

    “梦想从学习开始,事业从实践起步” —— 习近平

    172 引用 • 534 回帖
  • Facebook

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

    4 引用 • 15 回帖 • 444 关注
  • WebComponents

    Web Components 是 W3C 定义的标准,它给了前端开发者扩展浏览器标签的能力,可以方便地定制可复用组件,更好的进行模块化开发,解放了前端开发者的生产力。

    1 引用 • 9 关注