关于SSM的基本总结

SSM

Spring5

Spring 有两个核心部分:IOC 和 Aop

(1)IOC:控制反转,把创建对象过程交给 Spring 进行管理

(2)AOP:面向切面,不修改源代码进行功能增强

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
在这里插入图片描述

IOC

1、什么是IOC

  1. 控制反转,把对象创建和对象之间的调用,交给Spring进行管理
  2. 使用IOC目的:为了耦合度降低。

2、IOC 底层原理 (1)xml 解析、工厂模式、反射

IOC(BeanFactory接口)

1、IOC 思想基于 IOC 容器完成,IOC 容器底层就是对象工厂

2、Spring 提供 IOC 容器实现两种方式:(两个接口)

(1)BeanFactory:IOC 容器基本实现,是 Spring 内部的使用接口,不提供开发人员进行使用

  • 加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象

(2)ApplicationContext:BeanFactory 接口的子接口,提供更多更强大的功能,一般由开发人 员进行使用

  • 加载配置文件时候就会把在配置文件对象进行创建

IOC 操作 Bean 管理(基于 xml 方式)

1、基于xml方式创建对象

​ (1)在 spring 配置文件中,使用 bean 标签,标签里面添加对应属性,就可以实现对象创建

​ (2)在 bean 标签有很多属性,介绍常用的属性 * id 属性:唯一标识 * class 属性:类全路径(包类路径)

​ (3)创建对象时候,默认也是执行无参数构造方法完成对象创建

2、基于 xml 方式注入属性

​ (1)DI:依赖注入,就是注入属性

3、第一种注入方式:使用 set 方法进行注入

​ (1)创建类,定义属性和对应的 set 方法

​ (2)在 spring 配置文件配置对象创建,配置属性注入

4、第二种注入方式:使用有参数构造进行注入

(1)创建类,定义属性,创建属性对应有参数构造方法 

IOC 操作 Bean 管理(FactoryBean)

1、Spring 有两种类型 bean,一种普通 bean,另外一种工厂 bean(FactoryBean)

2、普通 bean:在配置文件中定义 bean 类型就是返回类型

3、工厂 bean:在配置文件定义 bean 类型可以和返回类型不一样

​ 第一步 创建类,让这个类作为工厂 bean,实现接口 FactoryBean

​ 第二步 实现接口里面的方法,在实现的方法中定义返回的 bean 类型

IOC 操作 Bean 管理(bean 作用域)

1、在 Spring 里面,设置创建 bean 实例是单实例还是多实例

2、在 Spring 里面,默认情况下,bean 是单实例对象

scope 属性值 第一个值 默认值,singleton,表示是单实例对象 第二个值 prototype,表示是多实例对象

singleton 和 prototype 区别 第一 singleton 单实例,prototype 多实例 第二 设置 scope 值是 singleton 时候,加载 spring 配置文件时候就会创建单实例对象 设置 scope 值是 prototype 时候,不是在加载 spring 配置文件时候创建 对象,在调用 getBean 方法时候创建多实例对象

IOC 操作 Bean 管理(bean 生命周期)

1、生命周期 (1)从对象创建到对象销毁的过程

2、bean 生命周期

(1)通过构造器创建 bean 实例(无参数构造)

(2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)

(3)调用 bean 的初始化的方法(需要进行配置初始化的方法)

(4)bean 可以使用了(对象获取到了)

(5)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)

第一步 执行无参数构造创建bean实例
第二步 调用set方法设置属性值
在初始化之前执行的方法
第三步 执行初始化的方法
在初始化之后执行的方法
第四步 获取创建bean实例对象
com.atguigu.spring5.bean.Orders@5427c60c
第五步 执行销毁的方法


bean 的后置处理器,bean 生命周期有七步
(1)通过构造器创建 bean 实例(无参数构造)
(2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
(3)把 bean 实例传递 bean 后置处理器的方法 postProcessBeforeInitialization
(4)调用 bean 的初始化的方法(需要进行配置初始化的方法)
(5)把 bean 实例传递 bean 后置处理器的方法 postProcessAfterInitialization
(6)bean 可以使用了(对象获取到了)
(7)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)

public class Orders {
//无参数构造
public Orders() {System.out.println("第一步 执行无参数构造创建 bean 实例");}
private String oname
public void setOname(String oname) {
this.oname = oname;
System.out.println("第二步 调用 set 方法设置属性值");}
//创建执行的初始化的方法
public void initMethod() {
System.out.println("第三步 执行初始化的方法");}
//创建执行的销毁的方法
public void destroyMethod() {
System.out.println("第五步 执行销毁的方法");}
}


<bean id="orders" class="com.atguigu.spring5.bean.Orders" init-
method="initMethod" destroy-method="destroyMethod">
<property name="oname" value="手机"></property>
</bean>

IOC 操作 Bean 管理(xml 自动装配)

1、什么是自动装配

​ (1)根据指定装配规则(属性名称或者属性类型),Spring 自动将匹配的属性值进行注入

2、演示自动装配过程

​ (1)根据属性名称自动注入

​ (2)根据属性类型自动注入

实现自动装配 bean 标签属性 autowire,配置自动装配 autowire 属性常用两个值: byName 根据属性名称注入 ,注入值 bean 的 id 值和类属性名称一样

byType 根据属性类型注入

IOC 操作 Bean 管理(基于注解方式)

1、什么是注解

​ (1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值…) (2) 使用注解,注解作用在类上面,方法上面,属性上面

​ (3)使用注解目的:简化 xml 配置

2、Spring 针对 Bean 管理中创建对象提供注解

(1)@Component (2)@Service (3)@Controller (4)@Repository * 上面四个注解功能是一样的,都可以用来创建 bean 实例

3、基于注解方式实现对象创建

第一步 引入依赖

第二步 开启组件扫描

第三步 创建类,在类上面添加创建对象注解

4、开启组件扫描细节配置

5、基于注解方式实现属性注入

(1)@Autowired:根据属性类型进行自动装配

​ 第一步 把 service 和 dao 对象创建,在 service 和 dao 类添加创建对象注解

​ 第二步 在 service 注入 dao 对象,在 service 类添加 dao 类型属性,在属性上面使用注解

(2)@Qualifier:根据名称进行注入

这个@Qualifier 注解的使用,和上面@Autowired 一起使用

(3)@Resource:可以根据类型注入,可以根据名称注入 (默认根据名称注入)

(4)@Value:注入普通类型属性

6、完全注解开发

创建配置类,替代 xml 配置文件

@Configuration //作为配置类,替代 xml 配置文件

@ComponentScan(basePackages = {“com.atguigu”})

AOP

什么是 AOP

(1)面向切面编程(方面),利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得 业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

(2)通俗描述:不通过修改源代码方式,在主干功能里面添加新功能

(3)使用登录例子说明 AOP

AOP(底层原理)

1、AOP 底层使用动态代理

(1)有两种情况动态代理 第一种 有接口情况,使用 JDK 动态代理

1、使用 JDK 动态代理,使用 Proxy 类里面的方法创建代理对象

​ (1)调用 newProxyInstance 方法

    • static ObjectnewProxyInstance(ClassLoader loader, 类<?>[] interfaces, InvocationHandler h) 返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。

方法有三个参数:

第一参数,类加载器

第二参数,增强方法所在的类,这个类实现的接口,支持多个接口

第三参数,实现这个接口 InvocationHandler,创建代理对象,写增强的部分

  • 创建接口实现类代理对象,增强类的方法

第二种 没有接口情况,使用 CGLIB 动态代理

  • 创建子类的代理对象,增强类的方法

AOP(术语)

1、连接点:类里面哪些方法可以被增强,这些方法称为连接点

2、切入点:实际被真正增强的方法,称为切入点

3、通知(增强):

​ 1、实际增强的逻辑不符称为通知(增强)

​ 2、通知有多种类型

​ 前置通知、后置通知、环绕通知、异常通知、最终通知

4、切面:是动作,把通知应用到切入点过程

AOP操作(准备工作)

1、Spring 框架一般都是基于 AspectJ 实现 AOP 操作

​ (1)AspectJ 不是 Spring 组成部分,独立 AOP 框架,一般把 AspectJ 和 Spirng 框架一起使 用,进行 AOP 操作

2、基于 AspectJ 实现 AOP 操作

​ (1)基于 xml 配置文件实现

​ (2)基于注解方式实现(使用)

3、在项目工程里面引入 AOP 相关依赖

4、切入点表达式

​ (1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强

​ (2)语法结构:

  execution([权限修饰符] [返回类型] [类全路径] [方法名称]([参数列表]) )

举例 1:对 com.atguigu.dao.BookDao 类里面的 add 进行增强

execution(* com.atguigu.dao.BookDao.add(…))

举例 2:对 com.atguigu.dao.BookDao 类里面的所有的方法进行增强

execution(* com.atguigu.dao.BookDao.* (…))

举例 3:对 com.atguigu.dao 包里面所有类,类里面所有方法进行增强

execution(* com.atguigu.dao.. (…))

AOP 操作(AspectJ 注解)

1、创建类,在类里面定义方法

2、创建增强类(编写增强逻辑)

(1)在增强类里面,创建方法,让不同方法代表不同通知类型

3、进行通知的配置

(1)在 spring 配置文件中,开启注解扫描

(2)使用注解创建 对象,添加@Component

(3)在增强类上面添加注解 @Aspect

(4)在 spring 配置文件中开启生成代理对象

4、配置不同类型的通知

(1)在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置

//增强的类
@Component
@Aspect
//生成代理对象
public class UserProxy {
//前置通知
//@Before 注解表示作为前置通知
@Before(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
public void before() {
System.
out.println("before.........");
}
//后置通知(返回通知)
@AfterReturning(value = "execution(*
com.atguigu.spring5.aopanno.User.add(..))")
public void afterReturning() {
System.
out.println("afterReturning.........");
}
//最终通知
@After(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
public void after() {
System.
out.println("after.........");
}
//异常通知
@AfterThrowing(value = "execution(*
com.atguigu.spring5.aopanno.User.add(..))")
public void afterThrowing() {
System.
out.println("afterThrowing.........");
}
//环绕通知
@Around(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws
Throwable {
System.
out.println("环绕之前.........");
//被增强的方法执行
proceedingJoinPoint.proceed();
System.
out.println("环绕之后.........");
}
}

JdbcTemplate

什么是 JdbcTemplate

(1)Spring 框架对 JDBC 进行封装,使用 JdbcTemplate 方便实现对数据库操作

1.调用 JdbcTemplate 来进行增删改操作

jdbcTemplate.update(String sql, Object..args)
有两个参数
⚫ 第一个参数:sql 语句
⚫ 第二个参数:可变参数,设置 sql 语句值

2.JdbcTemplate 操作数据库(查询返回某个值)

1、查询表里面有多少条记录,返回是某个值

2、使用 JdbcTemplate 实现查询返回某个值代码

jdbcTemplate.queryForObject(String sql,Class<T> requiredType)
有两个参数
⚫ 第一个参数:sql 语句
⚫ 第二个参数:返回类型 Class

3.使用JdbcTemplate实现查询返回对象

jdbcTemplate.queryForObject(String sql,RowMapper<T> rowMapper,Object... args)
有三个参数
⚫ 第一个参数:sql 语句
⚫ 第二个参数:RowMapper 是接口,针对返回不同类型数据,使用这个接口里面实现类完成数据封装
⚫ 第三个参数:sql 语句值

4.调用 JdbcTemplate 方法实现查询返回集合

query(String sql,RowMapper<T> rowMapper,Object... args)
有三个参数
⚫ 第一个参数:sql 语句
⚫ 第二个参数:RowMapper 是接口,针对返回不同类型数据,使用这个接口里面实现类完成
数据封装
⚫ 第三个参数:sql 语句值

5.JdbcTemplate 实现批量添加操作

jdbcTemplate.batchUpdate(String sql, List<Object[]> batchArgs);
有两个参数
⚫ 第一个参数:sql 语句
⚫ 第二个参数:List 集合,添加多条记录数据

事务操作

事务是数据库操作最基本单元,逻辑上一组操作,要么都成功,如果有一个失败所有操 作都失败

事务特性(ACID)

原子性:一组操作,要么都成功,如果有一个失败所有操作都失败
一致性:事务提交前后的数据完整性和状态保持一致
隔离性:多事务操作过程中,相互之间不会产生影响
持久性:提交事务后,表中数据真正发生变化

(1) 原子性  要么都成功,如果有一个失败那么所有操作都失败  
(2)一致性  比如两个人之间进行转账,两个人的钱数加起来的和,转之前和转之后没都变。他们的余额总钱数转之前转之后保持一致
(3)隔离性  多个事务操作时候,它们之间不会产生影响。比如两个人都去操作同一条记录,这个过程中,他们之间不会产生影响  
(4)持久性  提交事务后,表中数据真正发生变化

(1) 原子性 要么都成功,如果有一个失败那么所有操作都失败 (2)一致性 比如两个人之间进行转账,两个人的钱数加起来的和,转之前和转之后没都变。他们的余额总钱数转之前转之后保持一致

(3)隔离性 多个事务操作时候,它们之间不会产生影响。比如两个人都去操作同一条记录,这个过程中,他们之间不会产生影响 (4)持久性 提交事务后,表中数据真正发生变化

事务操作过程

第一步:开启事务
第二步:进行业务操作
第三步:没有发生异常,提交事务
第四步:出现异常,事务回滚

事务操作(Spring 事务管理介绍)

1、事务添加到 JavaEE 三层结构里面 Service 层(业务逻辑层)

2、在 Spring 进行事务管理操作

​ (1)有两种方式:编程式事务管理和声明式事务管理(使用)

3、声明式事务管理

​ (1)基于注解方式(使用)

​ (2)基于 xml 配置文件方式

4、在 Spring 进行声明式事务管理,底层使用 AOP 原理

5、Spring 事务管理 API

在 service 类上面(或者 service 类里面方法上面)添加事务注解

​ (1)@Transactional,这个注解添加到类上面,也可以添加方法上面

​ (2)如果把这个注解添加类上面,这个类里面所有的方法都添加事务

​ (3)如果把这个注解添加方法上面,为这个方法添加事务

事务操作(声明式事务管理参数配置)

1、在 service 类上面添加注解@Transactional,在这个注解里面可以配置事务相关参数

2、propagation:事务传播行为

(1)多事务方法直接进行调用,这个过程中事务 是如何进行管理的

Spring框架事务传播方式有7种

传播属性描述
REQUIRED如果有事务在运行,当前的方法就在这个事务内运行,否则,就启动一个新的事务,并在自己的事务内运行
REQUIRED_NEW当前的方法必须启动新事务,并在它自己的事务内运行,如果有事务正在运行,应该将它挂起
SUPPORTS如果有事务在运行,当前的方法就在这个事务内运行,否则它可以不允许在事务中
NOT_SUPPORED当前的方法不应该运行在事务中,如果有运行的事务,将它挂起
MANDATORY当前的方法必须运行在事务内部,如果没有正在运行的事务,就抛出异常
NEVER当前的方法不应该运行在事务中,如果有运行的事务,就抛出异常
NESTED如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运行,否则,就启动一个新的事务,并在它自己的事务内运行。

3、ioslation:事务隔离级别

(1)事务有特性成为隔离性,多事务操作之间不会产生影响。不考虑隔离性产生很多问题

(2)有三个读问题:脏读、不可重复读、幻读

(3)脏读:一个未提交事务读取到另一个未提交事务的数据

(4)不可重复读:一个未提交事务读取到另一提交事务修改数据

(5)幻读:一个未提交事务读取到另一提交事务添加数据

(6)解决:通过设置事务隔离级别,解决读问题

脏读:读取未提交的数据,不可重复读:读取了已提交的数据,幻读:读取了增加的数据

4、timeout:超时时间

(1)事务需要在一定时间内进行提交,如果不提交进行回滚

(2)默认值是 -1 ,设置时间以秒单位进行计算

5、readOnly:是否只读

(1)读:查询操作,写:添加修改删除操作

(2)readOnly 默认值 false,表示可以查询,可以添加修改删除操作

(3)设置 readOnly 值是 true,设置成 true 之后,只能查询

6、rollbackFor:回滚

(1)设置出现哪些异常进行事务回滚

7、noRollbackFor:不回滚

(1)设置出现哪些异常不进行事务回滚

SpringMVC

MVC简介

MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分

M:Model,模型层,指工程中的JavaBean,作用是处理数据

JavaBean分为两类:

  • 一类称为实体类Bean:专门存储业务数据的,如 Student、User 等
  • 一类称为业务处理 Bean:指 Service 或 Dao 对象,专门用于处理业务逻辑和数据访问。

V:View,视图层,指工程中的html或jsp等页面,作用是与用户进行交互,展示数据

C:Controller,控制层,指工程中的servlet,作用是接收请求和响应浏览器

MVC的工作流程: 用户通过视图层发送请求到服务器,在服务器中请求被Controller接收,Controller 调用相应的Model层处理请求,处理完毕将结果返回到Controller,Controller再根据请求处理的结果 找到相应的View视图,渲染数据后最终响应给浏览器

注:三层架构分为表述层(或表示层)、业务逻辑层、数据访问层,表述层表示前台页面和后台 servlet

总结:浏览器发送请求,若请求地址符合前端控制器的url-pattern,该请求就会被前端控制器 DispatcherServlet处理。前端控制器会读取SpringMVC的核心配置文件,通过扫描组件找到控制器, 将请求地址和控制器中@RequestMapping注解的value属性值进行匹配,若匹配成功,该注解所标识的 控制器方法就是处理请求的方法。处理请求的方法需要返回一个字符串类型的视图名称,该视图名称会 被视图解析器解析,加上前缀和后缀组成视图的路径,通过Thymeleaf对视图进行渲染,最终转发到视 图所对应页面 。

SpringMVC的特点

  • Spring 家族原生产品,与 IOC 容器等基础设施无缝对接
  • 基于原生的Servlet,通过了功能强大的前端控制器DispatcherServlet,对请求和响应进行统一 处理
  • 表述层各细分领域需要解决的问题全方位覆盖,提供全面解决方案
  • 代码清新简洁,大幅度提升开发效率
  • 内部组件化程度高,可插拔式组件即插即用,想要什么功能配置相应组件即可
  • 性能卓著,尤其适合现代大型、超大型互联网项目要求

web.xml配置

注册SpringMVC的前端控制器DispatcherServlet

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <!--
        注册springMVC的前端控制器,对浏览器所发送的请求统一进行处理
        在此配置下,springMVC的配置文件具有默认的位置和名称
        默认的位置:WEB-INF
        默认的名称:<servlet-name>-servlet.xml
        若要为springMVC的配置文件设置自定义的位置和名称
        需要在servlet标签中添加init-param
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springMVC.xml</param-value>
        </init-param>
        load-on-startup:将前端控制器DispatcherServlet的初始化时间提前到服务器启动时
    -->
    <!--配置SpringMVC的前端控制器,对浏览器发送的请求进行统一处理-->
    <servlet>
        <servlet-name>springMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springMVC.xml</param-value>
        </init-param>
        <!--将前端控制器DispatcherServlet的初始化事件提前到服务器启动时-->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springMVC</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>

注: 标签中使用/和/*的区别: /所匹配的请求可以是/login或.html或.js或.css方式的请求路径,但是/不能匹配.jsp请求路径的请 求 因此就可以避免在访问jsp页面时,该请求被DispatcherServlet处理,从而找不到相应的页面 /*则能够匹配所有请求,例如在使用过滤器时,若需要对所有请求进行过滤,就需要使用/*的写 法 。

总结

浏览器发送请求,若请求地址符合前端控制器的url-pattern,该请求就会被前端控制器 DispatcherServlet处理。前端控制器会读取SpringMVC的核心配置文件,通过扫描组件找到控制器, 将请求地址和控制器中@RequestMapping注解的value属性值进行匹配,若匹配成功,该注解所标识的 控制器方法就是处理请求的方法。处理请求的方法需要返回一个字符串类型的视图名称,该视图名称会 被视图解析器解析,加上前缀和后缀组成视图的路径,通过Thymeleaf对视图进行渲染,最终转发到视 图所对应页面 

3、@RequestParam @RequestParam是将请求参数和控制器方法的形参创建映射关系

@RequestParam注解一共有三个属性:

value:指定为形参赋值的请求参数的参数名

required:设置是否必须传输此请求参数,默认值为true 若设置为true时,则当前请求必须传输value所指定的请求参数,若没有传输该请求参数,且没有设置 defaultValue属性,则页面报错400:Required String parameter ‘xxx’ is not present;若设置为 false,则当前请求不是必须传输value所指定的请求参数,若没有传输,则注解所标识的形参的值为 null defaultValue:不管required属性值为true或false,当value所指定的请求参数没有传输或传输的值 为""时,则使用默认值为形参赋值 4、

@RequestHeader :@RequestHeader是将请求头信息和控制器方法的形参创建映射关系 @RequestHeader注解一共有三个属性:value、required、defaultValue,用法同@RequestParam

5、@CookieValue: @CookieValue是将cookie数据和控制器方法的形参创建映射关系 @CookieValue注解一共有三个属性:value、required、defaultValue,用法同@RequestParam

SpringMVC的视图

SpringMVC中的视图是View接口,视图的作用渲染数据,将模型Model中的数据展示给用户 SpringMVC视图的种类很多,默认有转发视图和重定向视图 当工程引入jstl的依赖,转发视图会自动转换为JstlView 若使用的视图技术为Thymeleaf,在SpringMVC的配置文件中配置了Thymeleaf的视图解析器,由此视 图解析器解析之后所得到的是ThymeleafView

1、ThymeleafView

当控制器方法中所设置的视图名称没有任何前缀时,此时的视图名称会被SpringMVC配置文件中所配置 的视图解析器解析,视图名称拼接视图前缀和视图后缀所得到的最终路径,会通过转发的方式实现跳转

2、转发视图

SpringMVC中默认的转发视图是InternalResourceView

SpringMVC中创建转发视图的情况: 当控制器方法中所设置的视图名称以"forward:"为前缀时,创建InternalResourceView视图,此时的视 图名称不会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀"forward:"去掉,剩余部 分作为最终路径通过转发的方式实现跳转

例如"forward:/","forward:/employee"

3、重定向视图

SpringMVC中默认的重定向视图是RedirectView

当控制器方法中所设置的视图名称以"redirect:"为前缀时,创建RedirectView视图,此时的视图名称不 会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀"redirect:"去掉,剩余部分作为最 终路径通过重定向的方式实现跳转

例如"redirect:/","redirect:/employee"

4、视图控制器view-controller

拦截器

1、拦截器的配置

  • SpringMVC中的拦截器用于拦截控制器方法的执行
  • SpringMVC中的拦截器需要实现HandlerInterceptor
  • SpringMVC的拦截器必须在SpringMVC的配置文件中进行配置:

2、拦截器的三个抽象方法

SpringMVC中的拦截器有三个抽象方法:

  • preHandle:控制器方法执行之前执行preHandle(),其boolean类型的返回值表示是否拦截或放行,返 回true为放行,即调用控制器方法;返回false表示拦截,即不调用控制器方法
  • postHandle:控制器方法执行之后执行postHandle()
  • afterComplation:处理完视图和模型数据,渲染视图完毕之后执行afterComplation()

3、多个拦截器的执行顺序

a>若每个拦截器的preHandle()都返回true

此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件的配置顺序有关:

preHandle()会按照配置的顺序执行,而postHandle()和afterComplation()会按照配置的反序执行

b>若某个拦截器的preHandle()返回了false

preHandle()返回false和它之前的拦截器的preHandle()都会执行,postHandle()都不执行,返回false 的拦截器之前的拦截器的afterComplation()会执行

异常处理器

1、基于配置的异常处理

SpringMVC提供了一个处理控制器方法执行过程中所出现的异常的接口:

HandlerExceptionResolver HandlerExceptionResolver接口的实现类有:DefaultHandlerExceptionResolver和 SimpleMappingExceptionResolver SpringMVC提供了自定义的异常处理器SimpleMappingExceptionResolver,使用方式:

 <!--配置拦截器-->
    <mvc:interceptors>
        <ref bean="firstInterceptor"></ref>
        <ref bean="secondInterceptor"></ref>
        <!--<bean class="com.atguigu.mvc.interceptors.FirstInterceptor"></bean>-->
        <!--<ref bean="firstInterceptor"></ref>-->
        <!--
            <mvc:interceptor>
                <mvc:mapping path="/**"/>
                <mvc:exclude-mapping path="/"/>
                <ref bean="firstInterceptor"></ref>
            </mvc:interceptor>
        -->
    </mvc:interceptors>

    <!--配置异常处理-->
    <!--<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="exceptionMappings">
            <props>
                <prop key="java.lang.ArithmeticException">error</prop>
            </props>
        </property>
        &lt;!&ndash;设置将异常信息共享在请求域中的键&ndash;&gt;
        <property name="exceptionAttribute" value="ex"></property>
    </bean>-->

2、基于注解的异常处理

@ControllerAdvice
public class ExceptionController {

    @ExceptionHandler(value = {ArithmeticException.class, NullPointerException.class})
    public String testException(Exception ex, Model model){
        model.addAttribute("ex", ex);
        return "error";
    }

}

SpringMVC执行流程

1、SpringMVC常用组件

  • DispatcherServlet:前端控制器,不需要工程师开发,由框架提供 作用:统一处理请求和响应,整个流程控制的中心,由它调用其它组件处理用户的请求
  • HandlerMapping:处理器映射器,不需要工程师开发,由框架提供 作用:根据请求的url、method等信息查找Handler,即控制器方法
  • Handler:处理器,需要工程师开发 作用:在DispatcherServlet的控制下Handler对具体的用户请求进行处理
  • HandlerAdapter:处理器适配器,不需要工程师开发,由框架提供 作用:通过HandlerAdapter对处理器(控制器方法)进行执行
  • ViewResolver:视图解析器,不需要工程师开发,由框架提供 作用:进行视图解析,得到相应的视图,例如:ThymeleafView、InternalResourceView、 RedirectView
  • View:视图 作用:将模型数据通过页面展示给用户

2、DispatcherServlet初始化过程

DispatcherServlet 本质上是一个 Servlet,所以天然的遵循 Servlet 的生命周期。所以宏观上是 Servlet 生命周期来进行调度。

3、DispatcherServlet调用组件处理请求

4、SpringMVC的执行流程

(1) 用户向服务器发送请求,请求被SpringMVC 前端控制器 DispatcherServlet捕获。

( 2) DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI),判断请求URI对应的映射:

​ (a) 不存在 i. 再判断是否配置了mvc:default-servlet-handler ii. 如果没配置,则控制台报映射查找不到,客户端展示404错误

​ (b)存在则执行下面的流程

(3) 根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及 Handler对象对应的拦截器),最后以HandlerExecutionChain执行链对象的形式返回。

(4) DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。

(5) 如果成功获得HandlerAdapter,此时将开始执行拦截器的preHandler(…)方法【正向】

( 6) 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)方法,处理请求。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:

​ (a) HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定 的响应信息

​ (b) 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等

​ (c) 数据格式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等

​ (d) 数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中

(7) Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象。

(8) 此时将开始执行拦截器的postHandle(…)方法【逆向】。

(9) 根据返回的ModelAndView(此时会判断是否存在异常:如果存在异常,则执行 HandlerExceptionResolver进行异常处理)选择一个适合的ViewResolver进行视图解析,根据Model 和View,来渲染视图。

(10) 渲染视图完毕执行拦截器的afterCompletion(…)方法【逆向】。

(11) 将渲染结果返回给客户端。

Mybatis

MyBatis特性

1) MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架

2) MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集

3) MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录

4) MyBatis 是一个 半自动的ORM(Object Relation Mapping)框架

和其它持久化层技术对比

  • JDBC

    • SQL 夹杂在Java代码中耦合度高,导致硬编码内伤
    • 维护不易且实际开发需求中 SQL 有变化,频繁修改的情况多见
    • 代码冗长,开发效率低
  • Hibernate 和 JPA

    • 操作简便,开发效率高
    • 程序中的长难复杂 SQL 需要绕过框架
    • 内部自动生产的 SQL,不容易做特殊优化
    • 基于全映射的全自动框架,大量字段的 POJO 进行部分映射时比较困难。
    • 反射操作太多,导致数据库性能下降
  • MyBatis

    • 轻量级,性能出色
    • SQL 和 Java 编码分开,功能边界清晰。Java代码专注业务、SQL语句专注数据
    • 开发效率稍逊于HIbernate,但是完全能够接受

创建MyBatis的映射文件

相关概念:ORM(Object Relationship Mapping)对象关系映射。

  • 对象:Java的实体类对象
  • 关系:关系型数据库
  • 映射:二者之间的对应关系

SqlSession:代表Java程序和数据库之间的会话。(HttpSession是Java程序和浏览器之间的 会话) SqlSessionFactory:是“生产”SqlSession的“工厂”。 工厂模式:如果创建某一个对象,使用的过程基本固定,那么我们就可以把创建这个对象的 相关代码封装到一个“工厂类”中,以后都使用这个工厂类来“生产”我们需要的对象。

MyBatis面向接口编程的两个一致:
     1、映射文件的namespace要和mapper接口的全类名保持一致
     2、映射文件中SQL语句的id要和mapper接口中的方法名一致
<!--
        查询功能的标签必须设置resultType或resultMap
        resultType:设置默认的映射关系
        resultMap:设置自定义的映射关系
    -->
    <select id="getUserById" resultType="com.atguigu.mybatis.pojo.User">
        select * from t_user where id = 3
    </select>     
     
     

MyBatis的增删改查

4、查询一个实体类对象 5、查询集合 注意: 1、查询的标签select必须设置属性resultType或resultMap,用于设置实体类和数据库表的映射 关系

resultType:自动映射,用于属性名和表中字段名一致的情况 resultMap:自定义映射,用于一对多或多对一或字段名和属性名不一致的情况 2、当查询的数据为多条时,不能使用实体类作为返回值,只能使用集合,否则会抛出异常 TooManyResultsException;但是若查询的数据只有一条,可以使用实体类或集合作为返回值

MyBatis获取参数值的两种方式(重点)

MyBatis获取参数值的两种方式:${}和#{}
${}的本质就是字符串拼接,
#{}的本质就是占位符赋值
${}使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号;
但是#{}使用占位符赋值的方式拼接sql,此时为字符串类型或日期类型的字段进行赋值时,
可以自动添加单引号

1、单个字面量类型的参数
若mapper接口中的方法参数为单个的字面量类型
此时可以使用${}和#{}以任意的名称获取参数的值,注意${}需要手动加单引号
2、多个字面量类型的参数
若mapper接口中的方法参数为多个时
此时MyBatis会自动将这些参数放在一个map集合中,以arg0,arg1...为键,以参数为值;以
param1,param2...为键,以参数为值;因此只需要通过${}和#{}访问map集合的键就可以获取相对应的
值,注意${}需要手动加单引号
<!--User checkLogin(String username, String password);-->
   <select id="checkLogin" resultType="User">
       <!--select * from t_user where username = #{arg0} and password = #{arg1}-->
       select * from t_user where username = '${param1}' and password = '${param2}'
   </select>
3、map集合类型的参数
若mapper接口中的方法需要的参数为多个时,此时可以手动创建map集合,将这些数据放在map中
只需要通过${}和#{}访问map集合的键就可以获取相对应的值,注意${}需要手动加单引号
4、实体类类型的参数
若mapper接口中的方法参数为实体类对象时
此时可以使用${}和#{},通过访问实体类对象中的属性名获取属性值,注意${}需要手动加单引号
5、使用@Param标识参数
可以通过@Param注解标识mapper接口中的方法参数
此时,会将这些参数放在map集合中,以@Param注解的value属性值为键,以参数为值;以
param1,param2...为键,以参数为值;只需要通过${}和#{}访问map集合的键就可以获取相对应的值,
注意${}需要手动加单引号
<!--User checkLoginByParam(@Param("username") String username, @Param("password") String password);-->
   <select id="checkLoginByParam" resultType="User">
       select * from t_user where username = #{username} and password = #{password}
   </select>

MyBatis的各种查询功能

MyBatis的各种查询功能:
     1、若查询出的数据只有一条
      a>可以通过实体类对象接收
      b>可以通过list集合接收
      c>可以通过map集合接收
     结果:{password=123456, sex=男, id=3, age=23, email=12345@qq.com, username=admin}
     2、若查询出的数据有多条
      a>可以通过实体类类型的list集合接收
      b>可以通过map类型的list集合接收
      c>可以在mapper接口的方法上添加@MapKey注解,此时就可以将每条数据转换的map集合作为值,以某个字段的值作为键,放在同一个map集合中
      注意:一定不能通过实体类对象接收,此时会抛异常TooManyResultsException
/**
     * 查询所有用户信息为map集合
     */
    //List<Map<String, Object>> getAllUserToMap();
    @MapKey("id")
    Map<String, Object> getAllUserToMap();
    
    
       MyBatis中设置了默认的类型别名
      java.lang.Integer-->int,integer
      int-->_int,_integer
      Map-->map
      String-->string

<!--Integer getCount();-->
    <select id="getCount" resultType="_int">
        select count(*) from t_user
    </select>
注意:
count(*) 和 count(1)从结果上查询出来一致,
count(字段)查询字段不为null,如果为null,不计算在内


自定义映射resultMap


    
* 解决字段名和属性名不一致的情况:
     * a>为字段起别名,保持和属性名的一致
     * b>设置全局配置,将_自动映射为驼峰
     * <setting name="mapUnderscoreToCamelCase" value="true"/>
     * c>通过resultMap设置自定义的映射关系
 <!--
 resultMap:设置自定义映射关系
 id:唯一标识,不能重复
 type:设置映射关系中的实体类类型
 子标签:
 id:设置主键的映射关系
 result:设置普通字段的映射关系
 属性:
 property:设置映射关系中的属性名,必须是type属性所设置的实体类类型中的属性名
 column:设置映射关系中的字段名,必须是sql语句查询出的字段名
    -->
    <resultMap id="empResultMap" type="Emp">
        <id property="eid" column="eid"></id>
        <result property="empName" column="emp_name"></result>
        <result property="age" column="age"></result>
        <result property="sex" column="sex"></result>
        <result property="email" column="email"></result>
    </resultMap>
     *
     * 处理多对一的映射关系:
     * a>级联属性赋值
     * b>association
     * c>分步查询
     *
     * 处理一对多的映射关系
     * a>collection
     * b>分步查询    
    

动态SQL

动态SQL:
     * 1、if:根据标签中test属性所对应的表达式决定标签中的内容是否需要拼接到SQL中
     * 2、where:
     * 当where标签中有内容时,会自动生成where关键字,并且将内容前多余的and或or去掉
     * 当where标签中没有内容时,此时where标签没有任何效果
     * 注意:where标签不能将其中内容后面多余的and或or去掉
     * 3、trim:
     * 若标签中有内容时:
     * prefix|suffix:将trim标签中内容前面或后面添加指定内容
     * suffixOverrides|prefixOverrides:将trim标签中内容前面或后面去掉指定内容
     * 若标签中没有内容时,trim标签也没有任何效果
     * 4、choose、when、otherwise,相当于if...else if...else
     * when至少要有一个,otherwise最多只能有一个
     * 5、foreach
     * collection:设置需要循环的数组或集合
     * item:表示数组或集合中的每一个数据
     * separator:循环体之间的分割符
     * open:foreach标签所循环的所有内容的开始符
     * close:foreach标签所循环的所有内容的结束符
     * 6、sql标签
     * 设置SQL片段:<sql id="empColumns">eid,emp_name,age,sex,email</sql>
     * 引用SQL片段:<include refid="empColumns"></include>

Mybatis缓存

1、MyBatis的一级缓存

一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就 会从缓存中直接获取,
不会从数据库重新访问 使一级缓存失效的四种情况:
1) 不同的SqlSession对应不同的一级缓存 
2) 同一个SqlSession但是查询条件不同 
3) 同一个SqlSession两次查询期间执行了任何一次增删改操作 
4) 同一个SqlSession两次查询期间手动清空了缓存 

2、MyBatis的二级缓存

二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被 缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取 
二级缓存开启的条件: 
a>在核心配置文件中,设置全局配置属性cacheEnabled="true",默认为true,不需要设置 
b>在映射文件中设置标签<cache /> 
c>二级缓存必须在SqlSession关闭或提交之后有效
d>查询的数据所转换的实体类类型必须实现序列化的接口
使二级缓存失效的情况:
两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效

3、二级缓存的相关配置

在mapper配置文件中添加的cache标签可以设置一些属性:

  • eviction属性:缓存回收策略
  • LRU(Least Recently Used) – 最近最少使用的:移除最长时间不被使用的对象。
  • FIFO(First in First out) – 先进先出:按对象进入缓存的顺序来移除它们。
  • SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
  • WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。 默认的是 LRU。
  • flushInterval属性:刷新间隔,单位毫秒 默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
  • size属性:引用数目,正整数 代表缓存最多可以存储多少个对象,太大容易导致内存溢出
  • readOnly属性:只读,true/false
    • true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了 很重要的性能优势。
    • false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是 false。

4、MyBatis缓存查询的顺序

先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。
如果二级缓存没有命中,再查询一级缓存
如果一级缓存也没有命中,则查询数据库
SqlSession关闭之后,一级缓存中的数据会写入二级缓存

分页插件

limit index,pageSize
     * index:当前页的起始索引
     * pageSize:每页显示的条数
     * pageNum:当前页的页码
     * index=(pageNum-1)*pageSize
     *
     * 使用MyBatis的分页插件实现分页功能:
     * 1、需要在查询功能之前开启分页
     * PageHelper.startPage(int pageNum, int pageSize);
     * 2、在查询功能之后获取分页相关信息
     * PageInfo<Emp> page = new PageInfo<>(list, 5);
     * list表示分页数据
     * 5表示当前导航分页的数量


### 3、二级缓存的相关配置 

在mapper配置文件中添加的cache标签可以设置一些属性:

-  eviction属性:缓存回收策略 
- LRU(Least Recently Used) – 最近最少使用的:移除最长时间不被使用的对象。 
- FIFO(First in First out) – 先进先出:按对象进入缓存的顺序来移除它们。 
- SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。 
- WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。 默认的是 LRU。 
- flushInterval属性:刷新间隔,单位毫秒 默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新 
- size属性:引用数目,正整数 代表缓存最多可以存储多少个对象,太大容易导致内存溢出 
- readOnly属性:只读,true/false 
  - true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了 很重要的性能优势。 
  - false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是 false。 

### 4、MyBatis缓存查询的顺序 

先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。
如果二级缓存没有命中,再查询一级缓存
如果一级缓存也没有命中,则查询数据库
SqlSession关闭之后,一级缓存中的数据会写入二级缓存


## 分页插件 

limit index,pageSize
* index:当前页的起始索引
* pageSize:每页显示的条数
* pageNum:当前页的页码
* index=(pageNum-1)*pageSize
*
* 使用MyBatis的分页插件实现分页功能:
* 1、需要在查询功能之前开启分页
* PageHelper.startPage(int pageNum, int pageSize);
* 2、在查询功能之后获取分页相关信息
* PageInfo page = new PageInfo<>(list, 5);
* list表示分页数据
* 5表示当前导航分页的数量

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

墨殇离陌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值