SSM基础框架学习
SSM基础框架学习
前言:最近一直在实习,没怎么更新笔记了,由于蚂蚁的SOFA和SOFABoot就是基于Spring和SpringBoot的,所以这里复习一下SSM(之前spring学了一个半吊子,迫于无奈复习🐕)
1. Spring 简介
1.1 Spring 是什么
Spring是分层的 Java SE/EE应用 full-stack 轻量级开源框架,以 IoC(Inverse Of Control:反转控制)和 AOP(Aspect Oriented Programming:面向切面编程)为内核。
提供了展现层 SpringMVC 和持久层 Spring JDBCTemplate 以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的Java EE 企业应用开源框架。
1.2 Spring 发展历程
1997 年, IBM提出了EJB 的思想
1998 年,SUN制定开发标准规范 EJB1.0
1999 年,EJB1.1 发布
2001 年,EJB2.0 发布
2003 年,EJB2.1 发布
2006 年,EJB3.0 发布
Rod Johnson ( Spring 之父)
Expert One-to-One J2EE Design and Development(2002)
阐述了 J2EE 使用EJB 开发设计的优点及解决方案
Expert One-to-One J2EE Development without EJB(2004)
阐述了 J2EE 开发不使用 EJB的解决方式(Spring 雏形)
2017 年 9 月份发布了 Spring 的最新版本 Spring5.0 通用版(GA)
1.3 Spring 优势
- 方便解耦,简化开发(IOC容器)
- AOP 编程的支持(AOP可以轻松解决一些OOP不容易实现的功能)
- 声明式事务的支持
- 方便程序测试
- 方便继承各种优秀框架
- 降低JavaEE API 的使用难度(对JDBC、JavaMail、远程调用等进行了薄封装减低使用难度)
- Java 源码式经典学习范例(灵活运用 Java 设计模式)
1.4 Spring 体系结构
1.5 SSM 三层架构
而其中 MVC 设计模型:
- M:model 模型 JavaBean
- V:View 视图 JSP
- C:Controller 控制器 Servlet
2. Spring 的IoC和DI
2.1 快速入门
通过快速入门简单体会 IoC ,把对象创建权交给了Spring框架,通过 IoC 能降低耦合但是不能接触耦合
① 新建Maven工程,导入 Spring 开发的基本包坐标
1 |
|
② 编写 Dao 接口和实现类
1 |
|
③ 在类路径下(resources)创建 Spring 核心配置文件 applicationContext.xml
④ 在 Spring 配置文件中配置 UserDaoImpl
1 |
|
⑤ 使用 Spring 的 API 创建 ApplicationContext 对象,使用 getBean 方法获得 Bean 实例
1 |
|
2.2 Spring 配置文件开发
2.2.1 Spring的重点配置
1 |
|
2.2.2 Bean 标签基本配置
用于配置对象交由Spring 来创建。
默认情况下它调用的是类中的无参构造函数,如果没有无参构造函数则不能创建成功。
示例:
1 |
|
基本属性:
id:Bean实例在Spring容器中的唯一标识
class:Bean的全限定名称
2.2.3 Bean 标签范围配置
当 scope 的取值为 singleton 时
Bean的实例化个数:1个
Bean的实例化时机: 当Spring核心文件被加载时,实例化配置的Bean实例
Bean的生命周期:
- 对象创建:当应用加载,创建容器时,对象就被创建了
- 对象运行:只要容器在,对象一直活着
- 对象销毁:当应用卸载,销毁容器时,对象就被销毁了
当 scope 的取值为 prototype 时
Bean的实例化个数:多个
Bean的实例化时机: 当调用getBean()方法时实例化Bean
- 对象创建:当使用对象时,创建新的对象实例
- 对象运行:只要对象在使用中,就一直活着
- 对象销毁:当对象长时间不用时,被 Java 的垃圾回收器回收了
2.2.4 Bean 生命周期配置
init-method:指定类中的初始化方法名称
destroy-method:指定类中销毁方法名称
示例:
1 |
|
2.2.5 Bean 实例化三种方法
无参构造方法实例化(默认)
工厂静态方法实例化
工厂实例方法实例化
使用无参构造方法实例化
它会根据默认无参构造方法来创建类对象,如果bean中没有默认无参构造函数,将会创建失败
1
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
工厂静态方法实例化
工厂的静态方法返回Bean实例
由于是静态方法,所以可以在使用工厂类的 class 类对象直接直接调用返回类对象,不需要获得工厂的bean
1
2
3
4
5public class StaticFactoryBean {
public static UserDao createUserDao(){
return new UserDaoImpl();
}
}1
2<bean id="userDao" class="com.itheima.factory.StaticFactoryBean"
factory-method="createUserDao" />工厂实例方法实例化
工厂的非静态方法返回Bean实例
非静态方法,需要先获得工厂 bean,再通过工厂 bean 获得 userDao
1 |
|
1 |
|
2.2.6 Bean 依赖注入⭐
2.2.6.1 分析
UserService实例和UserDao实例都存在与Spring容器中,一种做法是在容器外部获得UserService实例和UserDao实例,然后在程序中进行结合。
另一种做法是,因为UserService和UserDao都在Spring容器中,而最终程序直接使用的是UserService,所以可以在Spring容器中,将UserDao设置到UserService内部。
2.2.6.2 概念
依赖注入(Dependency Injection):它是 Spring 框架核心 IOC 的具体实现。
在编写程序时,通过控制反转,把对象的创建交给了 Spring,但是代码中不可能出现没有依赖的情况。
IOC 解耦只是降低他们的依赖关系,但不会消除。例如:业务层仍会调用持久层的方法。
那这种业务层和持久层的依赖关系,在使用 Spring 之后,就让 Spring 来维护了。
简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取。
2.2.6.3 依赖注入的方式
set方法
在UserServiceImpl中添加setUserDao方法
1
2
3
4
5
6
7
8
9
10public class UserServiceImpl implements UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void save() {
userDao.save();
}
}setter注入方式1:配置Spring容器调用set方法进行注入
1
2
3
4<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>setter注入方式2:P命名空间注入本质也是set方法注入,但比起上述的set方法注入更加方便,主要体现在配置文件中,如下:
首先,需要向配置文件引入P命名空间:
1
xmlns:p="http://www.springframework.org/schema/p"
其次,需要修改注入方式
1
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl" p:userDao-ref="userDao"/>
构造方法
创建有参构造
1
2
3
4
5
6
7
8
9public class UserServiceImpl implements UserService {
@Override
public void save() {
ApplicationContext applicationContext = new
ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
userDao.save();
}
}配置Spring容器调用有参构造时进行注入
1
2
3
4<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
<constructor-arg name="userDao" ref="userDao"></constructor-arg>
</bean>
2.2.6.4 依赖注入数据类型
上面的操作,都是注入的引用Bean,除了对象的引用可以注入,普通数据类型,集合等都可以在容器中进行注入。
注入数据的三种数据类型
普通数据类型
引用数据类型
集合数据类型
其中引用数据类型,此处就不再赘述了,之前的操作都是对UserDao对象的引用进行注入的,下面将以set方法注入为例,演示普通数据类型和集合数据类型的注入。
示例:
1 |
|
1 |
|
2.2.6.5 引入其他配置文件(分模块开发)
实际开发中,Spring的配置内容非常多,这就导致Spring配置很繁杂且体积很大,所以,可以将部分配置拆解到其他配置文件中,而在Spring主配置文件通过import标签进行加载
1 |
|
2.3 Spring 相关 API
2.3.1 ApplicationContext的继承体系
applicationContext:接口类型,代表应用上下文,可以通过其实例获得 Spring 容器中的 Bean 对象
(紫色为接口,浅绿色为抽象类,绿色为实现类)
2.3.2 ApplicationContext的实现类
我们主要关心其中三个
ClassPathXmlApplicationContext
它是从类的根路径下加载配置文件 推荐使用这种
FileSystemXmlApplicationContext
它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置
AnnotationConfigApplicationContext
当使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解。
2.3.3 getBean() 方法使用
1 |
|
当参数的数据类型是字符串时,表示根据Bean的id从容器中获得Bean实例,返回是Object,需要强转。
当参数的数据类型是Class类型时,表示根据类型从容器中匹配Bean实例,当容器中相同类型的Bean有多个时,则此方法会报错。
示例:
1 |
|
2.3.4 要点总结
Spring API 使用
1 |
|
2.4 Spring 配置数据源(使用配置文件)
2.4.1 数据源的作用(回顾)
- 数据源(连接池)是提高程序性能如出现的
- 事先实例化数据源,初始化部分连接资源
- 使用连接资源时从数据源中获取
- 使用完毕后将连接资源归还给数据源
常见的数据源(连接池):DBCP、C3P0、BoneCP、Druid等
2.4.2 数据源开发步骤
以下先看看手动创建过程,不使用 Spring 的 IoC 容器
①导入数据源的坐标和数据库驱动坐标
- 导入c3p0和druid的坐标
1 |
|
- 导入mysql数据库驱动坐标
1 |
|
②创建数据源对象,设置数据源的基本连接数据
- 创建C3P0连接池
1 |
|
- 创建Druid连接池
1 |
|
③对上面的硬编码进行改进,提取jdbc.properties配置文件,读取jdbc.properties配置文件创建连接池
1 |
|
1 |
|
④使用数据源获取连接资源和归还连接资源
2.4.3 Spring 配置数据源
基于上面手动创建过程,我们可以将DataSource的创建权交由Spring容器去完成
DataSource有无参构造方法,而Spring默认就是通过无参构造方法实例化对象的
DataSource要想使用需要通过set方法设置数据库连接信息,而Spring可以通过set方法进行字符串注入
1 |
|
测试从容器当中获取数据源
1 |
|
改进配置文件中的硬编码(其实并没有依赖,但不优雅),抽取 jdbc 配置文件
applicationContext.xml 加载 jdbc.properties 配置文件(和手动创建一致)获得连接信息
首先,需要引入context命名空间和约束路径:
命名空间:xmlns:context=”http://www.springframework.org/schema/context"
约束路径:http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
1 |
|
2.4.4 要点总结
Spring 容器加载 properties 文件
1 |
|
2.5 Spring 注解开发
2.5.1 Spring 注解开发简介
Spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,注解代替xml配置文件可以简化配置,提高开发效率。
2.5.2 Spring 原始注解
Spring原始注解主要是替代
注意:
使用注解进行开发时,需要在applicationContext.xml中配置组件扫描,作用是指定哪个包及其子包下的Bean需要进行扫描以便识别使用注解配置的类、字段和方法。
1 |
|
原始注解使用的示例:
示例一:使用@Compont或@Repository标识UserDaoImpl需要Spring进行实例化
1
2
3
4
5
6
7
8//@Component("userDao")
@Repository("userDao")
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("save running... ...");
}
}示例二:
使用@Compont或@Service标识UserServiceImpl需要Spring进行实例化
使用@Autowired或者@Autowired+@Qulifier或者@Resource进行userDao的注入
1
2
3
4
5
6
7
8
9
10
11
12//@Component("userService")
@Service("userService")
public class UserServiceImpl implements UserService {
/*@Autowired
@Qualifier("userDao")*/
@Resource(name="userDao")
private UserDao userDao;
@Override
public void save() {
userDao.save();
}
}示例三:
使用@Value进行字符串的注入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15@Repository("userDao")
public class UserDaoImpl implements UserDao {
@Value("注入普通数据")
private String str;
// 这里体现了value注解的必要性
@Value("${jdbc.driver}")
private String driver;
@Override
public void save() {
System.out.println(str);
System.out.println(driver);
System.out.println("save running... ...");
}
}示例四:
使用@Scope标注Bean的范围
1
2
3
4
5//@Scope("prototype")
@Scope("singleton")
public class UserDaoImpl implements UserDao {
//此处省略代码
}示例五:
使用@PostConstruct标注初始化方法,使用@PreDestroy标注销毁方法
1
2
3
4
5
6
7
8
9@PostConstruct
public void init(){
System.out.println("初始化方法....");
}
@PreDestroy
public void destroy(){
System.out.println("销毁方法.....");
}
2.5.3 Spring 新注解
使用上面的注解还不能全部替代xml配置文件,还需要使用注解替代的配置如下:
- 非自定义的Bean的配置:< bean >
- 加载properties文件的配置:< context:property-placeholder >
- 组件扫描的配置:< context:component-scan >
- 引入其他文件:< import >
因此通过以下新注解可以替代如上配置
新注解使用的示例(该示例演示了注解开发配置数据源):
示例一:
@Configuration
@ComponentScan
@Import
1
2
3
4
5@Configuration
@ComponentScan("com.itheima")
@Import({DataSourceConfiguration.class})
public class SpringConfiguration {
}示例二:
@PropertySource
@value
1
2
3
4
5
6
7
8
9
10
11@PropertySource("classpath:jdbc.properties")
public class DataSourceConfiguration {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;示例三:
@Bean (把第三方 jar 包中定义的类加入到 Spring 容器中)
1
2
3
4
5
6
7
8
9@Bean(name="dataSource")
public DataSource getDataSource() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass(driver);
dataSource.setJdbcUrl(url);
dataSource.setUser(username);
dataSource.setPassword(password);
return dataSource;
}注解开发的 API :测试加载核心配置类创建Spring容器
1
2
3
4
5
6
7
8
9
10
11
12@Test
public void testAnnoConfiguration() throws Exception {
ApplicationContext applicationContext = new
AnnotationConfigApplicationContext(SpringConfiguration.class);
UserService userService = (UserService)
applicationContext.getBean("userService");
userService.save();
DataSource dataSource = (DataSource)
applicationContext.getBean("dataSource");
Connection connection = dataSource.getConnection();
System.out.println(connection);
}
2.6 Spring 集成 Junit
2.6.1 集成的理由
可以利用 Spring 提前统一的加载容器,并利用 Spring 完成依赖注入,再进行测试
不需要给每一个 @Test 测试方法都载入一次配置文件,加载一次容器
2.6.2 Spring 集成 Junit 步骤
① 导入spring集成Junit的坐标
1 |
|
② 使用@Runwith 注解替换原来的运行期
以前是使用 Junit 完成测试,现在是向先运行 Spring 加载容器,Spring再去找 Junit 进行测试
1 |
|
③ 使用@ContextConfiguration 指定配置文件或配置类
1 |
|
④ 使用@Autowired 注入需要测试的对象
⑤ 创建测试方法进行测试
1 |
|
3. SpringMVC
3.1 Spring 集成 web 环境
3.1.1 ApplicationContext 应用上下文获取方式
应用上下文对象是通过new ClasspathXmlApplicationContext (spring 配置文件) 方式获取的,但是每次从容器中获得Bean时都要编写new ClasspathXmlApplicationContext (spring配置文件) ,这样的弊端是配置文件加载多次,应用上下文对象创建多次。
在Web项目中,可以使用 ServletContextListener 监听Web应用的启动,我们可以在Web应用启动时,就加载Spring的配置文件,创建应用上下文对象ApplicationContext,在将其存储到最大的域servletContext域中,这样就可以在任意位置从域中获得应用上下文ApplicationContext对象了。
3.1.2 Spring 提供获取应用上下文的工具
(关于这一段如果不能太理解,或者遗忘了看视频p39 p40回顾比较快)
上面提到的使用监听器监听Web应用启动在启动过程中加载Spring配置文件的功能不需要手动实现,Spring提供了一个监听器ContextLoaderListener就是对上述功能的封装,该监听器内部加载Spring配置文件,创建应用上下文对象,并存储到ServletContext域中,提供了一个客户端工具WebApplicationContextUtils供使用者获得应用上下文对象。
所以我们需要做的只有两件事:
①在web.xml中配置ContextLoaderListener监听器(导入spring-web坐标)
导入坐标
1 |
|
配置web.xml
1 |
|
②使用WebApplicationContextUtils获得应用上下文对象ApplicationContext
使用工具类回去上下文对象
1 |
|
3.2 SpringMVC 简介
3.2.1 SpringMVC 概述
SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架,属于SpringFrameWork 的后续产品,已经融合在 Spring Web Flow 中。
SpringMVC 已经成为目前最主流的MVC框架之一,并且随着Spring3.0 的发布,全面超越 Struts2,成为最优秀的 MVC 框架。它通过一套注解,让一个简单的 Java 类成为处理请求的控制器,而无须实现任何接口。同时它还支持 RESTful 编程风格的请求。
SpringMVC雏形分析:
- POJO:就是一个普通的 JavaBean
- 前端控制器(web框架基本都有):不同框架实现原理不一样
- SpringMVC 中 前端控制器是 servlet
- Struts2 中前端控制器是 fliter
3.2.2 SpringMVC快速入门
开发步骤:
需求:客户端发起请求,服务器端接收请求,执行逻辑并进行视图跳转。
开发步骤:
①导入SpringMVC相关坐标
1 |
|
②配置SpringMVC核心控制器DispathcerServlet
在web.xml中配置前端控制器
1 |
|
③创建Controller类和视图页面
创建Controller和业务方法
1 |
|
创建视图页面 index.jsp
1 |
|
④使用注解配置Controller类中业务方法的映射地址
使用@Controller 放入容器
使用@RequestMapping ,配置请求地址和方法的映射关系
1 |
|
⑤配置SpringMVC核心文件 spring-mvc.xml
创建spring-mvc.xml
1 |
|
⑥客户端发起请求测试
访问测试地址:http://localhost:8080/itheima_springmvc1/quick
流程图示总结:
3.2.3 SpringMVC 组件解析
- SpringMVC 的执行流程
①用户发送请求至前端控制器DispatcherServlet。
②DispatcherServlet收到请求调用HandlerMapping处理器映射器。
③处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
④DispatcherServlet调用HandlerAdapter处理器适配器。
⑤HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
⑥Controller执行完成返回ModelAndView。
⑦HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
⑧DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
⑨ViewReslover解析后返回具体View。
⑩DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中),DispatcherServlet响应用户。
各个组件解析
- 前端控制器:DispatcherServlet
用户请求到达前端控制器,它就相当于 MVC 模式中的 C,DispatcherServlet 是整个流程控制的中心,由它调用其它组件处理用户的请求,DispatcherServlet 的存在降低了组件之间的耦合性。
处理器映射器:HandlerMapping
HandlerMapping 负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。处理器适配器:HandlerAdapter
通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行处理器:Handler
它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到 Handler。由Handler 对具体的用户请求进行处理。
视图解析器: View Resolver
View Resolver 负责将处理结果生成 View 视图,View Resolver 首先根据逻辑视图名解析成物理视图名,即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。
视图:View
SpringMVC 框架提供了很多的 View 视图类型的支持,包括:jstlView、freemarkerView、pdfView等,最常用的视图就是 jsp。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面
注解解析
@Controller (前面学过,就是和 @Component 作用相同)
@RequestMapping ⭐⭐
作用:用于建立请求 URL 和处理请求方法之间的对应关系
位置:
类上,请求URL 的第一级访问目录。此处不写的话,就相当于应用的根目录
方法上,请求 URL 的第二级访问目录,与类上的使用@ReqquestMapping标注的一级目录一起拼接组成访问虚拟路径
属性:
value:用于指定请求的URL。它和path属性的作用是一样的
method:用于指定请求的方式(RequestMethod.POST,RequestMethod.get等)
params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的key和value必须和配置的一模一样
例如:
**params = {“accountName”}**,表示请求参数必须有accountName
**params = {“moeny!100”}**,表示请求参数中money不能是100
XML 配置解析
mvc 命名空间引入
1
2
3
4
5
6
7命名空间:
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
约束地址:
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd组件扫描
SpringMVC基于Spring容器,所以在进行SpringMVC操作时,需要将Controller存储到Spring容器中,如果使用@Controller注解标注的话,就需要使用
1
<context:component-scan base-package=“com.itheima.controller"/>
进行组件扫描。
视图解析器
SpringMVC有默认组件配置,默认组件都是 DispatcherServlet.properties 配置文件中配置的,该配置文件地址: org/springframework/web/servlet/DispatcherServlet.properties,该文件中配置了默认的视图解析器,如下:
1
org.springframework.web.servlet.ViewResolver = org.springframework.web.servlet.view.InternalResourceViewResolver
翻看该解析器源码,可以看到该解析器的默认设置,如下:
1
2
3
4REDIRECT_URL_PREFIX = "redirect:" --重定向前缀
FORWARD_URL_PREFIX = "forward:" --转发前缀(默认值)
prefix = ""; --视图名称前缀
suffix = ""; --视图名称后缀我们可以通过属性注入的方式修改视图的前后缀
1
2
3
4
5<!--配置内部资源视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
3.3 SpringMVC 的数据响应
3.3.1 SpringMVC的数据响应方式
页面跳转
- 直接返回字符串
- 通过ModelAndView对象返回
回写数据
- 直接返回字符串
- 返回对象或集合
3.3.2 SpringMVC 页面跳转
返回字符串形式
直接返回字符串:此种方式会将返回的字符串与视图解析器的前后缀拼接后跳转。
返回带有前缀的字符串:
转发:forward:/WEB-INF/views/index.jsp
重定向:redirect:/index.jsp (重定向是客户端再次访问,如果在WEB-INF是受保护文件夹,外界不能直接访问,重定向只能在被访问的路径下)
返回 ModelAndView 对象
model:模型 封装数据
view:视图 展示数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37@RequestMapping("/quick2")
public ModelAndView quickMethod2(){
ModelAndView modelAndView = new ModelAndView();
// 设置模型数据
modelAndView.addObject("username", "itcast");
// 设置视图名称
// 在 jsp 中用 ${username} 来展示 model 数据
modelAndView.setViewName("redirect:index.jsp");
return modelAndView;
}
@RequestMapping("/quick2")
// SpringMVC 还可以自动注入入参的ModelAndView,就不需要手动创建了
public ModelAndView quickMethod2(ModelAndView modelAndView){
modelAndView.addObject("username", "itcast");
// 在 jsp 中用 ${username} 来展示 model 数据
modelAndView.setViewName("redirect:index.jsp");
return modelAndView;
}
@RequestMapping("/quick2")
// SpringMVC 还可以自动注入入参的Model,就不需要手动创建了
public String quickMethod2(Model model){
// 设置模型数据
model.addAttribute("username", "itcast");
// 在 jsp 中用 ${username} 来展示 model 数据
return "redirect:index.jsp";
}
@RequestMapping("/quick3")
public ModelAndView quickMethod3(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("forward:/WEB-INF/views/index.jsp");
return modelAndView;
}向request域存储数据
在进行转发时,往往要向request域中存储数据,在jsp页面中显示,那么Controller中怎样向request域中存储数据呢?
通过SpringMVC框架注入的request对象setAttribute()方法设置
(这个不常用,因为我们使用了SpringMVC就最好使用框架提供的对象,不要使用 Javaweb 的对象,保证和原生的API实现解耦)
1
2
3
4
5
6@RequestMapping("/quick")
// SpringMVC 还可以自动注入入参的 request
public String quickMethod(HttpServletRequest request){
request.setAttribute("name","zhangsan");
return "index";
}通过ModelAndView的addObject()方法设置
1
2
3
4
5
6
7@RequestMapping("/quick3")
public ModelAndView quickMethod3(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("forward:/WEB-INF/views/index.jsp");
modelAndView.addObject("name","lisi");
return modelAndView;
}
3.3.3 SpringMVC 回写数据
直接返回字符串
Web基础阶段,客户端访问服务器端,如果想直接回写字符串作为响应体返回的话,只需要使用
response.getWriter().print(“hello world”) 即可,那么在Controller中想直接回写字符串该怎样呢?
通过SpringMVC框架注入的response对象,使用response.getWriter().print(“hello world”) 回写数据,此时不需要视图跳转,业务方法返回值为void
1
2
3
4@RequestMapping("/quick4")
public void quickMethod4(HttpServletResponse response) throws IOException {
response.getWriter().print("hello world");
}将需要回写的字符串直接返回,但此时需要通过@ResponseBody 注解告知SpringMVC框架,方法返回的字符串不是跳转是直接在http响应体中返回 (不使用原生API,更加解耦,更常用)⭐⭐
1
2
3
4
5@RequestMapping("/quick5")
@ResponseBody
public String quickMethod5() throws IOException {
return "hello springMVC!!!";
}在异步项目中,客户端与服务器端往往要进行json格式字符串交互,此时我们可以手动拼接json字符串返回
1
2
3
4
5@RequestMapping("/quick6")
@ResponseBody
public String quickMethod6() throws IOException {
return "{\"name\":\"zhangsan\",\"age\":18}";
}上述方式手动拼接json格式字符串的方式很麻烦(不优雅),开发中往往要将复杂的java对象转换成json格式的字符串,我们可以使用web阶段学习过的json转换工具jackson进行转换,导入jackson坐标
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16<!--jackson-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>通过jackson转换json格式字符串,回写字符串
1
2
3
4
5
6
7
8
9
10@RequestMapping("/quick7")
@ResponseBody
public String quickMethod7() throws IOException {
User user = new User();
user.setUsername("zhangsan");
user.setAge(18);
ObjectMapper objectMapper = new ObjectMapper();
String s = objectMapper.writeValueAsString(user);
return s;
}
返回对象或集合
(相当于把上面转json的过程交给了框架完成)
通过SpringMVC帮助我们对对象或集合进行json字符串的转换并回写,为处理器适配器配置消息转换参数,指定使用jackson进行对象或集合的转换,因此需要在spring-mvc.xml中进行如下配置,对前端控制器的配置文件进行配置覆盖:
1
2
3
4
5
6
7
8
9
10
11<bean class="org.springframework.web.servlet.mvc.method.annotation
.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json
.MappingJackson2HttpMessageConverter">
</bean>
</list>
</property>
</bean>1
2
3
4
5
6
7
8@RequestMapping("/quick8")
@ResponseBody
public User quickMethod8() throws IOException {
User user = new User();
user.setUsername("zhangsan");
user.setAge(18);
return user;
}在方法上添加**@ResponseBody**就可以返回json格式的字符串,但是这样配置比较麻烦,配置的代码比较多,因此,我们可以在springmvc.xml配置文件中使用mvc的注解驱动代替上述配置
1
2<!--mvc的注解驱动-->
<mvc:annotation-driven/>在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。
使用< mvc:annotation-driven >自动加载 RequestMappingHandlerMapping(处理映射器)和
RequestMappingHandlerAdapter( 处 理 适 配 器 ),可用在Spring-xml.xml配置文件中使用
< mvc:annotation-driven >替代注解处理器和适配器的配置。
同时使用< mvc:annotation-driven >默认底层就会集成jackson进行对象或集合的json格式字符串的转换。
3.4 SpringMVC 获得请求数据
3.4.1 获得请求参数
客户端请求参数的格式是:name=value&name=value
服务器端要获得请求的参数,有时还需要进行数据的封装,SpringMVC可以接收如下类型的参数:
基本类型参数
POJO类型参数(简单JavaBean)
数组类型参数
集合类型参数
3.4.2 获得基本类型参数
Controller中的业务方法的参数名称要与请求参数的name一致,参数值会自动映射匹配
3.4.3 获得POJO类型参数
Controller中的业务方法的POJO参数的属性名与请求参数的name一致,参数值会自动映射匹配
3.4.4 获得数组类型参数
Controller中的业务方法数组名称与请求参数的name一致,参数值会自动映射匹配
3.4.5 获得集合类型参数
获得集合参数时,要将集合参数包装到一个POJO中才可以
首先新建一个表单jsp,用于提交数据
1 |
|
那么就可以和POJO类型相似了,直接自动映射匹配
1 |
|
另一个场景(放行静态资源):
当使用ajax提交时,可以指定contentType为json形式,那么在方法参数位置使用@RequestBody可以直接接收集合数据而无需使用POJO进行包装
先加载 jqurey-3.3.1.js ,在编写自己的脚本
1 |
|
1 |
|
注意:通过谷歌开发者工具抓包发现,没有加载到jquery文件,原因是SpringMVC的前端控制器DispatcherServlet的url-pattern配置的是/,代表对所有的资源都进行过滤操作,然后去@RequestMapping找对应的路径,找不到。我们可以通过以下两种方式指定放行静态资源:
在spring-mvc.xml配置文件中指定放行的资源,通常都是静态资源
mapping 代表访问的地址,location表示访问的目录
1
<mvc:resources mapping="/js/**" location="/js/"/>
使用< mvc:default-servlet-handler/ >标签,代表如果SpringMVC找不到静态资源,就交由原始容器Tomcat服务器去寻找资源
3.4.6 请求数据乱码问题
当post请求时,数据会出现乱码,我们可以设置一个过滤器来进行编码的过滤
在web.xml中配置一个全局过滤器,对所有请求编码进行过滤
1 |
|
3.4.7 参数绑定注解@RequestParam
当请求的参数名称与Controller的业务方法参数名称不一致时,就需要通过@RequestParam注解显示的绑定
注解@RequestParam还有如下参数可以使用:
value:与请求参数名称
required:此在指定的请求参数是否必须包括,默认是true,提交时如果没有此参数则报错
defaultValue:当没有指定请求参数时,则使用指定的默认值赋值
3.4.8 获得Restful风格的参数
Restful是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。主要用于客户端和服务器交互类的软件,基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存机制等。
Restful风格的请求是使用“url+请求方式”表示一次请求目的的,HTTP 协议里面四个表示操作方式的动词如下:
GET:用于获取资源
POST:用于新建资源
PUT:用于更新资源
DELETE:用于删除资源
例如:
/user/1 GET : 得到 id = 1 的 user
/user/1 DELETE: 删除 id = 1 的 user
/user/1 PUT: 更新 id = 1 的 user
/user POST: 新增 user
上述url地址/user/1中的1就是要获得的请求参数,在SpringMVC中可以使用占位符进行参数绑定。地址/user/1可以写成/user/{id},占位符{id}对应的就是1的值。在业务方法中我们可以使用@PathVariable注解进行占位符的匹配获取工作。
3.4.9 自定义类型转换器
SpringMVC 默认已经提供了一些常用的类型转换器,例如客户端提交的字符串转换成int型进行参数设置。
但是不是所有的数据类型都提供了转换器,没有提供的就需要自定义转换器,例如:日期类型的数据就需要自定义转换器。
自定义类型转换器的开发步骤:
①定义转换器类实现Converter接口
1 |
|
②在spring-mvc.xml配置文件中声明转换器
1 |
|
③在< annotation-driven >中引用转换器(spring-mvc.xml配置文件)
1 |
|
3.4.10 获取Servlet相关API
SpringMVC支持使用原始ServletAPI对象作为控制器方法的参数进行注入,常用的对象如下:
HttpServletRequest
HttpServletResponse
HttpSession
1 |
|
3.4.11 获取请求头
@RequestHeader
使用@RequestHeader可以获得请求头信息,相当于web阶段学习的request.getHeader(name)
@RequestHeader注解的属性如下:
value:请求头的名称
required:是否必须携带此请求头
1
2
3
4
5@RequestMapping("/quick17")
@ResponseBody
public void quickMethod17(@RequestHeader(value = "User-Agent", required = false) String headerValue){
System.out.println(headerValue);
}@CookieValue
使用@CookieValue可以获得指定Cookie的值
@CookieValue注解的属性如下:
value:指定cookie的名称
required:是否必须携带此cookie
1
2
3
4
5
6@RequestMapping("/quick18")
@ResponseBody
public void quickMethod18(
@CookieValue(value = "JSESSIONID",required = false) String jsessionid){
System.out.println(jsessionid);
}
3.4.12 文件上传
文件上传客户端三要素:
表单项type=“file”
表单的提交方式是post
表单的enctype属性是多部分表单形式,及enctype=“multipart/form-data”
文件上传原理
当form表单修改为多部分表单时,request.getParameter()将失效。
enctype=“application/x-www-form-urlencoded” 时,form表单的正文内容格式是:key=value&key=value&key=value
当 form 表单的 enctype 取值为 Mutilpart/form-data 时,请求正文内容就变成多部分形式:
单文件上传的步骤
①导入fileupload和io坐标
1 |
|
②spring-mvc.xml配置文件上传解析器
1 |
|
③编写文件上传代码
1 |
|
多文件上传实现
多文件上传,只需要将页面修改为多个文件上传项,将方法参数MultipartFile类型修改为MultipartFile[]即可
1 |
|
1 |
|
3.4.13 要点总结
MVC 实现数据请求方式
基本类型参数
POJO类型参数
数组类型参数
集合类型参数
MVC获取数据细节
- 中文乱码问题
- @RequestParam 和 @PathVariable
- 自定义类型转换器
- 获得Servlet相关API
- @RequestHeader 和 @CookieValue
- 文件上传
3.5 SpringMVC 拦截器
3.5.1 拦截器(interceptor)的作用
Spring MVC 的拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。
将拦截器按一定的顺序联结成一条链,这条链称为拦截器链(Interceptor Chain)。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。拦截器也是AOP思想的具体实现。
3.5.2 拦截器和过滤器区别
3.5.3 拦截器快速入门
自定义拦截器很简单,只有如下三步:
①创建拦截器类实现HandlerInterceptor接口
1 |
|
②配置拦截器
在spring-mvc.xml中配置,多个拦截器配置顺序决定了执行顺序
1 |
|
③测试拦截器的拦截效果
编写目标方法
1 |
|
3.5.4 拦截器方法说明
3.6 SpringMVC 异常处理机制
3.6.1 异常处理的思路
系统中异常包括两类:预期异常和运行时异常 RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试等手段减少运行时异常的发生。
系统的Dao、Service、Controller出现都通过throws Exception向上抛出,最后由SpringMVC前端控制器交由异常处理器进行异常处理,如下图:
3.6.2 异常处理两种方式
使用Spring MVC提供的简单异常处理器SimpleMappingExceptionResolver
实现Spring的异常处理接口HandlerExceptionResolver 自定义自己的异常处理器
3.6.3 简单异常处理器 SimpleMappingExceptionResolver
SpringMVC已经定义好了该类型转换器,在使用时可以根据项目情况进行相应异常与视图的映射配置
spring-mvc.xml中配置
1 |
|
3.6.4 自定义异常处理步骤
①创建异常处理器类实现HandlerExceptionResolver
1 |
|
②配置异常处理器
spring-mvc.xml中配置
1 |
|
③编写异常页面
1 |
|
④测试异常跳转
1 |
|
4. Spring JdbcTemplate
用得不是很多,一般还是用 Mybatis/ibatis 等ORM框架实现
4.1 JdbcTemplate 概述
它是spring框架中提供的一个对象,是对原始繁琐的Jdbc API对象的简单封装。spring框架为我们提供了很多的操作模板类。
例如:操作关系型数据的JdbcTemplate和HibernateTemplate,操作nosql数据库的RedisTemplate,操作消息队列的JmsTemplate等等。
4.2 JdbcTemplate 开发步骤
①导入spring-jdbc和spring-tx坐标
1 |
|
②创建数据库表和实体
③创建JdbcTemplate对象
④执行数据库操作
1 |
|
4.3 Spring 产生 JdbcTemplate 对象
我们可以将JdbcTemplate的创建权交给Spring,将数据源DataSource的创建权也交给Spring,在Spring容器内部将数据源DataSource注入到JdbcTemplate模版对象中,配置如下:
1 |
|
从容器中获得JdbcTemplate进行添加操作
1 |
|
4.4 JdbcTemplate的常用操作
插入操作:见上面的样例
修改操作:
1
2
3
4
5
6
7
8
9
10
11@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class JdbcTemplateCRUDTest {
@Autowired
private JdbcTemplate jdbcTemplate;
@Test
//测试修改操作
public void testUpdate(){
jdbcTemplate.update("update account set money=? where name=?",1000,"tom");
}
}删除操作:
1
2
3
4@Test
public void testDelete(){
jdbcTemplate.update("delete from account where name=?","tom");
}查询全部操作:
1
2
3
4
5
6
7@Test
public void testQueryAll(){
List<Account> accounts = jdbcTemplate.query("select * from account", new BeanPropertyRowMapper<Account>(Account.class));
for (Account account : accounts) {
System.out.println(account.getName());
}
}查询单个数据操作:
1
2
3
4
5
6
7
8
9
10
11
12@Test
//测试查询单个对象操作
public void testQueryOne(){
Account account = jdbcTemplate.queryForObject("select * from account where name=?", new BeanPropertyRowMapper<Account>(Account.class), "tom");
System.out.println(account.getName());
}
@Test
//测试查询单个简单数据操作(聚合查询)
public void testQueryCount(){
Long aLong = jdbcTemplate.queryForObject("select count(*) from account", Long.class);
System.out.println(aLong);
}
4.5 要点总结
①导入spring-jdbc和spring-tx坐标
②创建数据库表和实体
③创建JdbcTemplate对象
1 |
|
④执行数据库操作
更新操作:
jdbcTemplate.update (sql,params)
查询操作:
jdbcTemplate.query (sql,Mapper,params)
jdbcTemplate.queryForObject(sql,Mapper,params)
5. Spring 的AOP
5.1 AOP 简介
5.1.1 AOP 是什么
AOP 为 Aspect Oriented Programming 的缩写,意思为面向切面编程,是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
AOP 是 OOP 的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
5.1.2 AOP 的作用和优势
作用:在程序运行期间,在不修改源码的情况下对方法进行功能增强
优势:减少重复代码,提高开发效率,并且便于维护
5.1.3 AOP 的底层实现
实际上,AOP 的底层是通过 Spring 提供的的动态代理技术实现的。在运行期间,Spring通过动态代理技术动态的生成代理对象,代理对象方法执行时进行增强功能的介入,在去调用目标对象的方法,从而完成功能的增强。
5.1.4 AOP 的动态代理技术
常用的动态代理技术
JDK 代理 : 基于接口的动态代理技术
cglib 代理:基于父类的动态代理技术
5.1.5 JDK的动态代理技术
详细的解释请见这一篇blog:动态代理
①目标类接口
1 |
|
②目标类
1 |
|
③动态代理代码
④ 调用代理对象的方法测试
1 |
|
5.1.6 cglib 的动态代理
该包已经集成到spring-core中了,可以直接使用
①目标类
1 |
|
②动态代理代码
③调用代理对象的方法测试
1 |
|
③调用代理对象的方法测试
1 |
|
5.1.7 AOP 相关概念
Spring 的 AOP 实现底层就是对上面的动态代理的代码进行了封装,封装后我们只需要对需要关注的部分进行代码编写,并通过配置的方式完成指定目标的方法增强。
在正式讲解 AOP 的操作之前,我们必须理解 AOP 的相关术语,常用的术语如下:
Target(目标对象):代理的目标对象
Proxy (代理):一个类被 AOP 织入增强后,就产生一个结果代理类
Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点
Pointcut(切入点):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义
Advice(通知/ 增强):所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知
Aspect(切面):是切入点和通知(引介)的结合
Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入
5.1.8 AOP 开发明确的事项
需要编写的内容
编写核心业务代码(目标类的目标方法)
编写切面类,切面类中有通知(增强功能方法)
在配置文件中,配置织入关系,即将哪些通知与哪些连接点进行结合
AOP 技术实现的内容
Spring 框架监控切入点方法的执行。一旦监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。
AOP 底层使用哪种代理方式
在 spring 中,框架会根据目标类是否实现了接口来决定采用哪种动态代理的方式。
- 有接口:JDK
- 无接口:cglib
5.1.9 要点总结
aop:面向切面编程
aop底层实现:基于JDK的动态代理 和 基于Cglib的动态代理
aop的重点概念:
- Pointcut(切入点):被增强的方法
- Advice(通知/ 增强):封装增强业务逻辑的方法
- Aspect(切面):切点+通知
- Weaving(织入):将切点与通知结合的过程
开发明确事项:
谁是切点(切点表达式配置)
谁是通知(切面类中的增强方法)
将切点和通知进行织入配置
5.2 基于 XML 的 AOP 开发
5.2.1 快速入门
①导入 AOP 相关坐标
1 |
|
②创建目标接口和目标类(内部有切点)
1 |
|
1 |
|
③创建切面类(内部有增强方法)
1 |
|
④将目标类和切面类的对象创建权交给 spring
applicationContext.xml 中配置
1 |
|
⑤在 applicationContext.xml 中配置织入关系
导入aop命名空间
1 |
|
配置切点表达式和前置增强的织入关系
1 |
|
⑥测试代码
1 |
|
5.2.2 AOP 配置详解
1. 切点表达式的写法
表达式语法:
1 |
|
访问修饰符可以省略
返回值类型、包名、类名、方法名可以使用星号* 代表任意
包名与类名之间一个点 . 代表当前包下的类,两个点 .. 表示当前包及其子包下的类
参数列表可以使用两个点 .. 表示任意个数,任意类型的参数列表
例如:
1 |
|
2. 通知的类型
通知的配置语法:
1 |
|
3. 切点表达式的抽取
当多个增强的切点表达式相同时,可以将切点表达式进行抽取,在增强中使用 pointcut-ref 属性代替 pointcut 属性来引用抽取后的切点表达式。
1 |
|
5.2.3 要点总结
aop织入的配置
1
2
3
4
5<aop:config>
<aop:aspect ref="切面类">
<aop:before method="通知方法名称" pointcut= "切点表达式" />
</aop:aspect>
</aop:config>通知的类型:前置通知、后置通知、环绕通知、异常抛出通知、最终通知
切点表达式的写法:
1
execution([修饰符] 返回值类型 包名.类名.方法名(参数))
5.3 基于注解的 AOP 开发
5.3.1 快速入门
基于注解的aop开发步骤:
①创建目标接口和目标类(内部有切点)
1 |
|
1 |
|
②创建切面类(内部有增强方法)
1 |
|
③将目标类和切面类的对象创建权交给 spring
1 |
|
④在切面类中使用注解配置织入关系
1 |
|
⑤在配置文件中开启组件扫描和 AOP 的自动代理
1 |
|
⑥测试
1 |
|
5.3.2 注解配置 AOP 详解
1. 注解通知类型
通知的配置语法:@通知注解(“切点表达式”)
2. 切点表达式的抽取
同 xml 配置 aop 一样,我们可以将切点表达式抽取。抽取方式是在切面内定义方法,在该方法上使用@Pointcut注解定义切点表达式,然后在在增强注解中进行引用。具体如下:
1 |
|
5.3.3 要点总结
- 注解aop开发步骤
①使用@Aspect标注切面类
②使用@通知注解标注通知方法
③在配置文件中配置aop自动代理< aop:aspectj-autoproxy />
- 通知注解类型:前置通知、后置通知、环绕通知、异常抛出通知、最终通知
6. Spring 声明式事务控制
需要理解编程式事务控制和申明式事务控制的区别
6.1 编程式事务控制相关对象
6.1.1 PlatformTransactionManager(了解)
PlatformTransactionManager 接口是 spring 的事务管理器,它里面提供了我们常用的操作事务的方法。
注意:
PlatformTransactionManager 是接口类型,不同的 Dao 层技术则有不同的实现类,例如:Dao 层技术是jdbc 或 mybatis 时:org.springframework.jdbc.datasource.DataSourceTransactionManager
Dao 层技术是hibernate时:org.springframework.orm.hibernate5.HibernateTransactionManager
6.1.2 TransactionDefinition
TransactionDefinition 是事务的定义信息对象,里面有如下方法:
- 事务的隔离级别:设置隔离级别,可以解决事务并发产生的问题,如脏读、不可重复读和虚读
- ISOLATION_DEFAULT
- ISOLATION_READ_UNCOMMITTED
- ISOLATION_READ_COMMITTED
- ISOLATION_REPEATABLE_READ
- ISOLATION_SERIALIZABLE
- 事务传播行为:解决业务方法在调用业务方法时,他们之间的事务统一性问题
- REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。一般的选择(默认值)
- SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)
- MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常
- REQUERS_NEW:新建事务,如果当前在事务中,把当前事务挂起。
- NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
- NEVER:以非事务方式运行,如果当前存在事务,抛出异常
- NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行 REQUIRED 类似的操作
- 超时时间:默认值是-1,没有超时限制。如果有,以秒为单位进行设置
- 是否只读:建议查询时设置为只读
6.1.3 TransactionStatus
TransactionStatus 接口提供的是事务具体的运行状态,方法介绍如下。
6.1.4 要点总结
编程式事务控制三大对象
PlatformTransactionManager:接口,指定事务控制行为
TransactionDefinition:封装事务参数,需要配置
TransactionStatus:被动的封装事务状态信息的,不需要配置
6.2 基于 XML 的声明式事务控制
6.2.1 什么是声明式事务控制
Spring 的声明式事务顾名思义就是采用声明的方式来处理事务。这里所说的声明,就是指在配置文件中声明,用在 Spring 配置文件中声明式的处理事务来代替代码式的处理事务。
作用:
- 事务管理不侵入开发的组件。具体来说,业务逻辑对象就不会意识到正在事务管理之中,事实上也应该如此,因为事务管理是属于系统层面的服务,而不是业务逻辑的一部分,如果想要改变事务管理策划的话,也只需要在定义文件中重新配置即可
- 在不需要事务管理的时候,只要在设定文件上修改一下,即可移去事务管理服务,无需改变代码重新编译,这样维护起来极其方便
Spring 声明式事务控制底层就是AOP
6.2.2 声明式事务控制的实现
声明式事务控制明确事项:
谁是切点?
谁是通知?
配置切面?
①引入tx命名空间
1 |
|
②配置事务增强
1 |
|
③配置事务 AOP 织入
1 |
|
④测试事务控制转账业务代码
1 |
|
6.2.3 切点方法的事务参数的配置
1 |
|
其中,< tx:method > 代表切点方法的事务参数的配置,例如:
1 |
|
name:切点方法名称
isolation:事务的隔离级别
propogation:事务的传播行为
timeout:超时时间
read-only:是否只读
6.2.4 要点总结
声明式事务控制的配置要点
平台事务管理器配置
事务通知的配置
事务aop织入的配置
6.3 基于注解的声明式事务控制
6.3.1 使用注解配置声明式事务控制
准备工作:
编写 AccountDao 和 AccountService
1 |
|
1 |
|
编写 applicationContext.xml 配置文件
1 |
|
6.3.2 注解配置声明式事务控制解析
①使用 @Transactional 在需要进行事务控制的类或是方法上修饰,注解可用的属性同 xml 配置方式,例如隔离级别、传播行为等。
②注解使用在类上,那么该类下的所有方法都使用同一套注解参数配置。
③使用在方法上,不同的方法可以采用不同的事务参数配置。
④Xml配置文件中要开启事务的注解驱动< tx:annotation-driven />
6.3.3 要点总结
注解声明式事务控制的配置要点
平台事务管理器配置(xml方式)
事务通知的配置(@Transactional注解配置)
事务注解驱动的配置 < tx:annotation-driven />
7. Mybatis
实战练习:
- 第一阶段的spring练习:巩固 2 - 3.4 以及 4 的知识实战 —— 视频 p89 - p106
- 第二阶段的spring练习:巩固 3.5 的知识实践 —— 视频 p112- p115
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!