@TOC

1. idea中使用lombok

  1. 导入依赖
  1. <dependency>
  2. <groupId>org.projectlombok</groupId>
  3. <artifactId>lombok</artifactId>
  4. <version>1.18.12</version>
  5. <scope>provided</scope>
  6. </dependency>
  1. idea添加lobbok插件,开启注解Setting -> Buid.. -> Comiler -> Annotation Processors -> Enable annotation processing
  2. 使用@Data

2. Mybatis的使用

  1. 导入依赖
  1. <!-- Mybatis核心 -->
  2. <dependency>
  3. <groupId>org.mybatis</groupId>
  4. <artifactId>mybatis</artifactId>
  5. <version>3.5.7</version>
  6. </dependency>
  7. <!-- MySQL驱动 -->
  8. <dependency>
  9. <groupId>mysql</groupId>
  10. <artifactId>mysql-connector-java</artifactId>
  11. <version>5.1.3</version>
  12. </dependency>
  1. 准备配置文件

建议命名为mybatis-config.xml,整个Spring之后这个文件省略。

注意:配置文件存放的位置是src/main/resources目录下。

  1. Mybatis映射文件

写SQL语句

注意:EmployeeMapper.xml所在的目录要和mybatis-config.xml中使用mapper标签配置的一致。

  1. 完成Mapper接口
    • 在SQL语句中,数据库表的表名不确定,需要外部动态传入,此时不能使用#{},因为数据库不允许表名位置使用问号占位符,此时只能使用${}。
    • 注意:由于Mapper接口中方法名是作为SQL语句标签的id,不能重复,所以Mapper接口中不能出现重名的方法不允许重载
  2. 数据输入
    有很多零散的参数需要传递,但是没有对应的实体类类型可以使用。使用@Param注解一个一个传入又太麻烦了。所以都封装到Map中。
  3. 数据输出

    1. <!-- 在全局范围内对Mybatis进行配置 -->
    2. <settings>
    3. <!-- 具体配置 -->
    4. <!-- 从org.apache.ibatis.session.Configuration类中可以查看能使用的配置项 -->
    5. <!-- 将mapUnderscoreToCamelCase属性配置为true,表示开启自动映射驼峰式命名规则 -->
    6. <!-- 规则要求数据库表字段命名方式:单词_单词 -->
    7. <!-- 规则要求Java实体类属性名命名方式:首字母小写的驼峰式命名 -->
    8. <setting name="mapUnderscoreToCamelCase" value="true"/>
    9. </settings>
  4. 自增组件

    1. SQL语句中加入属性
    2. useGeneratedKeys="true" keyProperty="empId"

3. log4j加入依赖

  1. <!-- log4j日志 -->
  2. <dependency>
  3. <groupId>log4j</groupId>
  4. <artifactId>log4j</artifactId>
  5. <version>1.2.17</version>
  6. </dependency>
  • log4j的配置文件

文件名固定:log4j.xml 或 log4j.properties

4.Mybatis关联外部文件

  • 创建jdbc.properties配置文件
    1. <properties resource="jdbc.properties"/>

5. 数据库表字段和实体类属性对应关系

  • 实体类型别名

    1. <!-- 配置类型的别名 -->
    2. <typeAliases>
    3. <!-- 声明了实体类所在的包之后,在Mapper配置文件中,只需要指定这个包下的简单类名即可 -->
    4. <package name="com.atguigu.mybatis.entity"/>
    5. </typeAliases>
  • 手动取别名

  • 驼峰式命名规则
  • resultMap
  1. <resultMap id="selectEmployeeByRMResultMap" type="com.atguigu.mybatis.entity.Employee">
  2. <!-- 使用id标签设置主键列和主键属性之间的对应关系 -->
  3. <!-- column属性用于指定字段名;property属性用于指定Java实体类属性名 -->
  4. <id column="emp_id" property="empId"/>
  5. <!-- 使用result标签设置普通字段和Java实体类属性之间的关系 -->
  6. <result column="emp_name" property="empName"/>
  7. <result column="emp_salary" property="empSalary"/>
  8. </resultMap>

6. 关联关系

  • 在“对一”关联关系中,我们的配置比较多,但是关键词就只有:associationjavaType
  • 在“对多”关联关系中,同样有很多配置,但是提炼出来最关键的就是:“collection”和“ofType

7. 分步查询

  1. <!-- orderList集合属性的映射关系,使用分步查询 -->
  2. <!-- 在collection标签中使用select属性指定要引用的SQL语句 -->
  3. <!-- select属性值的格式是:Mapper配置文件的名称空间.SQL语句id -->
  4. <!-- column属性:指定Customer和Order之间建立关联关系时所依赖的字段 -->
  5. <collection
  6. property="orderList"
  7. select="com.atguigu.mybatis.mapper.CustomerMapper.selectOrderList"
  8. column="customer_id"/>

8. MyBatis懒加载

  1. <!-- Mybatis全局配置 -->
  2. <settings>
  3. <!-- 开启延迟加载功能 -->
  4. <setting name="lazyLoadingEnabled" value="true"/>
  5. </settings>

9. 动态SQL

  1. if和where标签
    有选择的加入SQL片段
  2. set标签
    更新一部分字段
  3. trim标签
    使用trim标签控制条件部分两端是否包含某些字符
  4. choose/when/otherwise
    在多个分支条件中,仅执行一个。
  5. foreach标签
    批量
  6. sql标签
    抽取重复的SQL片段,可以引用

10. 一级缓存失效的情况

  • 不是同一个SqlSession
  • 同一个SqlSession但是查询条件发生了变化
  • 同一个SqlSession两次查询期间执行了任何一次增删改操作
  • 同一个SqlSession两次查询期间手动清空了缓存
  • 同一个SqlSession两次查询期间提交了事务

11. 二级缓存

  • 配置文件加入cache标签
  1. <mapper namespace="com.atguigu.mybatis.EmployeeMapper">
  2. <!-- 加入cache标签启用二级缓存功能 -->
  3. <cache/>
  • 实体类支持序列化
  1. public class Employee implements Serializable {}
  • 日志中打印的Cache Hit Ratio叫做缓存命中率

结论:SqlSession关闭的时候,一级缓存中的内容会被存入二级缓存

12.逆向工程

先创建数据库表,框架反向生成实体类、Mapper接口、Mapper配置文件

13.bean之xml

1. 根据id获取bean

  • 导入依赖
  1. <!-- 基于Maven依赖传递性,导入spring-context依赖即可导入当前所需所有jar包 -->
  2. <dependency>
  3. <groupId>org.springframework</groupId>
  4. <artifactId>spring-context</artifactId>
  5. <version>5.3.1</version>
  6. </dependency>
  • 配置文件
  1. <!-- 实验一 [重要]创建bean -->
  2. <bean id="happyComponent" class="com.atguigu.ioc.component.HappyComponent"/>
  • java
  1. // 创建 IOC 容器对象,为便于其他实验方法使用声明为成员变量
  2. private ApplicationContext iocContainer = new ClassPathXmlApplicationContext("applicationContext.xml");
  1. HappyComponent happyComponent = (HappyComponent) iocContainer.getBean("happyComponent");

2. 根据类型获取bean

类型要唯一

  1. HappyComponent component = iocContainer.getBean(HappyComponent.class);

3. 属性赋值之setter注入

  1. <property name="componentName" value="veryHappy"/>

4. 属性赋值之引用外部bean

  1. <property name="happyMachine" ref="happyMachine"/>

5. 属性赋值之内部bean

  1. <property name="happyMachine">
  2. <!-- 在一个 bean 中再声明一个 bean 就是内部 bean -->
  3. <!-- 内部 bean 可以直接用于给属性赋值,可以省略 id 属性 -->
  4. <bean class="com.atguigu.ioc.component.HappyMachine">
  5. <property name="machineName" value="makeHappy"/>
  6. </bean>
  7. </property>

6. 引入外部属性文件

导依赖

  1. <!-- MySQL驱动 -->
  2. <dependency>
  3. <groupId>mysql</groupId>
  4. <artifactId>mysql-connector-java</artifactId>
  5. <version>5.1.3</version>
  6. </dependency>
  7. <!-- 数据源 -->
  8. <dependency>
  9. <groupId>com.alibaba</groupId>
  10. <artifactId>druid</artifactId>
  11. <version>1.0.31</version>
  12. </dependency>

属性文件

  1. jdbc.user=root
  2. jdbc.password=atguigu
  3. jdbc.url=jdbc:mysql://192.168.198.100:3306/mybatis-example
  4. jdbc.driver=com.mysql.jdbc.Driver

引入外部属性文件

  1. <!-- 引入外部属性文件 -->
  2. <context:property-placeholder location="classpath:jdbc.properties"/>

属性赋值

  1. <!-- 实验六 [重要]给bean的属性赋值:引入外部属性文件 -->
  2. <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
  3. <property name="url" value="${jdbc.url}"/>
  4. <property name="driverClassName" value="${jdbc.driver}"/>
  5. <property name="username" value="${jdbc.user}"/>
  6. <property name="password" value="${jdbc.password}"/>
  7. </bean>

7. 级联属性

  1. <bean id="happyComponent6" class="com.atguigu.ioc.component.HappyComponent">
  2. <!-- 装配关联对象 -->
  3. <property name="happyMachine" ref="happyMachine2"/>
  4. <!-- 对HappyComponent来说,happyMachine的machineName属性就是级联属性 -->
  5. <property name="happyMachine.machineName" value="cascadeValue"/>
  6. </bean>

8. 属性赋值之构造器

  1. <!-- 实验八 给bean的属性赋值:构造器注入 -->
  2. <bean id="happyTeam" class="com.atguigu.ioc.component.HappyTeam">
  3. <constructor-arg value="happyCorps"/>
  4. <constructor-arg value="10"/>
  5. <constructor-arg value="1000.55"/>
  6. </bean>

9. 特殊值

  1. <property name="commonValue">
  2. <!-- null标签:将一个属性值明确设置为null -->
  3. <null/>
  4. </property>
  1. <!-- 实验九 给bean的属性赋值:特殊值处理 -->
  2. <bean id="propValue" class="com.atguigu.ioc.component.PropValue">
  3. <property name="expression">
  4. <!-- 解决方案二:使用CDATA节 -->
  5. <!-- CDATA中的C代表Character,是文本、字符的含义,CDATA就表示纯文本数据 -->
  6. <!-- XML解析器看到CDATA节就知道这里是纯文本,就不会当作XML标签或属性来解析 -->
  7. <!-- 所以CDATA节中写什么符号都随意 -->
  8. <value><![CDATA[a < b]]></value>
  9. </property>
  10. </bean>

10. P名称空间

  1. <!-- 实验十 给bean的属性赋值:使用p名称空间 -->
  2. <bean id="happyMachine3"
  3. class="com.atguigu.ioc.component.HappyMachine"
  4. p:machineName="goodMachine"
  5. />

11.集合属性

  1. <property name="memberList">
  2. <list>
  3. <value>member01</value>
  4. <value>member02</value>
  5. <value>member03</value>
  6. </list>
  7. </property>
  8. <!-- 使用set标签也能实现相同效果,只是附带了去重功能 -->
  9. <!-- array也同样兼容 -->
  10. <!-- 给Map类型的属性赋值 -->
  11. <!-- 也可以使用props标签 -->

12. 自动装配

所谓自动装配就是一个组件需要其他组件时,由 IOC 容器负责找到那个需要的组件,并装配进去。

  1. <!-- 实验十二 自动装配 -->
  2. <bean id="happyService3" class="com.atguigu.ioc.component.HappyService"/>
  3. <bean id="happyService2" class="com.atguigu.ioc.component.HappyService"/>
  4. <!-- 使用bean标签的autowire属性设置自动装配效果 -->
  5. <!-- byType表示根据类型进行装配,此时如果类型匹配的bean不止一个,那么会抛NoUniqueBeanDefinitionException -->
  6. <!-- byName表示根据bean的id进行匹配。而bean的id是根据需要装配组件的属性的属性名来确定的 -->
  7. <bean id="happyController"
  8. class="com.atguigu.ioc.component.HappyController"
  9. autowire="byName"
  10. >
  11. <!-- 手动装配:在property标签中使用ref属性明确指定要装配的bean -->
  12. <!--<property name="happyService" ref="happyService"/>-->
  13. </bean>

13. 集合类型的bean

  1. <!-- 实验十一 给bean的属性赋值:集合属性 -->
  2. <util:list id="machineList">
  3. <bean class="com.atguigu.ioc.component.HappyMachine">
  4. <property name="machineName" value="machineOne"/>
  5. </bean>
  6. <bean class="com.atguigu.ioc.component.HappyMachine">
  7. <property name="machineName" value="machineTwo"/>
  8. </bean>
  9. <bean class="com.atguigu.ioc.component.HappyMachine">
  10. <property name="machineName" value="machineThree"/>
  11. </bean>
  12. </util:list>

14. FactoryBean机制

FactoryBean是Spring提供的一种整合第三方框架的常用机制。和普通的bean不同,配置一个FactoryBean类型的bean,在获取bean的时候得到的并不是class属性中配置的这个类的对象,而是getObject()方法的返回值。通过这种机制,Spring可以帮我们把复杂组件创建的详细过程和繁琐细节都屏蔽起来,只把最简洁的使用界面展示给我们。

将来我们整合Mybatis时,Spring就是通过FactoryBean机制来帮我们创建SqlSessionFactory对象的。

  1. <!-- 实验十四 FactoryBean机制 -->
  2. <!-- 这个bean标签中class属性指定的是HappyFactoryBean,但是将来从这里获取的bean是HappyMachine对象 -->
  3. <bean id="happyMachine3" class="com.atguigu.ioc.factory.HappyFactoryBean">
  4. <!-- property标签仍然可以用来通过setXxx()方法给属性赋值 -->
  5. <property name="machineName" value="iceCreamMachine"/>
  6. </bean>

15. bean的作用域

  1. <!-- 实验十五 bean的作用域 -->
  2. <!-- scope属性:取值singleton(默认值),bean在IOC容器中只有一个实例,IOC容器初始化时创建对象 -->
  3. <!-- scope属性:取值prototype,bean在IOC容器中可以有多个实例,getBean()时创建对象 -->
  4. <bean id="happyMachine4" scope="prototype" class="com.atguigu.ioc.component.HappyMachine">
  5. <property name="machineName" value="iceCreamMachine"/>
  6. </bean>

16. bean的生命周期

  • 创建初始化方法和销毁方法
  1. public void happyInitMethod() {
  2. System.out.println("HappyComponent初始化");
  3. }
  4. public void happyDestroyMethod() {
  5. System.out.println("HappyComponent销毁");
  6. }
  • 配置bean时指定初始化和销毁方法
  1. <!-- 实验十六 bean的生命周期 -->
  2. <!-- 使用init-method属性指定初始化方法 -->
  3. <!-- 使用destroy-method属性指定销毁方法 -->
  4. <bean id="happyComponent"
  5. class="com.atguigu.ioc.component.HappyComponent"
  6. init-method="happyInitMethod"
  7. destroy-method="happyDestroyMethod"
  8. >
  9. <property name="happyName" value="uuu"/>
  10. </bean>

14. 注解管理bean

  • 导入spring依赖
  1. <!-- 基于Maven依赖传递性,导入spring-context依赖即可导入当前所需所有jar包 -->
  2. <dependency>
  3. <groupId>org.springframework</groupId>
  4. <artifactId>spring-context</artifactId>
  5. <version>5.3.1</version>
  6. </dependency>
  • 标记的四个注解没有本质区别
  1. 使用@Component注解标记的普通组件
  2. 使用@Controller注解标记的控制器组件
  3. 使用@Service注解标记的业务逻辑组件
  4. 使用@Repository注解标记的持久化层组件
  • 扫描
  1. <!-- 配置自动扫描的包 -->
  2. <!-- 最基本的扫描方式 -->
  3. <context:component-scan base-package="com.atguigu.ioc.component"/>
  1. <!-- 情况二:在指定扫描包的基础上指定匹配模式 -->
  2. <context:component-scan
  3. base-package="com.atguigu.ioc.component"
  4. resource-pattern="Soldier*.class"/>
  1. <!-- 情况三:指定不扫描的组件 -->
  2. <context:component-scan base-package="com.atguigu.ioc.component">
  3. <!-- context:exclude-filter标签:指定排除规则 -->
  4. <!-- type属性:指定根据什么来进行排除,annotation取值表示根据注解来排除 -->
  5. <!-- expression属性:指定排除规则的表达式,对于注解来说指定全类名即可 -->
  6. <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
  7. </context:component-scan>
  1. <!-- 情况四:仅扫描指定的组件 -->
  2. <!-- 仅扫描 = 关闭默认规则 + 追加规则 -->
  3. <!-- use-default-filters属性:取值false表示关闭默认扫描规则 -->
  4. <context:component-scan base-package="com.atguigu.ioc.component" use-default-filters="false">
  5. <!-- context:include-filter标签:指定在原有扫描规则的基础上追加的规则 -->
  6. <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
  7. </context:component-scan>

1. 组件的beanName

在我们使用XML方式管理bean的时候,每个bean都有一个唯一标识,便于在其他地方引用。现在使用注解后,每个组件仍然应该有一个唯一标识。

①默认情况

类名首字母小写就是bean的id。例如:SoldierController类对应的bean的id就是soldierController。

②使用value属性指定

  1. @Controller(value = "tianDog")
  2. public class SoldierController {
  3. }
  1. //当注解中只设置一个属性时,value属性的属性名可以省略:
  2. @Service("smallDog")
  3. public class SoldierService {
  4. }

2. 完全注解开发

①创建配置类

使用@Configuration注解将一个普通的类标记为Spring的配置类。

②根据配置类创建IOC容器对象

  1. // ClassPathXmlApplicationContext根据XML配置文件创建IOC容器对象

③配置bean

  1. // @Bean注解相当于XML配置文件中的bean标签
  2. // @Bean注解标记的方法的返回值会被放入IOC容器

3. 整合junit4

  • 好处1:不需要自己创建IOC容器对象了
  • 好处2:任何需要的bean都可以在测试类中直接享受自动装配
  • 导入依赖
  1. <!-- Spring的测试包 -->
  2. <dependency>
  3. <groupId>org.springframework</groupId>
  4. <artifactId>spring-test</artifactId>
  5. <version>5.3.1</version>
  6. </dependency>
  • 测试类的注解
  1. // junit的@RunWith注解:指定Spring为Junit提供的运行器
  2. @RunWith(SpringJUnit4ClassRunner.class)
  3. // Spring的@ContextConfiguration指定Spring配置文件的位置
  4. @ContextConfiguration(value = {"classpath:applicationContext.xml"})

15. AOP(Aspect Oriented Programming面向切面编程)

  • AOP的核心套路
    1. 前置通知(然后再调用被代理对象的目标方法)
    2. 返回通知
    3. 异常处理
    4. 后置通知
    5. 环绕通知(包括前面四种通知的所有功能。)

通知的执行顺序

  • Spring版本5.3.x以前:
    • 前置通知
    • 目标操作
    • 后置通知
    • 返回通知或异常通知
  • Spring版本5.3.x以后:
    • 前置通知
    • 目标操作
    • 返回通知或异常通知
    • 后置通知
  • AOP术语
    1. 横切关注点(如权限认证、日志、事务、异常等)
    2. 通知advice(横切关注点上要做的事情,也被称为增强)
    3. 连接点joinpoint(纯逻辑概念,指被拦截到的点)
    4. 切入点pointcut(定位连接点的方式,是一个表达式)
    5. 切面aspect(切入点和通知的结合,是一个类)
    6. 目标target(指被代理的目标对象)
    7. 代理proxy(向目标对象应用通知之后创建的代理对象)
    8. 织入weave(指把通知应用到目标上,生成代理对象的过程,spring采用在运行期织入)

基于注解的AOP的初步实现

  • 加入依赖
  1. <!-- spring-aspects会帮我们传递过来aspectjweaver -->
  2. <dependency>
  3. <groupId>org.springframework</groupId>
  4. <artifactId>spring-aspects</artifactId>
  5. <version>5.3.1</version>
  6. </dependency>
  • 创建切面类
  1. // @Aspect表示这个类是一个切面类
  2. @Aspect
  3. // @Component注解保证这个切面类能够放入IOC容器
  4. @Component
  5. public class LogAspect {
  6. // @Before注解:声明当前方法是前置通知方法
  7. // value属性:指定切入点表达式,由切入点表达式控制当前通知方法要作用在哪一个目标方法上
  8. @Before(value = "execution(public int com.atguigu.aop.api.Calculator.add(int,int))")
  9. public void printLogBeforeCore() {
  10. System.out.println("[AOP前置通知] 方法开始了");
  11. }
  12. @AfterReturning(value = "execution(public int com.atguigu.aop.api.Calculator.add(int,int))")
  13. public void printLogAfterSuccess() {
  14. System.out.println("[AOP返回通知] 方法成功返回了");
  15. }
  16. @AfterThrowing(value = "execution(public int com.atguigu.aop.api.Calculator.add(int,int))")
  17. public void printLogAfterException() {
  18. System.out.println("[AOP异常通知] 方法抛异常了");
  19. }
  20. @After(value = "execution(public int com.atguigu.aop.api.Calculator.add(int,int))")
  21. public void printLogFinallyEnd() {
  22. System.out.println("[AOP后置通知] 方法最终结束了");
  23. }
  24. }
  • spring配置文件
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
  6. <!-- 开启基于注解的AOP功能 -->
  7. <aop:aspectj-autoproxy/>
  8. <!-- 配置自动扫描的包 -->
  9. <context:component-scan base-package="com.atguigu.aop"/>
  10. </beans>

切入点表达式

  1. @Component
  2. public class AtguiguPointCut {
  3. @Pointcut(value = "execution(public int *..Calculator.sub(int,int))")
  4. public void atguiguGlobalPointCut(){}
  5. @Pointcut(value = "execution(public int *..Calculator.add(int,int))")
  6. public void atguiguSecondPointCut(){}
  7. @Pointcut(value = "execution(* *..*Service.*(..))")
  8. public void transactionPointCut(){}
  9. }

切面优先级@Order(较小的数):优先级高

各个通知获取细节信息

  1. // @Before注解标记前置通知方法
  2. // value属性:切入点表达式,告诉Spring当前通知方法要套用到哪个目标方法上
  3. // 在前置通知方法形参位置声明一个JoinPoint类型的参数,Spring就会将这个对象传入
  4. // 根据JoinPoint对象就可以获取目标方法名称、实际参数列表
  5. @Before(value = "execution(public int com.atguigu.aop.api.Calculator.add(int,int))")
  6. public void printLogBeforeCore(JoinPoint joinPoint) {
  7. // 1.通过JoinPoint对象获取目标方法签名对象
  8. // 方法的签名:一个方法的全部声明信息
  9. Signature signature = joinPoint.getSignature();
  10. // 2.通过方法的签名对象获取目标方法的详细信息
  11. String methodName = signature.getName();
  12. System.out.println("methodName = " + methodName);
  13. int modifiers = signature.getModifiers();
  14. System.out.println("modifiers = " + modifiers);
  15. String declaringTypeName = signature.getDeclaringTypeName();
  16. System.out.println("declaringTypeName = " + declaringTypeName);
  17. // 3.通过JoinPoint对象获取外界调用目标方法时传入的实参列表
  18. Object[] args = joinPoint.getArgs();
  19. // 4.由于数组直接打印看不到具体数据,所以转换为List集合
  20. List<Object> argList = Arrays.asList(args);
  21. System.out.println("[AOP前置通知] " + methodName + "方法开始了,参数列表:" + argList);
  22. }

16. 声明式事务

  1. PlatformTransactionManager 接口本身没有变化,它继承了TransactionManager。
  2. TransactionManager接口中什么都没有,但是它还是有存在的意义——定义一个技术体系。
  3. 我们现在要使用的事务管理器是org.springframework.jdbc.datasource.DataSourceTransactionManager,将来整合 Mybatis 用的也是这个类。它继承PlatformTransactionManager
  4. DataSourceTransactionManager类中的主要方法:
  • doBegin():开启事务
  • doSuspend():挂起事务
  • doResume():恢复挂起的事务
  • doCommit():提交事务
  • doRollback():回滚事务

使用注解基本实现

  • 加入依赖
  1. dependencies>
  2. <!-- 基于Maven依赖传递性,导入spring-context依赖即可导入当前所需所有jar包 -->
  3. <dependency>
  4. <groupId>org.springframework</groupId>
  5. <artifactId>spring-context</artifactId>
  6. <version>5.3.1</version>
  7. </dependency>
  8. <!-- Spring 持久化层支持jar包 -->
  9. <!-- Spring 在执行持久化层操作、与持久化层技术进行整合过程中,需要使用orm、jdbc、tx三个jar包 -->
  10. <!-- 导入 orm 包就可以通过 Maven 的依赖传递性把其他两个也导入 -->
  11. <dependency>
  12. <groupId>org.springframework</groupId>
  13. <artifactId>spring-orm</artifactId>
  14. <version>5.3.1</version>
  15. </dependency>
  16. <!-- Spring 测试相关 -->
  17. <dependency>
  18. <groupId>org.springframework</groupId>
  19. <artifactId>spring-test</artifactId>
  20. <version>5.3.1</version>
  21. </dependency>
  22. <!-- junit测试 -->
  23. <dependency>
  24. <groupId>junit</groupId>
  25. <artifactId>junit</artifactId>
  26. <version>4.12</version>
  27. <scope>test</scope>
  28. </dependency>
  29. <!-- MySQL驱动 -->
  30. <dependency>
  31. <groupId>mysql</groupId>
  32. <artifactId>mysql-connector-java</artifactId>
  33. <version>5.1.3</version>
  34. </dependency>
  35. <!-- 数据源 -->
  36. <dependency>
  37. <groupId>com.alibaba</groupId>
  38. <artifactId>druid</artifactId>
  39. <version>1.0.31</version>
  40. </dependency>
  41. </dependencies>
  • 外部属性文件
  1. atguigu.url=jdbc:mysql://192.168.198.100:3306/mybatis-example
  2. atguigu.driver=com.mysql.jdbc.Driver
  3. atguigu.username=root
  4. atguigu.password=atguigu
  • spring配置文件
  1. <!-- 配置自动扫描的包 -->
  2. <context:component-scan base-package="com.atguigu.tx"/>
  3. <!-- 导入外部属性文件 -->
  4. <context:property-placeholder location="classpath:jdbc.properties" />
  5. <!-- 配置数据源 -->
  6. <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
  7. <property name="url" value="${atguigu.url}"/>
  8. <property name="driverClassName" value="${atguigu.driver}"/>
  9. <property name="username" value="${atguigu.username}"/>
  10. <property name="password" value="${atguigu.password}"/>
  11. </bean>
  12. <!-- 配置 JdbcTemplate -->
  13. <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
  14. <!-- 装配数据源 -->
  15. <property name="dataSource" ref="druidDataSource"/>
  16. </bean>
  • 配置事务
  1. <!-- 配置事务管理器 -->
  2. <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  3. <!-- 事务管理器的bean只需要装配数据源,其他属性保持默认值即可 -->
  4. <property name="dataSource" ref="druidDataSource"/>
  5. </bean>
  • 开启事务
  1. <!-- 开启基于注解的声明式事务功能 -->
  2. <!-- 使用transaction-manager属性指定当前使用是事务管理器的bean -->
  3. <!-- transaction-manager属性的默认值是transactionManager,如果事务管理器bean的id正好就是这个默认值,则可以省略这个属性 -->
  4. <tx:annotation-driven transaction-manager="transactionManager"/>
  • 使用注解
  1. @Transactional
  1. // readOnly = true把当前事务设置为只读
  2. @Transactional(readOnly = true)
  1. @Transactional(readOnly = false, timeout = 3)
  1. @Transactional(rollbackFor = Exception.class)
  1. @Transactional(isolation = Isolation.READ_COMMITTED, readOnly = false)

使用XML

  • 只需要一个依赖
  1. <dependency>
  2. <groupId>org.springframework</groupId>
  3. <artifactId>spring-aspects</artifactId>
  4. <version>5.3.1</version>
  5. </dependency>
  • spring配置文件
  1. <aop:config>
  2. <!-- 配置切入点表达式,将事务功能定位到具体方法上 -->
  3. <aop:pointcut id="txPoincut" expression="execution(* *..*Service.*(..))"/>
  4. <!-- 将事务通知和切入点表达式关联起来 -->
  5. <aop:advisor advice-ref="txAdvice" pointcut-ref="txPoincut"/>
  6. </aop:config>
  7. <!-- tx:advice标签:配置事务通知 -->
  8. <!-- id属性:给事务通知标签设置唯一标识,便于引用 -->
  9. <!-- transaction-manager属性:关联事务管理器 -->
  10. <tx:advice id="txAdvice" transaction-manager="transactionManager">
  11. <tx:attributes>
  12. <!-- tx:method标签:配置具体的事务方法 -->
  13. <!-- name属性:指定方法名,可以使用星号代表多个字符 -->
  14. <tx:method name="get*" read-only="true"/>
  15. <tx:method name="query*" read-only="true"/>
  16. <tx:method name="find*" read-only="true"/>
  17. <!-- read-only属性:设置只读属性 -->
  18. <!-- rollback-for属性:设置回滚的异常 -->
  19. <!-- no-rollback-for属性:设置不回滚的异常 -->
  20. <!-- isolation属性:设置事务的隔离级别 -->
  21. <!-- timeout属性:设置事务的超时属性 -->
  22. <!-- propagation属性:设置事务的传播行为 -->
  23. <tx:method name="save*" read-only="false" rollback-for="java.lang.Exception" propagation="REQUIRES_NEW"/>
  24. <tx:method name="update*" read-only="false" rollback-for="java.lang.Exception" propagation="REQUIRES_NEW"/>
  25. <tx:method name="delete*" read-only="false" rollback-for="java.lang.Exception" propagation="REQUIRES_NEW"/>
  26. </tx:attributes>
  27. </tx:advice>

17. @RequestMapping

该注解的作用就是将请求的 URL 地址和处理请求的方式关联起来,建立映射关系。SpringMVC 接收到指定的请求,就会来找到在映射关系中对应的方法来处理这个请求。

  1. @RequestMapping("/user/login")
  2. @RequestMapping("/fruit/*")
  1. @RequestMapping(value = "/emp",
  2. method = RequestMethod.GET)
  1. @GetMapping
  2. @PostMapping
  3. @PUTMapping
  4. @DELETEMapping
  5. ...
  1. // 使用 @RequestHeader 注解获取请求消息头信息
  2. // name 或 value 属性:指定请求消息头名称
  3. // defaultValue 属性:设置默认值
  4. @RequestHeader
  5. // 使用 @CookieValue 注解获取指定名称的 Cookie 数据
  6. // name 或 value 属性:指定Cookie 名称
  7. // defaultValue 属性:设置默认值
  8. @CookieValue

获取请求参数

  1. @RequestMapping("/param/one/name/one/value")
  2. public String oneNameOneValue(
  3. // 使用@RequestParam注解标记handler方法的形参
  4. // SpringMVC 会将获取到的请求参数从形参位置给我们传进来
  5. @RequestParam("userName") String userName
  6. )

18. RESTFul

REST,即Representational State Transfer的缩写,可以翻译我为“表示性的状态转移”,“表现层资源的状态转移”

如果一个架构符合REST原则,就称它为RESTful架构。

REST 风格的好处

①含蓄,安全

②风格统一

③无状态

④严谨,规范

⑤简洁,优雅

19.PUT&DELETE请求

  • web.xml
  • 两个 Filter 并存,一定要让 CharacterEncodingFilter 先执行
  1. <filter>
  2. <filter-name>hiddenHttpMethodFilter</filter-name>
  3. <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
  4. </filter>
  5. <filter-mapping>
  6. <filter-name>hiddenHttpMethodFilter</filter-name>
  7. <url-pattern>/*</url-pattern>
  8. </filter-mapping>
  • 表单
  • 要点1:原请求方式必须是 post
  • 要点2:新的请求方式名称通过请求参数发送
  • 要点3:请求参数名称必须是_method
  • 要点4:请求参数的值就是要改成的请求方式

20. 拦截器

  • 创建拦截器类,实现接口
  1. public class Process01Interceptor implements HandlerInterceptor {
  2. Logger logger = LoggerFactory.getLogger(this.getClass());
  3. // 在处理请求的目标 handler 方法前执行
  4. @Override
  5. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  6. logger.debug("Process01Interceptor preHandle方法");
  7. // 返回true:放行
  8. // 返回false:不放行
  9. return true;
  10. }
  11. // 在目标 handler 方法之后,渲染视图之前
  12. @Override
  13. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
  14. logger.debug("Process01Interceptor postHandle方法");
  15. }
  16. // 渲染视图之后执行
  17. @Override
  18. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  19. logger.debug("Process01Interceptor afterCompletion方法");
  20. }
  21. }

拦截器执行顺序

  • preHandle() 方法
  • 目标 handler 方法
  • postHandle() 方法
  • 渲染视图
  • afterCompletion() 方法
  • xml配置
  1. <!-- 注册拦截器 -->
  2. <mvc:interceptors>
  3. <!-- 直接通过内部 bean 配置的拦截器默认拦截全部请求(SpringMVC 范围内) -->
  4. <bean class="com.atguigu.mvc.interceptor.Process01Interceptor"/>
  5. </mvc:interceptors>
  1. <!-- 具体配置拦截器可以指定拦截的请求地址 -->
  2. <mvc:interceptor>
  3. <!-- 精确匹配 -->
  4. <mvc:mapping path="/common/request/one"/>
  5. <bean class="com.atguigu.mvc.interceptor.Process03Interceptor"/>
  6. </mvc:interceptor>
  1. <mvc:interceptor>
  2. <!-- /*模糊匹配,匹配路径中的一层 -->
  3. <mvc:mapping path="/common/request/*"/>
  4. <bean class="com.atguigu.mvc.interceptor.Process04Interceptor"/>
  5. </mvc:interceptor>
  1. <mvc:interceptor>
  2. <!-- /**模糊匹配,匹配路径中的多层 -->
  3. <mvc:mapping path="/common/request/**"/>
  4. <bean class="com.atguigu.mvc.interceptor.Process05Interceptor"/>
  5. </mvc:interceptor>
  1. <mvc:interceptor>
  2. <!-- /**匹配路径中的多层 -->
  3. <mvc:mapping path="/common/request/**"/>
  4. <!-- 使用 mvc:exclude-mapping 标签配置不拦截的地址 -->
  5. <mvc:exclude-mapping path="/common/request/two/bbb"/>
  6. <bean class="com.atguigu.mvc.interceptor.Process05Interceptor"/>
  7. </mvc:interceptor>

多拦截器的执行顺序

  • preHandle()方法:和配置的顺序一样
  • 目标handler方法
  • postHandle()方法:和配置的顺序相反
  • 渲染视图
  • afterCompletion()方法:和配置的顺序相反

作用

preHandle()方法 :决中文乱码问题,安全验证(判断是否已经登录),页面跳转(系统维护中)等

postHandle()方法:网站升级测试时,跳转到新版测试页面;进行敏感字符替换等

afterCompletion()方法:完成资源关闭,异常处理等操作

21. 注解设定类型转换

SpringMVC 对基本数据类型提供了自动的类型转换。很多带格式的数据必须明确指定格式之后才可以进行类型转换。最典型的就是日期类型。

  1. @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  2. private Date productDate;
  3. @NumberFormat(pattern = "###,###,###.###")
  4. private Double productPrice;

22. 数据校验

@Email 标注值必须是格式正确的 Email 地址
@Length 标注值字符串大小必须在指定的范围内
@NotEmpty 标注值字符串不能是空字符串
@Range 标注值必须在指定的范围内

23. 异常映射

  • 创建异常处理器类
  • 异常处理器加入IoC容器

    1. <context:component-scan base-package="com.atguigu.mvc.handler,com.atguigu.mvc.exception"/>
  • 给异常处理器类标记注解

    1. // 异常处理器类需要使用 @ControllerAdvice 注解标记
    2. @ControllerAdvice
    3. public class MyExceptionHandler {
    4. }
  • 声明处理异常的方法

    1. // @ExceptionHandler注解:标记异常处理方法
    2. // value属性:指定匹配的异常类型
    3. // 异常类型的形参:SpringMVC 捕获到的异常对象
    4. @ExceptionHandler(value = NullPointerException.class)
    5. public String resolveNullPointerException(Exception e, Model model) {
    6. // 我们可以自己手动将异常对象存入模型
    7. model.addAttribute("atguiguException", e);
    8. // 返回逻辑视图名称
    9. return "error-nullpointer";
    10. }
    • 异常范围
  1. <prop key="java.lang.ArithmeticException">error-arith</prop>
  2. <prop key="java.lang.RuntimeException">error-runtime</prop>

24. SpringMVC执行流程

  1. 首先浏览器发送请求——>DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他组件进行处理,作为统一访问点,进行全局的流程控制
  2. DispatcherServlet——>HandlerMapping,处理器映射器将会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器对象、多个HandlerInterceptor拦截器)对象
  3. DispatcherServlet——>HandlerAdapter,处理器适配器将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器
  4. HandlerAdapter——>调用处理器相应功能处理方法,并返回一个ModelAndView对象(Model部分是业务对象返回的模型数据,View部分为逻辑视图名)
  5. DispatcherServlet——> ViewResolver,视图解析器将把逻辑视图名解析为物理视图,返回View对象
  6. DispatcherServlet——>View,View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构
  7. DispatcherServlet——>响应,返回控制权给DispatcherServlet,由它返回响应给用户,到此一个流程结束

SpringMVC的常见API

①中央控制器DispatcherServlet

②处理器映射器HandlerMapping

③处理器执行链HandlerExecutionChain

④处理器适配器HandlerAdapter

⑤视图解析器ViewResolver