SSM

(写在开头:本文主要依据黑马程序员SSM框架教程PPT资料编写)

一、Spring

Spring的基本概念

loC 反转控制
AOP 面向切面编程

Spring的快速入门

spring的基本开发步骤

1.导入Spring开发的基本包坐标

2.编写Dao接口和实现类

3.创建Spring核心配置文件

4.在Spring配置文件中配置UserDaoImpl

5.使用Spring的API获得Bean实例

快速入门步骤

1.导入坐标

2.创建Bean

3.创建applicationContext.xml

4.在配置文件中进行配置

5.创建ApplicationContext对象getBean

Spring配置文件

Bean标签的配置

 用于配置对象交由Soring来创建默认的情况下他会调用类中的无参构造函数,如果没有无参构造则不能创建成功

Bean标签的基本属性

id :Bean实例在Spring容器中的唯一标识
class:Bean的全限定名称

Bean标签的范围取值

 scope:指对象的做哟ing范围,取值如下

scope的取值为singleton时

Bean的实例化个数:1个

Bean的实例化时机:当Spring核心文件被加载时,实例化配置的Bean实例

Bean的生命周期:

  对象创建:当应用加载,创建容器时,对象就被创建了

 对象运行:只要容器在,对象就就一直活着

  对象销毁:当应用卸载,销毁容器时,对象就被销毁了

scope的取值为prototype

Bean的实例化个数:多个

Bean的实例化时机:当调用getBean()方法时实例化Bean

Bean的生命周期:

  对象创建:当使用对象时,创建新的对象实例

 对象运行:只要对对象在使用中,对象就就一直活着

 对象销毁:当对象长时间不用时,杯Java的垃圾回收器回收了

Bean的生命周期配置

init-method:指定类中的初始化方法名称

destroy-method:指定类中的销毁方法

Bean实例化三种方式

  • 无参构造方法实例化

  • 工厂静态方法实例化

  • 工厂实例方法实例化


例:工厂实例方法实例化


Bean的依赖注入


依赖注入的具体分析

依赖注入 (Denpendency Injection):它是Spring框架核心IOC的具体实现。

在编写程序时,通过控制反转,把对象的创建交给了Spring,但是代码中不可能出现没有依赖的情况。IOC解耦知识降低他们的依赖的关系,但是并不会消除。例如:业务层任然会调用持久层的方法。

那这种业务层和持久层的依赖关系,在使用Spring之后,就让Spring来维护了。简单的说,就是坐等框架把持久层的对象储如业务层,而不用我们自己去获取。

依赖注入的方式

思考:怎样将UserDao植入到UserService内部呢?

  • 构造方法

  • set方法

1.set方法的注入

普通的set方法注入

P命名空间的注入

P命名空间注入本质也是set方法注入,但比set方法的注入更加的方便,主要体现在配置文件中

修改注入方式

2.构造注入

Bean的依赖注入的数据类型

除了对象的引用可以注入,普通的数据类型,集合等都可以在容器中进行注入

注入数据发的三种数据类型

  • 普通数据类型

  • 引用数据类型

  • 集合数据类型

引用其他配置文件(分模块开发)

实际的开发中,Spring的配置内容非常多,这就导致Spring配置之很繁杂且体积很大,所以,可以将部分配置拆解到其他的配置文件中,而在Spring主配置文件通过impor标签进行加载

Spring相关的API

ApplicationContext的继承体系

applicationContext:接口类型,代表应用上下文,可以通过其实例获得Spring容器中的Bean对象

ApplicationContext的实现类

  • ClassPathXmlApplicationContext

他是从类根路径下加载配置文件 (推荐使用)

  • FileSystemXmlApplicationContext

他是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。

  • AnnotationConfigApplicationContext

使用注解配置容器对象时,需要使用此类来创建Spring容器。它用来读取注解。

getBean可以通过多种方式进行获取

app.getBean(“id”)   根据id获取 唯一的

app.getBean(class)   根据类型获取 不一定唯一

Spring配置数据源

数据源(连接池)的作用

数据源是为了提高程序性能出现的;实现实例化数据源,初始化部分连接资源;使用连接资源时从数据源中获取;使用我完毕后将连接资源归还给数据源

常见的数据源(连接池):DBCP,C3P0,BoneCP,Druid等

数据源的开发步骤

  • 导入数据源的坐标和数据库驱动坐标

  • 创建数据源对象

  • 设置数据源的基本连接数据

  • 使用数据源获取连接资源和归还连接资源


    1. 手动创建c3p0数据源

2.手动创建Druid数据源

3.从配置文件中获取

由Spring配置数据源

可以将DataSource的创建权交由Spring容器去完成

  1. 配置Bean
  2. Spring容器产生数据源对象

注意: c3p0和druid的bean配置时 他们的需要注入的driver,url等的名字不同,主要取决于他们内部对应的set方法不同,需要注入的名字就是set后面对应的名字

由spring中加载properties配置文件

  1. 首先需要映入context命名空间和约束路径

命名空间复制xmlns,在xmlns后面加上:context,最后将bean全部改为context,最后即是

  1. 同理约束路径为
  2. 加载外部的properties文件

location即是文件的位置

使用EL表达式将properties中的数据传入bean

即 ${key}

  1. 最后同上

Spring注解开发

Spring的原始注解

spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,注解代替xml配置文件可以简化配置,提高开发效率。

spring的原始注解主要是替代Bean的配置

注意:使用注解进行开发时,,需要applicationContext.xml中配置组件扫描,作用时指定哪个包及其子包下需要进行扫描以便识别使用注解配置的类,字段和方法

@Value注解

配合这个表达式使用

spring的新注解

具体实现
配置数据源

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
@Configuration
//说明这是一个核心配置文件
@ComponentScan("com.itheima")
//扫描组件对应着xml中的 <context:component-scan base-package="com.itheima">
@PropertySource("classpath:jdbc.properties");
//从properties文件中获取那些数据 对应着xml中的 <context:property-placeholder location="classpath:jdbc.properties"/>

public class SpringConfiguration {
//使用@Value注入值
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
public DataSource getDataSource() throws PropertyVetoException{
ComboPooledDataSource dataSource = new ComboPooledDataSource;
dataSource.setDriverclass(driver);
dataSource.setJdbcUrl(url);
dataSource.setUser(username);
dataSource.setPassword(password);
return dataSource;

}
}

Spring集成Junit

步骤

  1. 导入spring集成junit的jar包
  2. 使用@Runwith注解替换原来的运行期
  3. 使用@ContextConfiguration指定配置文件或配置类
  4. 使用@Autowired注入需要测试的对象
  5. 创建测试方法进行测试

Spring与Web环境的集成

  • ApplicationContext应用上下文获取方式

应用上下文对象是通过new ClasspathXmlApplicationContext (spring配置文件)方式获取的,但是每次从容器中获得Bean时都要编写new ClasspathXmlApplicationContext (spring配置文件),这样的弊端是配置的时候文件加载多次,应用上下文对象创建多次。

在Web项目中可以使用ServletContextListener监听Web应用的启动,我们可以在Web应用启动时,就加载Spring的配置文件,创建应用上下文对象ApplicationContext,在将其存储到最大的域servletContext域中,这样就可以在任意位置从域中获得上下文对象ApplicationContext对象了。

spring提供获取应用上下文的工具

Spring提供了一个监听器ContextLoaderListener就是对方法的封装,该监听器内部加载Spring配置文件,创建应用上下文对象,并存储到ServletContext域中,提供了一个客户端工具WebApplicationContextUtils供使用者获取应用上下文对象。

所以我们只需要只有两件事

  1. 在Web.XML中配置ContextLoaderListener监听器(导入spring-web坐标)
  2. 使用WebApplicationContextUtils获得上下文对象ApplicationContext

二、SpringMVC

SpringMVC的简介

概述

SpringMVC是一种基于Java的实现MVC设计模型的请求驱动类型的轻量级Web框架,属于SpringFrameWork的后续产品,已经融合在Spring Web Flow中

开发步骤

  1. 导入SpringMVC的相关坐标
  2. 配置SpringMVC核心控制器DispathcerServlet
  3. 创建Controller类和视图页面
  4. 使用注解配置Controller类中业务方法得到映射地址
  5. 配置SpringMVC核心文件Spring-mvc.xml
  6. 客户端发起请求测试
  7. SpringMVC的执行流程

图示

文字

SpringMVC注解解析

@RequestMapping

作用:用于建立请求 URL 和处理请求方法之间的对应关系
位置:
类上,请求URL 的第一级访问目录。此处不写的话,就相当于应用的根目录
方法上,请求 URL 的第二级访问目录,与类上的使用@ReqquestMapping标注的一级目录一起组成访问虚拟路径
属性:
value:用于指定请求的URL。它和path属性的作用是一样的
method:用于指定请求的方式
params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的key和value必须和配置的一模一样
例如:
params = {“accountName”},表示请求参数必须有accountName
params = {“moeny!100”},表示请求参数中money不能是100

mvc命名空间引入

命名空间: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注解标注的话,就需要使用<context:component-scan base-package=“com.itheima.controller"/>进行组件扫描。

SpringMVC的XML配置解析

视图解析器

SpringMVC有默认组件配置,默认组件都是DispatcherServlet.properties配置文件中配置的,该配置文件地址org/springframework/web/servlet/DispatcherServlet.properties,该文件中配置了默认的视图解析器,如下:

1
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

我们可以通过属性注入的方式修改视图的的前后缀

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>

SpringMVC的相关组件

前端控制器:DispatcherServlet
处理器映射器:HandlerMapping
处理器适配器:HandlerAdapter
处理器:Handler
视图解析器:View Resolver
视图:View

SpringMVC的注解和配置

请求映射注解:@RequestMapping
视图解析器配置:
REDIRECT_URL_PREFIX = “redirect:”
FORWARD_URL_PREFIX = “forward:”
prefix = “”;
suffix = “”;

SpringMVC的数据响应方式

1) 页面跳转
直接返回字符串
通过ModelAndView对象返回

2) 回写数据
直接返回字符串
返回对象或集合

页面跳转

  • 返回字符串形式
    直接返回字符串:此种方式会将返回的字符串与视图解析器的前后缀拼接后跳转
  • 返回ModelAndView对象
  • 向request域存储数据
    A. 通过SpringMVC框架注入的request对象setAttribute()方法设置

    B.通过ModelAndView的addObject()方法设置

回写数据

1.直接返回字符串

通过SpringMVC框架注入的response对象,使用response.getWriter().print(“hello world”) 回写数据,此时不需要视图跳转,业务方法返回值为void。

将需要回写的字符串直接返回,但此时需要通过@ResponseBody注解告知SpringMVC框架,方法返回的字符串不是跳转是直接在http响应体中返回。

在异步项目中,客户端与服务器端往往要进行json格式字符串交互,此时我们可以手动拼接json字符串返回。

上述方式手动拼接json格式字符串的方式很麻烦,开发中往往要将复杂的java对象转换成json格式的字符串,我们可以使用web阶段学习过的json转换工具jackson进行转换,导入jackson坐标。

2. 返回对象或集合
通过SpringMVC帮助我们对对象或集合进行json字符串的转换并回写,为处理器适配器配置消息转换参数,指定使用jackson进行对象或集合的转换,因此需要在spring-mvc.xml中进行如下配置:


在方法上添加@ResponseBody就可以返回json格式的字符串,但是这样配置比较麻烦,配置的代码比较多,因此,我们可以使用mvc的注解驱动代替上述配置。

在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。
使用mvc:annotation-driven自动加载 RequestMappingHandlerMapping(处理映射器)和
RequestMappingHandlerAdapter( 处 理 适 配 器 ),可用在Spring-xml.xml配置文件中使用
mvc:annotation-driven替代注解处理器和适配器的配置。
同时使用mvc:annotation-driven默认底层就会集成jackson进行对象或集合的json格式字符串的转换。

SpringMVC 获得请求数据

获得请求参数

客户端请求参数的格式是:name=value&name=value… …
服务器端要获得请求的参数,有时还需要进行数据的封装,SpringMVC可以接收如下类型的参数:

  • 基本类型参数
  • POJO类型参数
  • 数组类型参数
  • 集合类型参数

获得基本类型参数

Controller中的业务方法的参数名称要与请求参数的name一致,参数值会自动映射匹配。

获得POJO类型参数

Controller中的业务方法的POJO参数的属性名与请求参数的name一致,参数值会自动映射匹配。

获得数组类型参数

Controller中的业务方法数组名称与请求参数的name一致,参数值会自动映射匹配。

获得集合类型参数

获得集合参数时,要将集合参数包装到一个POJO中才可以。

当使用ajax提交时,可以指定contentType为json形式,那么在方法参数位置使用@RequestBody可以直接接收集合数据而无需使用POJO进行包装。
1
2
注意:通过谷歌开发者工具抓包发现,没有加载到jquery文件,原因是SpringMVC的前端控制器DispatcherServlet的url-pattern配置的是/,代表对所有的资源都进行过滤操作,我们可以通过以下两种方式指定放行静态资源:
在spring-mvc.xml配置文件中指定放行的资源
<mvc:resources mapping=“/js/**” location=“/js/”/>
使用mvc:default-servlet-handler/标签

请求数据乱码问题

当post请求时,数据会出现乱码,我们可以设置一个过滤器来进行编码的过滤。

参数绑定注解@requestParam

当请求的参数名称与Controller的业务方法参数名称不一致时,就需要通过@RequestParam注解显示的绑定。

注解@RequestParam还有如下参数可以使用:

  • value:与请求参数名称
  • required:此在指定的请求参数是否必须包括,默认是true,提交时如果没有此参数则报错
  • defaultValue:当没有指定请求参数时,则使用指定的默认值赋值

获得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注解进行占位符的匹配获取工作。

自定义类型转换器

  • SpringMVC 默认已经提供了一些常用的类型转换器,例如客户端提交的字符串转换成int型进行参数设置。
  • 但是不是所有的数据类型都提供了转换器,没有提供的就需要自定义转换器,例如:日期类型的数据就需要自定义转换器。

自定义类型转换器的开发步骤:

  1. 定义转换器类实现Converter接口
  2. 在配置文件中声明转换器
  3. 中引用转换器

第一步:定义转换器类实现Converter接口

第二步:在配置文件中声明转换器

第三步:在中引用转换器

获得Servlet相关API

SpringMVC支持使用原始ServletAPI对象作为控制器方法的参数进行注入,常用的对象如下:

  • HttpServletRequest
  • HttpServletResponse
  • HttpSession

获得请求头

@RequestHeader

使用@RequestHeader可以获得请求头信息,相当于web阶段学习的request.getHeader(name)
@RequestHeader注解的属性如下:

  • value:请求头的名称
  • required:是否必须携带此请求头

    @CookieValue
    使用@CookieValue可以获得指定Cookie的值
    @CookieValue注解的属性如下:
  • value:指定cookie的名称
  • required:是否必须携带此cookie

文件上传

  • 文件上传客户端三要素
  • 表单项type=“file”
  • 表单的提交方式是post
  • 表单的enctype属性是多部分表单形式,及enctype=“multipart/form-data”

    2.文件上传原理
  • 当form表单修改为多部分表单时,request.getParameter()将失效。
  • enctype=“application/x-www-form-urlencoded”时,form表单的正文内容格式是:key=value&key=value&key=value
  • 当form表单的enctype取值为Mutilpart/form-data时,请求正文内容就变成多部分形式:

单文件上传步骤

  1. 导入fileupload和io坐标
  2. 配置文件上传解析器
  3. 编写文件上传代码

单文件上传实现

  1. 导入fileupload和io坐标
  2. 配置文件上传解析器
  3. 编写文件上传代码

多文件上传实现

多文件上传,只需要将页面修改为多个文件上传项,将方法参数MultipartFile类型修改为MultipartFile[]即可

SpingMVC拦截器

Spring MVC 的拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。

将拦截器按一定的顺序联结成一条链,这条链称为拦截器链(Interceptor Chain)。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。拦截器也是AOP思想的具体实现。

拦截器快速入门

自定义拦截器很简单,只有如下三步:

  • 创建拦截器类实现HandlerInterceptor接口
  • 配置拦截器
  • 测试拦截器的拦截效果
  1. 创建拦截器类实现HanderInterceptor接口
  2. 配置拦截器
  3. 测试拦截器的拦截效果(编写目标方法)

拦截器方法说明

SpringMVC异常处理

异常处理思路

系统中异常包括两类:预期异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试等手段减少运行时异常的发生。

系统的Dao、Service、Controller出现都通过throws Exception向上抛出,最后由SpringMVC前端控制器交由异常处理器进行异常处理,如下图:

异常处理两种方式

  • 使用Spring MVC提供的简单异常处理器SimpleMappingExceptionResolver
  • 实现Spring的异常处理接口HandlerExceptionResolver 自定义自己的异常处理器

简单异常处理器SimpleMappingExceptionResolver

SpringMVC已经定义好了该类型转换器,在使用时可以根据项目情况进行相应异常与视图的映射配置

自定义异常处理步骤

  • 创建异常处理器类实现HandlerExceptionResolver
  • 配置异常处理器
  • 编写异常页面
  • 测试异常跳转
  1. 创建异常处理器类实现HandlerExceptionResolver
  2. 配置异常处理器
  3. 编写异常界面
  4. 测试异常跳转

AOP

AOP简介

what is AOP

AOP 为 Aspect Oriented Programming 的缩写,意思为面向切面编程,是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。

AOP 是 OOP 的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

AOP的作用及其优势

作用:在程序运行期间,在不修改源码的情况下对方法进行功能增强
优势:减少重复代码,提高开发效率,并且便于维护

AOP的底层实现

实际上,AOP 的底层是通过 Spring 提供的的动态代理技术实现的。在运行期间,Spring通过动态代理技术动态的生成代理对象,代理对象方法执行时进行增强功能的介入,在去调用目标对象的方法,从而完成功能的增强。

AOP的动态代理技术

常用的动态代理技术

  • JDK 代理 : 基于接口的动态代理技术
  • cglib 代理:基于父类的动态代理技术

JDK的动态代理

  1. 目标类接口
  2. 目标类
  3. 动态代理代码
  4. 调用代理对象的方法测试

cglib 的动态代理

  1. 目标类
  2. 动态代理代码
  3. 调用代理对象的方法测试

AOP相关的概念

Spring 的 AOP 实现底层就是对上面的动态代理的代码进行了封装,封装后我们只需要对需要关注的部分进行代码编写,并通过配置的方式完成指定目标的方法增强。

Target(目标对象):代理的目标对象
Proxy (代理):一个类被 AOP 织入增强后,就产生一个结果代理类
Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点
Pointcut(切入点):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义
Advice(通知/ 增强):所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知
Aspect(切面):是切入点和通知(引介)的结合
Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入

AOP 开发明确的事项

  1. 需要编写的内容
    编写核心业务代码(目标类的目标方法)
    编写切面类,切面类中有通知(增强功能方法)
    在配置文件中,配置织入关系,即将哪些通知与哪些连接点进行结合
  2. AOP 技术实现的内容
    Spring 框架监控切入点方法的执行。一旦监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。
  3. AOP 底层使用哪种代理方式
    在 spring 中,框架会根据目标类是否实现了接口来决定采用哪种动态代理的方式。

AOP知识要点

aop:面向切面编程
aop底层实现:基于JDK的动态代理 和 基于Cglib的动态代理
aop的重点概念:
Pointcut(切入点):被增强的方法
Advice(通知/ 增强):封装增强业务逻辑的方法
Aspect(切面):切点+通知
Weaving(织入):将切点与通知结合的过程
开发明确事项:
谁是切点(切点表达式配置)
谁是通知(切面类中的增强方法)
将切点和通知进行织入配置

基于XMl的AOP开发

快速入门

  1. 导入AOP相关坐标
  2. 创建目标接口和目标类(内部有切点)
  3. 创建切面类(内部有增强方法)
  4. 将目标类和切面类 的对象创建权交给spring
  5. 在applicationContext.xml中配置关系
    导入aop命名空间

    配置切点表达式和前置增强的植入关系
  6. 测试代码

XML配置AOP详解

  1. 切点表达式的写法
    表达式语法

    访问修饰符可以省略
    返回值类型、包名、类名、方法名可以使用星号* 代表任意
    包名与类名之间一个点 . 代表当前包下的类,两个点 … 表示当前包及其子包下的类
    参数列表可以使用两个点 … 表示任意个数,任意类型的参数列表
    such as
  2. 通知的类型
    通知的配置语法

  3. 切点表达式的抽取
    当多个增强的切点表达式相同时,可以将切点表达式进行抽取,在增强中使用 pointcut-ref 属性代替 pointcut 属性来引用抽取后的切点表达式。

知识要点

aop织入的配置

通知的类型:前置通知、后置通知、环绕通知、异常抛出通知、最终通知
切点表达式的写法:

基于注解的AOP开发

快速入门

基于注解的aop开发步骤:

  • 创建目标接口和目标类(内部有切点)

  • 创建切面类(内部有增强方法)

  • 将目标类和切面类的对象创建权交给 spring

  • 在切面类中使用注解配置织入关系

  • 在配置文件中开启组件扫描和 AOP 的自动代理

  • 测试

  • 创建目标接口和目标类(内部有切点)

  • 创建切面类

  • 将目标类和切面类的对象创建权交给 spring

  • 在切面类中使用注解配置织入关系

  • 在配置文件中开启组件扫描和 AOP 的自动代理

  • 测试代码

注解配置 AOP 详解

  • 注解通知的类型
    通知的配置语法:@通知注解(“切点表达式")
  • 切点表达式的抽取
    同 xml 配置 aop 一样,我们可以将切点表达式抽取。抽取方式是在切面内定义方法,在该方法上使用@Pointcut注解定义切点表达式,然后在在增强注解中进行引用。具体如下:

知识要点

注解aop开发步骤

  • 使用@Aspect标注切面类
  • 使用@通知注解标注通知方法
  • 在配置文件中配置aop自动代理aop:aspectj-autoproxy/

通知注解类型

编程式事物控制相关对象

PlatformTransactionManager

PlatformTransactionManager 接口是 spring 的事务管理器,它里面提供了我们常用的操作事务的方法。

注意:
PlatformTransactionManager 是接口类型,不同的 Dao 层技术则有不同的实现类,例如:Dao 层技术是jdbc 或 mybatis 时:org.springframework.jdbc.datasource.DataSourceTransactionManager
Dao 层技术是hibernate时:org.springframework.orm.hibernate5.HibernateTransactionManager

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,没有超时限制。如果有,以秒为单位进行设置

  • 是否只读:建议查询时设置为只读

TransactionStatus 接口提供的是事务具体的运行状态,方法介绍如下。

知识要点

编程式事务控制三大对象

  • PlatformTransactionManager
  • TransactionDefinition
  • TransactionStatus

基于 XML 的声明式事务控制

什么是声明式事务控制
Spring 的声明式事务顾名思义就是采用声明的方式来处理事务。这里所说的声明,就是指在配置文件中声明,用在 Spring 配置文件中声明式的处理事务来代替代码式的处理事务。
声明式事务处理的作用

  • 事务管理不侵入开发的组件。具体来说,业务逻辑对象就不会意识到正在事务管理之中,事实上也应该如此,因为事务管理是属于系统层面的服务,而不是业务逻辑的一部分,如果想要改变事务管理策划的话,也只需要在定义文件中重新配置即可

  • 在不需要事务管理的时候,只要在设定文件上修改一下,即可移去事务管理服务,无需改变代码重新编译,这样维护起来极其方便
    注意:Spring 声明式事务控制底层就是AOP。

声明式事务控制的实现

  • 引入tx命名空间
  • 配置事务增强
  • 配置事务AOP织入
  • 测试事务控制转账业务代码

切点方法的事务参数的配置


其中,tx:method 代表切点方法的事务参数的配置,例如:
<tx:method name=“transfer” isolation=“REPEATABLE_READ” propagation=“REQUIRED” timeout=“-1” read-only=“false”/>

  • name:切点方法名称

  • isolation:事务的隔离级别

  • propogation:事务的传播行为

  • timeout:超时时间

  • read-only:是否只读

基于注解的声明式事务控制

使用注解怕配置声明式事务控制

  • 编写AccountDao

  • 编写AccountService

  • 编写applicationContext.xml配置文件

注解配置声明式事务控制解析

  • 使用 @Transactional 在需要进行事务控制的类或是方法上修饰,注解可用的属性同 xml 配置方式,例如隔离级别、传播行为等。

  • 注解使用在类上,那么该类下的所有方法都使用同一套注解参数配置。

  • 使用在方法上,不同的方法可以采用不同的事务参数配置。

  • Xml配置文件中要开启事务的注解驱动<tx:annotation-driven />

三、Mybatis

Mybatis简介

什么是Mybatis

  • mybatis是一个优秀的基于java的持久层框架,它内部封装了jdbc,使开发者只需要关注sql语句本身,而不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。
  • mybatis通过xml或注解的方式将要执行的各种statement配置起来,并通过java对象和statement中sql的动态参数进行映射生成最终执行的sql语句。
  • 最后mybatis框架执行sql并将结果映射为java对象并返回。采用ORM思想解决了实体和数据库映射的问题,对jdbc进行了封装,屏蔽了jdbc api 底层访问细节,使我们不用与jdbc api 打交道,就可以完成对数据库的持久化操作。

Mybatis快速入门

Mybatis开发步骤

Mybatis官网地址:http://www.mybatis.org/mybatis-3/

  • 添加MyBatis的坐标
  • 创建user数据表
  • 编写User实体类
  • 编写映射文件UserMapper.xml
  • 编写核心文件SqlMapConfig.xml
  • 编写测试类

环境搭建

  • 导入Mybatis坐标及其他的相关坐标

  • 创建user表格
  • 编写user实体
  • 编写UserMapper映射文件
  • 编写Mybatis核心文件
  • 编写测试代码

Mybatis映射文件概述

Mybatis的增删改查操作

插入数据操作

  • 编写UserMapper映射文件
  • 编写插入实体的User的代码
  • 插入操作需要注意的问题
  • 插入语句使用insert标签
  • 在映射文件中使用parameterType属性指定要插入的数据类型
  • Sql语句中使用#{实体属性名}方式引用实体中的属性值
  • 插入操作使用的API是sqlSession.insert(“命名空间.id”,实体对象);
  • 插入操作涉及数据库数据变化,所以要使用sqlSession对象显示的提交事务,即sqlSession.commit()

修改数据操作

  • 编写UserMapper的映射文件

  • 编写修改 实体User的代码

  • 修改操作需要注意的问题

  • 修改语句使用update标签

  • 修改操作使用的API是sqlSession.update(“命名空间.id”,实体对象);

删除数据操作

  1. 编写UserMapper的映射文件

  2. 编写删除数据的代码

  3. 删除操作需注意问题

  • 删除语句使用delete标签

  • Sql语句中使用#{任意字符串}方式引用传递的单个参数

  • 删除操作使用的API是sqlSession.delete(“命名空间.id”,Object);

知识小结

增删改查映射配置与API:
查询数据:

1
2
3
4
List<User> userList = sqlSession.selectList("userMapper.findAll");
<select id="findAll" resultType="com.itheima.domain.User">
select * from User
</select>

添加数据:

1
2
3
4
sqlSession.insert("userMapper.add", user);
<insert id="add" parameterType="com.itheima.domain.User">
insert into user values(#{id},#{username},#{password})
</insert>

修改数据:

1
2
3
4
sqlSession.update("userMapper.update", user);
<update id="update" parameterType="com.itheima.domain.User">
update user set username=#{username},password=#{password} where id=#{id}
</update>

删除数据:

1
2
3
4
sqlSession.delete("userMapper.delete",3);
<delete id="delete" parameterType="java.lang.Integer">
delete from user where id=#{id}
</delete>

Mybatis核心配置文件概述

Mybatis核心配置文件的层级关系

Mybatis常用配置文件解析

environment标签

数据库环境的配置,支持多环境配置

其中,事务管理器(transactionManager)类型有两种:

  • JDBC:这个配置就是直接使用了JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域。
  • MANAGED:这个配置几乎没做什么。它从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。
    默认情况下它会关闭连接,然而一些容器并不希望这样,因此需要将 closeConnection 属性设置为 false来阻止它默认的关闭行为。

其中,数据源(dataSource)类型有三种:

  • UNPOOLED:这个数据源的实现只是每次被请求时打开和关闭连接。
  • POOLED:这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来。
  • JNDI:这个数据源的实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI
    上下文的引用。

mapper标签

该标签的作用是加载映射的,加载方式有如下几种:

  • 使用相对于类路径的资源引用,例如:

  • 使用完全限定资源定位符(URL),例如:

  • 使用映射器接口实现类的完全限定类名,例如:

  • 将包内的映射器接口实现全部注册为映射器,例如:

Properties标签

实际开发中,习惯将数据源的配置信息单独抽取成一个properties文件,该标签可以加载额外配置的properties文件

typeAliases标签

类型别名是为Java 类型设置一个短的名字。原来的类型名称配置如下

配置typeAliases,为com.itheima.domain.User定义别名为user
上面我们是自定义的别名,mybatis框架已经为我们设置好的一些常用的类型的别名

知识小结


Mybatis相应的API

SqlSession工厂构建器SqlSessionFactoryBuilder

常用API:SqlSessionFactory build(InputStream inputStream)
通过加载mybatis的核心文件的输入流的形式构建一个SqlSessionFactory对象

其中, Resources 工具类,这个类在 org.apache.ibatis.io 包中。Resources 类帮助你从类路径下、文件系统或一个 web URL 中加载资源文件。

SqlSession工厂对象SqlSessionFactory

SqlSessionFactory 有多个个方法创建 SqlSession 实例。常用的有如下两个:

SqlSession会话对象

SqlSession 实例在 MyBatis 中是非常强大的一个类。在这里你会看到所有执行语句、提交或回滚事务和获取映射器实例的方法。
执行语句的方法主要有:

操作事务的方法主要有:

MyBatis的Dao层实现

传统开发方式

  1. 编写UserDao接口

  2. 编写UserDaoImpl实现

  3. 测试传统方式

代理开发方式

  • 代理开发方式介绍
    采用 Mybatis 的代理开发方式实现 DAO 层的开发,这种方式是我们后面进入企业的主流。
    Mapper 接口开发方法只需要程序员编写Mapper 接口(相当于Dao 接口),由Mybatis 框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
    Mapper 接口开发需要遵循以下规范:
    1、 Mapper.xml文件中的namespace与mapper接口的全限定名相同
    2、 Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
    3、 Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同
    4、 Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
  • 编写UserMapper接口
  • 测试代理方法

知识小结

Mybatis映射文件深入

动态sql语句

1. 概述
Mybatis 的映射文件中,前面我们的 SQL 都是比较简单的,有些时候业务逻辑复杂时,我们的 SQL是动态变化的,此时在前面的学习中我们的 SQL 就不能满足要求了。
2. 动态语句之if
我们根据实体类的不同取值,使用不同的 SQL语句来进行查询。比如在 id如果不为空时可以根据id查询,如果username 不同空时还要加入用户名作为条件。这种情况在我们的多条件组合查询中经常会碰到。

当查询条件id和username都存在时,控制台打印的sql语句如下:
当查询条件只有id存在时,控制台打印的sql语句如下:
动态 SQL 之foreach
循环执行sql的拼接操作,例如:SELECT * FROM USER WHERE id IN (1,2,5)。
测试代码片段如下:
foreach标签的属性含义如下:
标签用于遍历集合,它的属性:

  • collection:代表要遍历的集合元素,注意编写时不要写#{}
  • open:代表语句的开始部分
  • close:代表结束部分
  • item:代表遍历集合的每个元素,生成的变量名
  • sperator:代表分隔符

SQL片段抽取

Sql 中可将重复的 sql 提取出来,使用时用 include 引用即可,最终达到 sql 重用的目的

知识小结

MyBatis映射文件配置:

1
2
3
4
5
6
7
8
<select>:查询
<insert>:插入
<update>:修改
<delete>:删除
<where>:where条件
<if>:if判断
<foreach>:循环
<sql>:sql片段抽取

Mybatis核心文件深入

typeHandlers标签

无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。下表描述了一些默认的类型处理器(截取部分)。

你可以重写类型处理器或创建你自己的类型处理器来处理不支持的或非标准的类型。具体做法为:实现 org.apache.ibatis.type.TypeHandler 接口, 或继承一个很便利的类 org.apache.ibatis.type.BaseTypeHandler, 然后可以选择性地将它映射到一个JDBC类型。例如需求:一个Java中的Date数据类型,我想将之存到数据库的时候存成一个1970年至今的毫秒数,取出来时转换成java的Date,即java的Date与数据库的varchar毫秒值之间转换。

开发步骤:

  1. 定义转换类继承类BaseTypeHandler
  2. 覆盖4个未实现的方法,其中setNonNullParameter为java程序设置数据到数据库的回调方法,
  3. getNullableResult为查询时 mysql的字符串类型转换成 java的Type类型的方法
  4. 在MyBatis核心配置文件中进行注册
  5. 测试转换是否正确

plugins标签

MyBatis可以使用第三方的插件来对功能进行扩展,分页助手PageHelper是将分页的复杂操作进行封装,使用简单的方式即可获得分页的相关数据
开发步骤:

  1. 导入通用PageHelper的坐标
  2. 在mybatis核心配置文件中配置PageHelper插件
  3. 测试分页数据获取

导入通用PageHelper坐标
在mybatis核心配置文件中配置PageHelper插件
测试分页代码实现
获得分页相关的其他参数

知识小结

MyBatis核心配置文件常用标签:
1、properties标签:该标签可以加载外部的properties文件
2、typeAliases标签:设置类型别名
3、environments标签:数据源环境配置标签
4、typeHandlers标签:配置自定义类型处理器
5、plugins标签:配置MyBatis的插件

Mybatis的多表操作

一对一查询

  1. 一对一查询的模型
    用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户
    一对一查询的需求:查询一个订单,与此同时查询出该订单所属的用户
  2. 一对一查询的语句
    对应的sql语句:select * from orders o,user u where o.uid=u.id;
    查询的结果如下:
  3. 创建Order和User实体
  4. 创建OrderMapper接口
  5. 配置OrderMapper.xml
    其中resultMap还可以配置如下:
  6. 测试结果

一对多查询

  1. 一对多查询的模型
    用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户
    一对多查询的需求:查询一个用户,与此同时查询出该用户具有的订单
  2. 一对多查询的语句
    对应的sql语句:select *,o.id oid from user u left join orders o on u.id=o.uid;
    查询的结果如下:
  3. 修改User实体
  4. 创建UserMapper接口
  5. 配置UserMapper.xml
  6. 测试结果

多对多查询

  1. 多对多查询的模型
    用户表和角色表的关系为,一个用户有多个角色,一个角色被多个用户使用
    多对多查询的需求:查询用户同时查询出该用户的所有角色
  2. 多对多查询的语句
    对应的sql语句:select u.,r.,r.id rid from user u left join user_role ur on u.id=ur.user_id
    inner join role r on ur.role_id=r.id;
    查询的结果如下:
  3. 创建Role实体,修改User实体
  4. 添加UserMapper接口方法
  5. 配置UserMapper.xml6. 测试结果

知识小结

MyBatis多表配置方式:
一对一配置:使用 < resultMap > 做配置
一对多配置:使用< resultMap > + < collection >做配置
多对多配置:使用< resultMap > + < collection >做配置

Mybatis注解开发

常用注解

这几年来注解开发越来越流行,Mybatis也可以使用注解开发方式,这样我们就可以减少编写Mapper
映射文件了。我们先围绕一些基本的CRUD来学习,再学习复杂映射多表操作。

@Insert:实现新增
@Update:实现更新
@Delete:实现删除
@Select:实现查询
@Result:实现结果集封装
@Results:可以与@Result 一起使用,封装多个结果集
@One:实现一对一结果集封装
@Many:实现一对多结果集封装

MyBatis的增删改查

我们完成简单的user表的增删改查的操作



修改MyBatis的核心配置文件,我们使用了注解替代的映射文件,所以我们只需要加载使用了注解的Mapper接口即可
或者指定扫描包含映射关系的接口所在的包也可以

MyBatis的注解实现复杂映射开发

实现复杂关系映射之前我们可以在映射文件中通过配置来实现,使用注解开发后,我们可以使用@Results注解,@Result注解,@One注解,@Many注解组合完成复杂关系的配置

一对一查询

  1. 一对一查询的模型
    用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户
    一对一查询的需求:查询一个订单,与此同时查询出该订单所属的用户
  2. 一对一查询的语句
    对应的sql语句:
    select * from orders;
    select * from user where id=查询出订单的uid;
    查询的结果如下:
  3. 创建Order和User实体
  4. 创建OrderMapper接口
  5. 使用注解配置Mapper
  6. 测试结果

一对多查询

  1. 一对多查询的模型
    用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户
    一对多查询的需求:查询一个用户,与此同时查询出该用户具有的订单
  2. 一对多查询的语句
    对应的sql语句:
    select * from user;
    select * from orders where uid=查询出用户的id;
    查询的结果如下:
  3. 修改User实体
  4. 创建UserMapper接口
  5. 使用注解配置Mapper
  6. 测试结果

多对多查询

  1. 多对多查询的模型
    用户表和角色表的关系为,一个用户有多个角色,一个角色被多个用户使用
    多对多查询的需求:查询用户同时查询出该用户的所有角色
  2. 多对多查询的语句
    对应的sql语句:
    select * from user;
    select * from role r,user_role ur where r.id=ur.role_id and ur.user_id=用户的id
    查询的结果如下:
  3. 创建Role实体,修改User实体
  4. 添加UserMapper接口方法
  5. 使用注解配置Mapper
  6. 测试结果

至此为全部的SSM笔记.


SSM
http://example.com/2021/07/15/SSM/
作者
Mercury
发布于
2021年7月15日
许可协议