目录
Maven
简介
工作机制(★)
依赖配置(★)
Maven命令
MyBatis
入门
单参数查询(★)
多参数查询(★★★)
自定义映射关系(★★★)
基本增删改查操作(★)
Mapper接口定义(★★★)
注解方式配置SQL(★★★)
MyBatis动态SQL(★★★)
和标签
标签
标签
Spring
Spring框架介绍(★)
Spring控制反转(★)
Spring依赖注入
基于XML方式依赖注入(★)
基于注解方式依赖注入(★★★)
1. 使用注解标记组件
2. 配置扫描组件所在包
Spring AOP面向切面编程
基于注解方式配置切面(★★★)
启用 AspectJ 自动代理功能
使用@Aspect 注解定义切面
使用@Pointcut 注解定义切点
使用注解定义通知
SpringMVC
SpringMVC框架简介(★)
运行原理(★)
SpringMVC框架搭建
能够结合需求写出控制器代码(★★★)
@RequestMapping注解使用(★★★)
SpringMVC配置文件(★★★)
SpringMVC前后端数据交互(★★★)
基于JSON的数据交互(★)
拦截器
拦截器定义(★)
拦截器配置(★★★)
全局异常处理(★)
SSM整合
SSM框架整合配置(★★★)
Spring声明式事务管理(★★★)
基于XML实现
基于注解实现
事务失效场景
Maven
简介
Maven 的本质是⼀个项目管理工具,将项⽬开发和管理过程抽象成⼀个项目对象模型(POM),通过简单的配置和命令就可以完成项⽬的构建管理和依赖管理。 使⽤ Maven 可以实现⾃动化构建、测试、打包和发布项⽬,⼤⼤提⾼了开发效率和质量。
工作机制(★)
依赖配置(★)
通过Maven⼯程的pom.xml⽂件可以完成依赖配置。⽐如,我们需要在⼯程中使⽤MySQL驱动的Jar 包,我们只需要在pom.xml中完成添加如下依赖配置:
<dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><version>5.7.6</version>
</dependency>
groupId、artifactId和version是Jar包依赖的GAV三坐标,GAV三坐标就相当于人的姓+名,起到一个标识的作用。
在<dependency>节点中还有一个<scope>元素可以设置依赖的作用范围,有如下四个取值:
scope取值 | 编译阶段 | 测试阶段 | 运行阶段 |
compile(默认值) | 有效 | 有效 | 有效 |
provided | 有效 | 有效 | 无效 |
test | 无效 | 有效 | 无效 |
runtime | 无效 | 无效 | 有效 |
默认值就是不写出这个元素的时候;再比如,一般导入junit依赖时,都是会标识test以表示只测试阶段。
Maven命令
Maven配置完成后,就可以使用Maven命令进行项目构建和依赖管理了。
命令 | 作用 | 说明 |
mvn -v | 查看Maven当前版本信息 | 使用mvn –v或mvn –version命令,执行后的结果一样。 |
mvn clean | 删除target目录 | target目录是Maven的输出目录,主要存放生成的class、jar、war等文件。 |
mvn compile | 编译程序 | 编译后的文件将存放在taget/classes目录中。 |
mvn package | 打包项目 | 打包后的结果(jar或war包)将存放在target目录中。 |
mvn install | 安装jar包到本地仓库 | 将打包好的jar包存放到Maven本地仓库中。 |
MyBatis
入门
MyBatis是一个优秀的数据持久层框架,是一种半自动的ORM实现。MyBatis最初是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation迁移到了Google Code。随着开发团队转投Google Code旗下, iBatis3.x正式更名为MyBatis。 代码于2013年11月迁移到Github。
- 目前比较流行的ORM框架有Hibernate和MyBatis。
- 开发效率:Hibernate>Mybatis>JDBC
- 运行效率:JDBC>Mybatis>Hibernate
单参数查询(★)
UserMapper.xml映射文件中添加如下SQL配置:
<!--根据用户名查询用户信息-->
<select id="selectUserByUsername" resultType="user">select * from t_user where username=#{username}
</select>
注:
- id用来指定唯一标识,resultType用来指定绑定结果类型
- parameterType用来指定传递的参数类型,该属性也可以省略不写
- #{ }就相当于JDBC中的问号占位符,用于接收调用者传递过来的一个参数。
- 因为根据用户名查询用户信息只会传递一个参数,因此#{ }中的参数名可以任意。
- 使用${ }也可以接收参数,但是这种形式的传参在MyBatis底层进行的是字符串拼接的操作,可能会造成SQL注入的问题,实际开发中,能用#{}实现的,肯定不用${}。
- 如果使用${}来接收参数,则是如下配置写法。
<!--根据用户名查询用户信息--><select id="selectUserByUsername" resultType="user">select * from t_user where username='${username}'</select>
多参数查询(★★★)
- 能够根据题目要求写出对应的<select>配置
在UserMapper.xml中添加如下SQL配置:
<!--根据性别和出生年份查询用户信息--><select id="selectUserByParam" resultType="user">select * from t_user where sex=#{sex} and year(birthDate)=#{birthYear}</select>
注:
- 因为SQL配置需要接收两个参数,所以使用了两个#{}占位符
- 对于多个参数,可以使用实体类或者Map来传递多个参数值
- 要注意的是,#{}里的参数名一定要和实体类中的属性名或者Map中的键名一一对应,如果不一致将接收不到参数值。
自定义映射关系(★★★)
在SQL映射文件中,当查询结果列名和实体类属性名不一致时,可以使用<resultMap>标签实现自定义映射关系。
<resultMap id="employeeMap" type="Employee"><!-- 使用id标签设置主键列和主键属性之间的对应关系 --><!-- column属性用于指定字段名;property属性用于指定Java实体类属性名 --><id column="id" property="id"/><!-- 使用result标签设置普通字段和Java实体类属性之间的关系 --><result column="emp_name" property="empName"/><result column="emp_age" property="empAge"/><result column="emp_birth" property="empBirth"/><result column="emp_job" property="empJob"/><result column="emp_join" property="empJoin"/>
</resultMap>
注:
- 通过<id>和<result>子标签可以定义数据库表字段和Java实体类属性之间的映射关系。
- <id>用于定义主键列和主键属性之间的映射关系
- <result>用于普通列和Java实体类属性之间的映射关系
映射关系定义完成后,我们还需要在SQL配置中使用resultMap属性引用该映射关系,MyBatis底层才能根据我们自定义的映射规则完成数据映射。
<!--SQL语句配置,将查询的结果映射到User对象中--><select id="selectAllEmployees" resultMap="employeeMap">select * from t_employee</select>
基本增删改查操作(★)
insert语句使用<insert>标签来配置,同样是使用#{}来接收参数,#{}里面的参数名要和实体类中的属性名一一对应,还要注意,对于<insert>、<update>和<delete>标签来说,不需要指定resultType属性,因为默认值为int类型,表示数据库受影响的行数。
<!--新增一个用户-->
<insert id="insertOne">insert into t_user(username,password,age,sex,birthDate)values(#{username},#{password},#{age},#{sex},#{birthDate})
</insert>
Mapper接口定义(★★★)
- 能够结合SQL配置写出正确的接口方法。
在MyBatis框架,接口的定义需要遵循如下的规范:
- 方法名和SQL配置的id一致
- 方法返回值和resultType一致
- 方法的参数和SQL配置需要的参数一致
SQL配置:
<!--根据性别和出生年份查询用户信息--><select id="selectUserByParam" resultType="user">select * from t_userwhere sex=#{sex} and year(birthDate)=#{birthYear}</select>
SQL配置对应的接口方法:
List<User> selectUserByParam(UserParam param);
注:因为在SQL配置中需要两个参数,这里接口方法的参数为实体类UserParam。
或者
第二个SQL配置对应的接口方法:
List<User> selectUserByParam(Map<String,Object> param);
注:这个接口是使用Map对象来传递多个参数。
或者
第二个SQL配置对应的接口方法:
List<User> selectUserByParam(@Param("sex") int sex, @Param("birthYear") String birthYear);
注:通过接口的方式可以使用@Param注解传递多个简单类型参数。@Param中的参数名要和SQL配置中的参数名一一对应。
注解方式配置SQL(★★★)
- 能够基于注解方式配置SQL语句。
MyBatis 提供了基于注解的方式来配置 SQL 语句。
- @Insert注解:用于定义insert语句,作用等同于xml配置中<insert>标签
- @Update注解:用于定义update语句,作用等同于xml配置中<update>标签
- @Delete注解:用于定义delete语句,作用等同于xml配置中<delete>标签
- @Select注解:用于定义select语句,作用等同于xml配置中<select>标签
MyBatis动态SQL(★★★)
<if>和<where>标签
- <if>标签用于进行条件判断,类似于Java中的if语句,通过该标签可以有选择的加入SQL语句的片段。
- <where>标签的作用是能够自动处理查询条件,智能的处理多余的where、and、or关键字。
- <if>和<where>标签组合可以实现动态条件查询。
<select id="selectByParam" resultType="User">select * from t_user<!--自动处理多余的where,and,or关键字--><where><!--当username参数值不为空且不为空字符串时,则加入SQL片段--><if test="username!=null and username!=''">and username=#{username}</if><!--当sex参数值不为空时,则加入SQL片段--><if test="sex!=null">and sex=#{sex}</if><!--当birthYear参数值不为空时,则加入SQL片段--><if test="birthYear!=null and birthYear!=''">and year(birthDate)=#{birthYear}</if></where></select>
<trim>标签
<trim>标签是一个格式化的标记,主要用于动态拼接SQL的条件语句,可以完成set标签或者是where标签的功能。
<select id="selectByParam" resultType="User">select * from t_user<trim prefix="where" prefixOverrides="and|or"><!--当username参数值不为空且不为空字符串时,则加入SQL片段--><if test="username!=null and username!=''">and username=#{username}</if><!--当sex参数值不为空时,则加入SQL片段--><if test="sex!=null">and sex=#{sex}</if><!--当birthYear参数值不为空时,则加入SQL片段--><if test="birthYear!=null and birthYear!=''">and year(birthDate)=#{birthYear}</if></trim></select>
<foreach>标签
<foreach>标签可以在SQL配置中迭代集合类型参数。常用于构造in语句实现查询某一范围内的数据。可以用来实现批量查询、批量更新、批量删除和批量新增操作。
<select id="selectListByNos" resultType="String">select stu_name from student<where><!--判断集合是否为空--><if test="list!=null and !list.isEmpty()">stu_no in<!--使用<foreach>遍历集合参数--><foreach collection="list"item="no"open="("close=")"separator=",">#{no}</foreach></if></where></select>
collection="list"
:指定要遍历的集合名称。item="no"
:指定集合中每个元素的别名。open="("
:指定遍历开始时的前缀。close=")"
:指定遍历结束时的后缀。separator=","
:指定集合中每个元素之间的分隔符。#{no}
:表示集合中的每个元素,用于生成SQL语句中的值。
Spring
Spring框架介绍(★)
Spring Framework(Spring框架)
是一个开源的应用程序框架,由SpringSource公司开发,最初是为了解决企业级开发中各种常见问题而创建的。它提供了很多功能,例如:控制反转(IoC)、依赖注入(DI)、面向切面编程(AOP)、声明式事务管理(TX)等。其主要目标是使企业级应用程序的开发变得更加简单和快速
,广泛应用于Java企业开发领域。
Spring控制反转(★)
IoC(Inversion of Control)
的含义是控制反转
。 控制反转指的是当应用程序需要创建一个对象时,不再是应用程序直接通过new的方式创建该对象,而是由 Spring容器来创建和管理,即控制权由应用程序转移到 Spring容器中,也就是“反转”了控制权。
把UserDao对象注册到Spring容器中,我们可以在spring-beans.xml中加入如下<bean>配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!--配置UserDao组件信息--><bean id="userDao" class="com.cg.dao.UserDao"></bean></beans>
从Spring容器中获取Bean并使用
public class SpringTest {@Testpublic void test1(){//创建Ioc容器ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("spring-beans.xml");//从IoC容器中获取组件(根据name获取Bean)UserDao userDao=context.getBean("userDao",UserDao.class);//调用组件方法userDao.insert("张三",24);}
}
在<bean>标签中,可以通过配置scope属性来定义Bean的作用域。
<!--通过scope属性定义Bean作用域-->
<bean id="..." class="..." scope="..."></bean>
scope常用可选值:
取值 | 含义 | 创建对象的时机 | 默认值 |
singleton | 在 IOC 容器中,这个 bean 的对象始终为单实例 | IOC 容器初始化时 | 是 |
prototype | 这个 bean 在 IOC 容器中有多个实例 | 获取 bean时 | 否 |
singleton
是Spring中的默认作用域。当一个Bean的作用域被设置为singleton
时,Spring容器只会创建该Bean的一个实例。无论多少个请求,都会返回同一个实例。- 适用于无状态的Bean,如工具类、服务类等。这些Bean不需要维护状态,每次调用方法时都是独立的。
prototype
作用域的Bean,每次请求时都会创建一个新的实例。每次调用getBean
方法时,都会返回一个新的Bean实例。- 适用于有状态的Bean,如用户会话管理、事务管理等。这些Bean需要维护状态,每次请求时都需要一个新的实例。
Spring依赖注入
Spring容器可以通过依赖注⼊(DI)功能将⼀个组件注册到另外⼀个组件的属性中,从⽽完成依赖关系的传递,解除对象之间的耦合,也可以称为属性注入。
基于XML方式依赖注入(★)
在 Spring容器 中,依赖注入(DI)
可以通过 XML 配置文件实现的。它提供了两种形式的依赖注入配置:Setter 方法注入和构造方法注入。
(1)Setter方法注入
是指IoC容器可以动态调用Bean中属性的set方法,注入依赖对象。因此,基于Setter方法的依赖注入要求我们需要在Bean中为属性定义set方法
。通过属性的set方法可以注入简单类型参数值或者其他Bean对象。在配置文件中使用<property>标签完成属性注入。
配置如下所示:
<!--使用Bean标签配置Bean信息--><bean class="com.cg.bean.StudentBean"><!--使用property标签完成简单类型属性值的注入--><property name="name" value="张三"/><property name="code" value="0001"/></bean>
(2)构造方法注入
是指IoC容器可以动态调用Bean的带参构造方法
,注入依赖对象。因此,基于构造方法的依赖注入要求我们需要在Bean中定义带参构造方法
,参数为要依赖的其他Bean对象引用或简单类型参数
。在配置文件中使用使用<constructor-arg>标签完成参数注入。
<!--使用Bean标签配置Bean信息--><bean class="com.cg.bean.StudentBean"><!--使用constructor-arg标签完成构造方法参数的注入--><constructor-arg index="0" value="00001"/><constructor-arg index="1" value="李四"/></bean>
基于注解方式依赖注入(★★★)
基于注解方式的组件注册实现需要两个步骤:
- 使用注解标记组件
- 扫描组件所在的包
1. 使用注解标记组件
(1)Spring框架中提供了以下多个注解,这些注解可以直接标注在 Java 类上,将它们定义成 Spring Bean。
注解 | 说明 |
@Repository | 常用于将数据访问层(Dao层)的组件标识为Spring中的Bean |
@Service | 常用于将业务逻辑层(Service层)的组件标识为Spring中的Bean |
@Controller | 常用于将控制层(Controller层)的组件标识为Spring中的Bean |
@Component | 常用于将除了以上三层以外的其他组件标识为Spring中的Bean |
对于Spring使用IoC容器管理这些组件来说以上注解没有区别,可以互换, 只是习惯上不同的注解应用于不同层级的组件上, 让我们能够快速分辨组件的作用。
(2)通过使用 @Autowired
注解可以实现Spring容器中组件之间的依赖注入。
- @Autowired 只需要标注在属性上面即可,并且不需要定义带参构造函数或者为属性定义set方法即可完成依赖注入。该注解默认根据类型装配,如果想根据名称装配,需要配合@Qualifier注解一起用。
@Service
public class UserService {@Autowiredprivate UserDao userDao;//省略其他代码
}
2. 配置扫描组件所在包
在spring-beans.xml中添加如下配置:
<!--扫描组件所在包-->
<context:component-scan base-package="com.cg.controller,com.cg.service,com.cg.dao"/>
Spring AOP面向切面编程
AOP
(Aspect Oriented Programming),中文翻译为面向切面编程
,是一种编程的思想,是对OOP( Object Oriented Programming,面向对象编程 )的补充和完善。 它利用一种称为"横切"
的技术,剖解开封装的对象内部,并将那些与业务无关,但却影响了多个类的公共行为
封装到一个可重用模块
,并将其命名为"Aspect",即切面。AOP可以减少系统的重复代码,降低模块之间的耦合度,并有利于提升项目的可操作性和可维护性。
基于注解方式配置切面(★★★)
启用 AspectJ 自动代理功能
Spring 基于注解配置 AOP 需要启用 AspectJ 自动代理
功能,启用该功能后,Spring框架会自动扫描应用程序中所有被AOP注解标记的类,并自动创建AOP代理对象。
启用 AspectJ 自动代理功能需要在Spring的配置文件中添加如下配置:
<!--启用AspectJ自动代理功能-->
<aop:aspectj-autoproxy/>
使用@Aspect 注解定义切面
在 Spring 管理的 Bean 类上使用 @Aspect 注解
就可以定义一个切面。
//日志记录切面类
@Aspect
public class LogAspect {}
使用@Pointcut 注解定义切点
在切面类中定义一个空方法
并使用 @Pointcut 注解
来定义切点,然后在@Pointcut注解中定义切点表达式
用来匹配切入的目标类和方法。空方法的方法名就是切点的唯一标识id。
//日志记录切面类
@Aspect
public class LogAspect {//定义切点,切点的id为"pointcut()"@Pointcut("execution(* com.cg.service.*.*(..))")public void pointcut(){ }
}
- @Pointcut注解中可以定义切点表达式,execution()表示切入的是方法。
- * com.cg.service.*.*(..)表示切入com.cg.service包下的所有类的所有方法。
使用注解定义通知
在Spring AOP中通过以下注解来定义通知。
- 使用
@Before 注解
定义前置通知
,在方法执行前添加操作。在该注解中,需要指定切点来控制当前通知方法要作用在哪些目标方法上。
//日志记录切面类
@Aspect
public class LogAspect {//定义切点,切点的id为"pointcut()"@Pointcut("execution(* com.cg.service.*.*(..))")public void pointcut(){}//前置通知方法@Before("pointcut()")public void before(){//方法调用之前打印日志System.out.println("开始调用方法");}
}
- 使用
@AfterReturning 注解
定义返回通知
,在方法正常返回时执行,方法抛异常不执行。
//返回通知方法@AfterReturning(value = "pointcut()")public void afterReturn(){System.out.println("结束调用方法");}
- 使用
@After 注解
定义后置通知,在方法退出时执行,无论方法内部是否抛出异常。
//后置通知方法@After("pointcut()")public void after(){//方法调用之后打印日志System.out.println("结束调用方法");}
- 使用
@AfterThrowing 注解
定义异常通知,在方法抛出异常时执行。
//异常通知方法@AfterThrowing("pointcut()")public void exception(){//方法调用异常打印日志System.out.println("调用方法出现异常");}
SpringMVC
SpringMVC框架简介(★)
SpringMVC是Spring Web MVC的简称。Spring MVC属于SpringFrameWork的后续产品,是Spring框架基于MVC模式构建的用于Web应用程序开发的全功能模块。
运行原理(★)
SpringMVC框架是基于Servlet API构建的。在SpringMVC框架内部有一个核心Servlet “DispatcherServlet
”,DispatcherServlet继承于HttpServlet,在SpringMVC框架中用于做整体请求处理调度!
SpringMVC框架搭建
能够结合需求写出控制器代码(★★★)
使用@Controller和@RequestMapping注解定义控制器。
@Controller
public class HelloController {@RequestMapping("/hello")public String hello(){return "hello";}
}
@RequestMapping注解使用(★★★)
@RequestMapping注解的作用就是将请求的 URL 地址
和控制器中的方法
关联起来,建立映射关系。
- 精准路径匹配: 在@RequestMapping注解指定 URL 地址时,按照请求地址进行精确匹配。
@Controller
public class HelloController {@RequestMapping("/hello")public String hello(){return "hello";}
}
- 模糊路径匹配: 在@RequestMapping注解指定 URL 地址时, 通过使用通配符,匹配多个类似的地址。
- 路径设置为/hello/*, /* 为单层任意字符串,/hello/a、/hello/aaa 可以访问此方法, /hello/a/a 不可以 。
@Controller
public class HelloController {@RequestMapping("/hello/*")public String hello(){return "hello";}
}
- 路径设置为/hello/**, /** 为任意层任意字符串,/hello/a、/hello/aaa 可以访问此方法,/hello/a/a 也可以访问
@Controller
public class HelloController {@RequestMapping("/hello/**")public String hello(){return "hello";}
}
- 在@RequestMapping中,通过value属性可以指定URL地址,通过method属性可以限定请求方式
@Controller
public class HelloController {@RequestMapping(value="/hello",method = RequestMethod.GET)public String hello(){return "hello";}
}
该方法只能接收get请求,如果违背请求方式,会报405异常。RequestMethod是一个枚举类型,定义了八种请求方式。
public enum RequestMethod {GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE
}
也可以使用@GetMapping、@PostMapping、@PutMapping、@DeleteMapping来限定请求方式。
@Controller
public class HelloController {@GetMapping("/hello")public String hello(){return "hello";}
}
- 在@RequestMapping指定的URL地址中可以使用
占位符{xxx}
表示路径中的传递的值,再通过@PathVariable
注解,将占位符所传递的值和控制器方法的形参进行绑定。
@Controller
public class HelloController {@RequestMapping("/hello/{username}")public String hello(@PathVariable("username")String username){System.out.println(username);return "hello";}
}
- @RequestMapping也可以同时标注在类上,表示类中的所有方法都是以该地址作为父路径,访问类中方法时都需要在方法URL地址前面加上该父路径。
- 访问该控制器里的方法都需要加上
父级路径/abc
,因此通过路径/abc/hello
可以访问该hello方法。
@RestController
@RequestMapping("/abc")
public class HelloController {@RequestMapping("/hello")public String hello(){return "hello";}
}
SpringMVC配置文件(★★★)
- 能够说出下面每一项配置的作用
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"><!--开启注解驱动--><mvc:annotation-driven/><!--扫描控制器所在的包,注册到IoC容器中--><context:component-scan base-package="com.cg.controller"/><!--配置视图解析器--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/views/"></property><property name="suffix" value=".jsp"></property></bean><!--静态资源访问映射路径,解决静态资源找不到的问题,也可以使用<mvc:default-servlet-handler/> --><mvc:resources location="/static/" mapping="/static/**"/>
</beans>
<?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"><!-- 配置DispatcherServlet --><servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- 加载类路径下的springmvc.xml(SpringMVC框架配置文件) --><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><!-- 配置DispatcherServlet接受所有HTTP请求 --><servlet-mapping><servlet-name>springmvc</servlet-name><url-pattern>/</url-pattern></servlet-mapping>
</web-app>
SpringMVC前后端数据交互(★★★)
在HTTP请求中,无论是get请求还是post请求,一般都会携带参数,Controller接收参数的方式有以下三种:
- HttpServletRequest接收
@ResponseBody@RequestMapping("/doAdd")public String doAdd(HttpServletRequest request){String username= request.getParameter("username");String password= request.getParameter("password");String tel= request.getParameter("tel");int sex= Integer.parseInt(request.getParameter("sex"));User user=new User(username,password,tel,sex);userService.add(user);return "success";}
- 方法形参接收
- 在每一个形参前面都要加上@RequestParam注解指定接收的请求参数名称
@ResponseBody@RequestMapping("/doAdd")public String doAdd(@RequestParam("username") String username,@RequestParam("password") String password,@RequestParam("tel") String tel,@RequestParam("sex") int sex){User user=new User(username,password,tel,sex);userService.add(user);return "success";}
- 实体类型接收
我们直接使用User实体类就可以接收参数:
//用户实体类
@Data
public class User {private String username;//用户名private String password;//密码private String tel;//联系电话private int sex;//性别
}
在Controller方法中加入User类型的参数,参数名任意。
@ResponseBody@RequestMapping("/doAdd")public String doAdd(User user){userService.add(user);return "success";}
基于JSON的数据交互(★)
Spring MVC框架默认支持的 JSON 解析框架是 Jackson。Jackson 是一个用于处理 JSON 数据的 Java 库,它可以将 Java 对象序列化为 JSON 字符串,也可以将 JSON 字符串反序列化为 Java 对象。
在SpringMVC框架中使用Jackson需要以下四个步骤:
- 在SpringMVC项目中引入Jackson库依赖
- 在Spring容器中注册JSON消息转换器
<!--注解驱动,向容器中注入SpringMVC框架运行需要的组件Bean-->
<mvc:annotation-driven/>
3.在控制器方法中 使用 @RequestBody 注解来接收 JSON格式参数,并将其解析为 Java 对象
4.在控制器方法中 使用 @ResponseBody 注解将返回的Java对象转化为JSON数据放在响应体中
5.将实体类型作为控制器方法参数,并加上@RequestBody注解
@Controller
@RequestMapping("/api/product")
public class ProductController {@Autowiredprivate ProductService productService;@CrossOrigin@ResponseBody@RequestMapping("/add")public Result<Product> add(@RequestBody Product product){System.out.println(product.toString());productService.add(product);return new Result<Product>(1,"新增商品成功",product);}
}
拦截器
拦截器定义(★)
在SpringMVC项目中,可以通过实现HandlerInterceptor接口并重写接口中的方法来创建拦截器类。
在HandlerInterceptor接口中有三个方法,分别是preHandle、postHandle和afterCompletion方法。
- preHandle方法是在控制器目标方法执行之前执行的方法
- postHandle方法是在控制器目标方法执行之后执行的方法,目标方法内部异常时不执行
- afterCompletion方法是在给与客户端最终响应之后执行的方法,无论目标方法内部是否异常都会执行。
拦截器配置(★★★)
拦截器类创建好之后,还需要通过在SpringMVC配置文件中配置<mvc:interceptors>标签完成拦截器的配置才能生效。
- <mvc:interceptors>元素用于配置一组拦截器,其子元素<bean>定义的是全局拦截器,即拦截所有请求
<!-- 配置拦截器 --><mvc:interceptors><!-- 配置一个全局拦截器,拦截所有客户端请求 --><bean class="interceptor.MyInterceptor"></bean></mvc:interceptors>
- <mvc:interceptor>元素定义指定路径的拦截器,其子元素<mvc:mapping>用于配置拦截器作用的路径,<mvc:exclude-mapping>用于配置拦截器不需要拦截,也就是放行的路径。
<!-- 配置拦截器 --><mvc:interceptors><!-- 定义指定路径的拦截器 --><mvc:interceptor><!-- 配置拦截器拦截的路径 , /api/**表示拦截以/api/开头的所有请求 --><mvc:mapping path="/api/**"/><!-- 配置拦截器不需要拦截的路径 --><mvc:exclude-mapping path="/api/login"/><!-- 指定拦截器全限定类型--><bean class="interceptor.LoginInterceptor"></bean></mvc:interceptor></mvc:interceptors>
如果项目配置了了多个拦截器,那么拦截器的preHandle方法依次顺序执行,而拦截器的postHandle方法和afterCompletion反序执行。
全局异常处理(★)
@ControllerAdvice
和@ExceptionHandler
注解的组合可以实现捕获所有控制器抛出的异常并进行处理。
//全局异常处理器
@ControllerAdvice
public class GlobalExceptionHandler{@ResponseBody//处理业务异常@ExceptionHandler(BusinessException.class)public Result<Exception> handleBusException(BusinessException ex){return new Result<>(400,ex.getMessage(),ex);}@ResponseBody//处理系统异常@ExceptionHandler(Exception.class)public Result<Exception> handleException(Exception ex){return new Result<>(500,"抱歉,服务器出现了异常,正在加紧修复中",ex);}
}
SSM整合
SSM框架整合配置(★★★)
- 需要在src/main/resources(类路径)下添加三个配置,分别是SpringMVC框架的配置(springmvc.xml)、MyBatis核心配置文件(mybatis-config.xml)、数据库连接的配置(db.properties)以及Spring和MyBatis框架的整合配置(spring-mybatis.xml)
- 需要修改web.xml配置DispatcherServlet,同时加载src/main/resources(类路径)下的配置文件
- 能够说出配置文件中每一项配置的作用。参考我之前的博客
Spring声明式事务管理(★★★)
Spring声明式事务管理通过AOP技术实现的事务管理,主要思想是将事务作为一个“切面”代码单独编写,然后通过AOP技术将事务管理的“切面”植入到业务目标类方法中。
Spring的声明式事务管理可以通过两种方式来实现,一种是基于XML的方式,另一种是基于注解的方式。
基于XML实现
基于XML方式的声明式事务是在配置文件中通过<tx:advice>元素配置事务规则来实现的,然后通过使用<aop:config>编写的AOP配置,让Spring自动对目标生成代理。
<!--定义事务管理器 --><bean id="txManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!--关联数据源--><property name="dataSource" ref="dataSource" /></bean><!-- 配置事务规则 --><tx:advice id="txAdvice" transaction-manager="txManager"><tx:attributes><!-- 定义哪些方法需要进行事务处理,*表示任意字符,比如find*表示以find开头的方法 --><tx:method name="find*" propagation="SUPPORTS" read-only="true"/><tx:method name="add*" propagation="REQUIRED"/><tx:method name="del*" propagation="REQUIRED"/><tx:method name="update*" propagation="REQUIRED"/><tx:method name="moneyTransfer" propagation="REQUIRED"/></tx:attributes></tx:advice><!-- 定义切面 --><aop:config><!-- 定义切点 --><aop:pointcut expression="execution(* com.cg.service.*.*(..))" id="pointcut"/><!-- 在指定的切点上应用事务规则 --><aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/></aop:config>
基于注解实现
- 开启事务注解驱动
<!--定义事务管理器 --><bean id="txManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!--关联数据源--><property name="dataSource" ref="dataSource" /></bean><!--开启事务注解驱动 --><tx:annotation-driven transaction-manager="txManager"/>
- 在需要事务管理的类或方法上使用@Transactional注解。
- 如果将注解添加在Bean类上,则表示事务的设置对整个Bean类的所有方法都起作用;
- 如果将注解添加在Bean类中的某个方法上,则表示事务的设置只对该方法有效。
- 使用@Transactional注解时,可以通过参数配置具体事务规则
事务失效场景
- 失效场景1:使用try...catch...代码块捕获异常并处理,未抛出
原因分析:因为异常已经被捕获并处理,异常未抛出导致事务管理器未捕获到异常导致事务失效。
解决方案:去掉try...catch...代码块,或者将异常抛出去
- 失效场景2:抛出的异常不是RuntimeException异常及其子类。
原因分析:声明式异常处理默认只能捕获处理RuntimeException异常及其子类异常。对于其他类型的异常不会处理。
解决方案1:抛出异常时,异常类型要使用RuntimeException或者其子类,而不是Exception,特别是自定义的业务异常,一定要继承RuntimeException及其子类。
解决方案2:可以在@Transactional注解中通过配置rollbackFor属性指定异常类型为Exception,表示对所有异常都会出发事务管理机制。