SSM(Spring+SpringMVC+MyBatis)框架集是由Spring、MyBatis两个开源框架整合而成(Spring整合Mybatis,SpringMVC是Spring中的部分内容),是继SSH(Spring+Struts+Hibernate)之后,目前比较主流的Java EE企业级框架,适用于搭建各种大型的企业级应用系统。
Spring
Spring是于2003年兴起的一个轻量级的Java开发框架,是为了解决企业级应用开发的复杂性而创建的,为了简化开发。它可以使用基本的JavaBean来完成以前只可能由EJB完成的事情。它是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
SpringMVC
SpringMVC是一种基于Java,实现了Web MVC设计模式,请求驱动类型的轻量级Web框架。它属于Spring Framework的后续产品,是Spring的一个子项目。
Mybatis
MyBatis是一个可以自定义SQL、存储过程和高级映射的持久层框架。
一.项目创建
1.1 创建项目
创建Maven项目并选择webapp原型
1.2 导入所需依赖
<properties>
<spring.version>5.3.1</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<!--springmvc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Mybatis核心 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!--mybatis和spring的整合包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<!-- 连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>
<!-- junit测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<!-- log4j日志 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!--分页插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</dependency>
<!-- 日志 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- ServletAPI -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!--jackson处理json数组-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.1</version>
</dependency>
<!--文件上传依赖-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!-- Spring5和Thymeleaf整合包 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.12.RELEASE</version>
</dependency>
</dependencies>
二.目录结构
控制层controller、业务层service、持久层mapper(dao)
web应用程序配置文件:web.xml
web框架SpringMVC配置文件:springmvc.xml
Spring框架配置文件:spring.xml
MyBatis核心配置文件:mybatis-config.xml
数据库连接配置JDBC属性文件:jdbc.properties
日志配置文件:log4j.xml
三.配置web.xml
<?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">
<!--配置Spring的编码过滤器-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--配置处理请求方式的过滤器-->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--配置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>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--配置Spring的监听器,在服务器启动时加载Spring的配置文件-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--设置Spring配置文件自定义的位置和名称-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring.xml</param-value>
</context-param>
</web-app>
3.1 编码过滤器
解决获取请求参数的乱码问题,可以使用 SpringMVC 提供的编码过滤器 CharacterEncodingFilter
<!--配置Spring的编码过滤器-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
encoding:编码类型
forceEncoding:同时为响应设置
3.2 处理请求方式的过滤器
SpringMVC 提供了 HiddenHttpMethodFilter 帮助我们将 POST 请求转换为 DELETE 或 PUT 请求(删除与更新)
<!--配置处理请求方式的过滤器-->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
1.当前请求必须的请求方式为post 2.当前请求必须传输请求参数method,
<form th:action="@{/user}" method="post">
<input type="hidden" name="_method" value="put">
<input type="submit" value="修改用户信息">
</form> <br>
<form th:action="@{/user/1}" method="post">
<input type="hidden" name="_method" value="delete">
<input type="submit" value="删除用户信息">
</form> <br>
@RequestMapping(value = "/user", method = RequestMethod.PUT)
public String updateUser(){
System.out.println("修改用户信息--> /user -->put");
return "success";
}
@RequestMapping(value = "/user/{id}", method = RequestMethod.DELETE)
public String deleteUser(@PathVariable("id") Integer id){
System.out.println("删除用户信息--> /user/" + id + " -->delete");
return "success";
}
在web.xml中注册时,必须先注册CharacterEncodingFilter,再注册HiddenHttpMethodFilter
原因: 在 CharacterEncodingFilter 中通过 request.setCharacterEncoding(encoding) 方法设置字符集的 request.setCharacterEncoding(encoding) 方法要求前面不能有任何获取请求参数的操作 而 HiddenHttpMethodFilter 恰恰有一个获取请求方式的操作:String paramValue = request.getParameter(this.methodParam);
3.3 SpringMVC的前端控制器
对请求和响应进行统一处理
<!--配置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>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
contextConfigLocation:设置SpringMVC配置文件的位置和名称
load-on-startup:DispatcherServlet的初始化时间提前到服务器启动时,提高初次访问网页速度
url-pattern中 / 和 /* 的区别: /: 匹配浏览器向服务器发送的所有请求(不包括. jsp) /*: 匹配浏览器向服务器发送的所有请求(包括. jsp) bispatcherServlet不能处理jsp的请求
3.4 Spring的监听器
在web服务器的启动时,读取Spring的配置文件,创建Spring的IOC容器
<!--配置Spring的监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--设置Spring配置文件自定义的位置和名称-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring.xml</param-value>
</context-param>
四.配置springmvc.xml
<?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">
<!-- 扫描控制层组件 -->
<context:component-scan base-package="com.junn.ssm.controller"></context:component-scan>
<!-- 配置视图解析器 -->
<bean id="viewResolver"
class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="order" value="1"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<!-- 视图前缀 -->
<property name="prefix" value="/WEB-INF/templates/"/>
<!-- 视图后缀 -->
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML5"/>
<property name="characterEncoding" value="UTF-8" />
</bean>
</property>
</bean>
</property>
</bean>
<!-- 配置默认的servlet处理静态资源 -->
<mvc:default-servlet-handler />
<!-- 开启MVC的注解驱动 -->
<mvc:annotation-driven />
<!-- 配置访问首页的视图控制 -->
<mvc:view-controller path="/" view-name="index"></mvc:view-controller>
<!-- 配置文件上传解析器 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
</beans>
<!--
拦截器和异常解析器需要才配置
-->
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/testRequestEntity"/>
<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>
<property name="exceptionAttribute" value="ex"></property>
</bean>
4.1 扫描组件
<!-- 扫描控制层组件 -->
<context:component-scan base-package="com.junn.ssm.controller"></context:component-scan>
① 注解
和 XML 配置文件一样,注解本身并不能执行, 注解本身仅仅只是做一个标记,具体的功能是框架检测 到注解标记的位置,然后针对这个位置按照注解标记的功能来执行具体操作。 本质上:所有一切的操作都是Java代码来完成的,XML和注解只是告诉框架中的Java代码如何执行。
@Service
public class UserServiceImpl implements UserService {
}
@Component:将类标识为普通组件 @Controller:将类标识为控制层组件 @Service:将类标 识为业务层组件 @Repository:将类标识为持久层组件
② 扫描
Spring 为了知道程序员在哪些地方标记了什么注解,就需要通过扫描的方式,来进行检测。然后根据注解进行后续操作
1. 最基本的扫描方式
<!--扫描组件-->
<context:component-scan base-package="com.junn.spring"></context:component-scan>
存在的问题: SpringMVC 扫描控制层 Spring 扫描除控制层以外所有组件 所以需要排除组件
2. 指定要排除的组件
context:exclude-filter标签:指定排除规则 type:设置排除或包含的依据 type="annotation",根据注解排除(最常用),expression中设置要排除的注解的全类名 type="assignable",根据类型排除,expression中设置要排除的类型的全类名
<context:component-scan base-package="com.junn.spring">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
3. 仅扫描指定组件
context:include-filter标签:指定在原有扫描规则的基础上追加的规则 type:设置排除或包含的依据 type="annotation",根据注解排除,expression中设置要排除的注解的全类名 type="assignable",根据类型排除,expression中设置要排除的类型的全类名 use-default-filters属性:取值false表示关闭默认扫描规则, 此时必须设置use-default-filters="false",因为默认规则即扫描指定包下所有类
<context:component-scan base-package="com.junn.spring" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
③ 组件所对应的bean的id
在我们使用XML方式管理bean的时候,每个bean都有一个唯一标识,便于在其他地方引用。
现在使用注解后,每个组件仍然应该有一个唯一标识
默认情况 类名首字母小写就是bean的id。 例如:UserController类对应的bean的id就是userController。 自定义bean的id 可通过标识组件的注解的value属性设置自定义的bean的id
@Service("userService")//默认为userServiceImpl
public class UserServiceImpl implements UserService {
}
④ 基于注解的自动装配
@Autowired注解能够标识的位置 a> 标识在成员变量上,此时不需要设置成员变量的set方法 b> 标识在set方法上 c> 标识在为当前成员变量赋值的有参构造上
@Controller
public class UserController {
@Autowired
private UserService userService;
public void saveUser(){
userService.saveUser();
}
}
// 注意基于注解的自动装配不需要get和set方法
4.2 视图解析器
<!-- 配置视图解析器 -->
<bean id="viewResolver"
class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="order" value="1"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<!-- 视图前缀 -->
<property name="prefix" value="/WEB-INF/templates/"/>
<!-- 视图后缀 -->
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML5"/>
<property name="characterEncoding" value="UTF-8" />
</bean>
</property>
</bean>
</property>
</bean>
浏览器发送请求,若请求地址符合前端控制器的url-pattern,该请求就会被前端控制器 DispatcherServlet处理。 前端控制器会读取SpringMVC的核心配置文件,通过扫描组件找到控制器, 将请求地址和控制器中@RequestMapping注解的value属性值进行匹配, 若匹配成功,该注解所标识的 控制器方法就是处理请求的方法。处理请求的方法需要返回一个字符串类型的视图名称,该视图名称会 被视图解析器解析, 加上前缀和后缀组成视图的路径,通过Thymeleaf对视图进行渲染,最终转发到视 图所对应页面
4.3 默认的servlet与开启注解
当前工程的 web. xml 配置的前端控制器 DispatcherServlet 的 url-pattern 是 /,tomcat 的 web. xml 配置的 DefaultServlet 的 url -pattern 也是 /
此时,浏览器发送的请求会优先被Dispatcherservlet进行处理,但是Dispatcherservlet 无法处理静态资源
<!-- 配置默认的servlet处理静态资源 -->
<mvc:default-servlet-handler />
<!-- 开启MVC的注解驱动 -->
<mvc:annotation-driven />
配置 <mvc:default-servlet-handler /> ,此时浏览器发送的所有请求都会被DefaultServlet处理 配置 <mvc:annotation-driven /> 和 <mvc:annotation-driven />,浏览器发送的请求会先被DispatcherServlet处理,无法处理在交给Defaul tServlet处理
4.4 视图控制器
当控制器方法中,仅仅用来实现页面跳转,比如首页,即只需要设置视图名称时,可以将处理器方法使用viewcontroller标签进行表示
<!-- 配置访问首页的视图控制 -->
<mvc:view-controller path="/" view-name="index"></mvc:view-controller>
注: 当SpringMVC中设置任何一个view-controller时,其他控制器中的请求映射将全部失效, 此时需要在SpringMVC的核心配置文件中设置开启mvc注解驱动的标签:<mvc:annotation-driven />
4.5 文件上传解析器
必须通过文件解析器的解析才能将文件转换为MultipartFile对象
<!-- 配置文件上传解析器 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
① 文件下载
使用ResponseEntity实现下载文件的功能
@RequestMapping("/test/down")
public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException {
//获取ServletContext对象
ServletContext servletContext = session.getServletContext();
//获取服务器中文件的真实路径
String realPath = servletContext.getRealPath("/img/head_cat.jpg");
//创建输入流
InputStream is = new FileInputStream(realPath);
//创建字节数组,获取字节数
byte[] bytes = new byte[is.available()];
//将流读到字节数组中
is.read(bytes);
//创建HttpHeaders对象设置响应头信息
MultiValueMap<String, String> headers = new HttpHeaders();
//设置要下载方式以及下载文件的名字
headers.add("Content-Disposition", "attachment;filename=1.jpg");
//设置响应状态码
HttpStatus statusCode = HttpStatus.OK;
//创建ResponseEntity对象
ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, headers, statusCode);
//关闭输入流
is.close();
return responseEntity;
}
② 文件上传
要求form表单的请求方式必须为post,并且添加属性enctype=”multipart/form-data”
SpringMVC中将上传的文件封装到MultipartFile对象中,通过此对象可以获取文件相关信息
文件上传的要求: form表单的请求方式必须为post form表单必须设置属性enctype="multipart/form-data"以二进制形式传输
<form action="/SpringMVC/test/up" method="post" enctype="multipart/form-data">
头像:<input type="file" name="photo"><br/>
<input type="submit" value="上传">
</form>
@RequestMapping("/test/up")
public String testUp(MultipartFile photo, HttpSession session) throws IOException {
//获取上传的文件的文件名
String fileName = photo.getOriginalFilename();
//获取上传的文件的后缀名
String hzName = fileName.substring(fileName.lastIndexOf("."));
//获取uuid
String uuid = UUID.randomUUID().toString();
//拼接一个新的文件名
fileName = uuid + hzName;
//获取ServletContext对象
ServletContext servletContext = session.getServletContext();
//获取当前工程下photo目录的真实路径
String photoPath = servletContext.getRealPath("photo");
//创建photoPath所对应的File对象
File file = new File(photoPath);
//判断file所对应目录是否存在
if (!file.exists()) {
file.mkdir();
}
String finalPath = photoPath + File.separator + fileName;
//上传文件
photo.transferTo(new File(finalPath));
return "success";
}
注意:文件类型input的name值需要与MultipartFile参数值对应,否则会报空指针异常
4.6 拦截器
用于拦截控制器方法的执行,它需要实现HandlerInterceptor ,前端控制器DispatcherServlet本质上就是一个拦截器
① 拦截器的配置
SpringMVC的拦截器必须在SpringMVC的配置文件中进行配置
通过mvc:mapping设置需要拦截的请求,通过mvc:exclude-mapping设置需要排除的请求
<mvc:interceptors>
<ref bean="firstInterceptor" />
<ref bean="secondInterceptor" />
<!--或者-->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/testRequestEntity"/>
<ref bean="firstInterceptor"></ref>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/testRequestEntity"/>
<ref bean="secondInterceptor"></ref>
</mvc:interceptor>
</mvc:interceptors>
<!-- /*匹配一层,/**匹配所有层 -->
② 拦截器的三个抽象方法
preHandle:控制器方法执行之前执行preHandle(),其boolean类型的返回值表示是否拦截或放行,返回true为放行,即调用控制器方法;返回false表示拦截,即不调用控制器方法
postHandle:控制器方法执行之后执行postHandle()
afterCompletion:处理完视图和模型数据,渲染视图完毕之后执行afterCompletion()
// 此时类名首字母小写就是bean的id
@Component
public class FirstInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("FirstInterceptor-->preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("FirstInterceptor-->postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("FirstInterceptor-->afterCompletion");
}
}
③ 多个拦截器的执行顺序
a. 若每个拦截器的preHandle()都返回true
此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件的配置顺序有关:
preHandle()会按照配置的顺序执行,而postHandle()和afterCompletion()会按照配置的反序执行
b. 若某个拦截器的preHandle()返回了false
preHandle()返回false和它之前的拦截器的preHandle()都会执行,postHandle()都不执行,返回false 的拦截器之前的拦截器的afterCompletion()会执行
4.7 异常处理器
① 基于配置的异常处理
SpringMVC提供了一个处理控制器方法执行过程中所出现的异常的接口:HandlerExceptionResolver HandlerExceptionResolver接口的实现类有:DefaultHandlerExceptionResolver和 SimpleMappingExceptionResolver
SpringMVC提供了自定义的异常处理器SimpleMappingExceptionResolver,使用方式:
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<!--key设置要处理的异常,value设置出现该异常时要跳转的页面所对应的逻辑视图-->
<prop key="java.lang.ArithmeticException">error</prop>
<prop key="其他异常">其他页面</prop>
</props>
</property>
<!--设置共享在请求域中的异常信息的属性名-->
<property name="exceptionAttribute" value="ex"></property>
</bean>
② 基于注解的异常处理
@ControllerAdvice //将当前类标识为异常处理的组件
public class ExceptionController {
@ExceptionHandler(ArithmeticException.class) //用于设置所标识方法处理的异常
public String handleArithmeticException(Exception ex, Model model){
model.addAttribute("ex", ex);
return "error";
}
}
// ex表示当前请求处理中出现的异常对象
五.搭建MyBatis环境
核心配置文件 — 如何连接数据库
映射文件 — 如何操作数据库 即SQL语句
5.1 创建属性文件
<!-- jdbc.properties -->
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm_learn?serveTimezone=UTC
jdbc.username=root
jdbc.password=root
5.2 创建核心配置文件
<!-- mybatis-config.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--开启驼峰命名转换-->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<plugins>
<!--配置分页插件-->
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
</configuration>
数据源,类型别名所对应的包,以及映射文件位置在spring中设置
5.3 创建Mapper接口和映射文件
public interface EmployeeMapper {
List<Employee> getEmployeePage();
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.ssm.mapper.EmployeeMapper">
<select id="getEmployeePage" resultType="Employee">
select * from t_emp
</select>
</mapper>
5.4 创建mybatis日志文件
<!-- log4j.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<param name="Encoding" value="UTF-8"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n"/>
</layout>
</appender>
<logger name="java.sql">
<level value="debug"/>
</logger>
<logger name="org.apache.ibatis">
<level value="info"/>
</logger>
<root>
<level value="debug"/>
<appender-ref ref="STDOUT"/>
</root>
</log4j:configuration>
六.配置spring.xml
<?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:tx="http://www.springframework.org/schema/tx"
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/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 扫描组件(除控制层) -->
<context:component-scan base-package="com.junn.ssm">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 引入jdbc.properties -->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!-- 配置Druid数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 开启事务的注解驱动 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- 配置用于创建SqlSessionFactory的工厂bean -->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 设置MyBatis配置文件的路径(可以不设置) -->
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<!-- 设置数据源 -->
<property name="dataSource" ref="dataSource"></property>
<!-- 设置类型别名所对应的包 -->
<property name="typeAliasesPackage" value="com.junn.ssm.pojo"></property>
</bean>
<!-- 配置mapper接口的扫描配置 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.junn.ssm.mapper"></property>
</bean>
</beans>
6.1 扫描组件
见4.1
6.2 引入jdbc.properties
数据库连接配置属性文件
6.3 Druid数据源
连接数据库
6.4 开启事务
① 添加事务配置
声明式事务的配置步骤: 1,在Spring的配置文件中配置事务管理器 2、开启事务的注解驱动
<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="druidDataSource"></property>
</bean>
<!--
开启事务的注解驱动
将使用@Transactional注解所标识的方法或类中所有的方法使用事务进行管理
transaction- manager属性设置事务管理器的id
若事务管理器的bean的id默认为transactionManager,则该属性可以不写
-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
② 添加事务注解
因为service层表示业务逻辑层,一个方法表示一个完成的功能,
因此处理事务一般在service层处理在BookServiceImpl的buybook()添加注解@Transactional
@Transactional注解标识的位置: 1, 标识在方法上 2, 标识在类上,则类中所有的方法都会被事务管理 在需要被事务管理的方法上,添加@Transactional注解, 该方法就会被事务管理
@Service
public class BookServiceImpl implements BookService {
@Autowired
private BookDao bookDao;
@Override
@Transactional
public void buyBook(Integer userId, Integer bookId) {
//查询图书价格
Integer price = bookDao.getPriceByBookId(bookId);
//更新图书库存
bookDao.updateStock(bookId);
//更新用户余额
bookDao.updateBalance(userId, price);
}
}
③ 测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:tx-annotation.xml")
public class TxByAnnotationTest {
@Autowired
private BookController bookController;
@Test
public void testBuyBook(){
bookController.buyBook(1, 1);
}
}
6.5 自动装配获取mapper对象
<!-- 配置用于创建SqlSessionFactory的工厂bean -->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 设置MyBatis配置文件的路径(可以不设置) -->
<property name="configLocation" value="classpath:mybatis-config.xml">
</property>
<!-- 设置数据源 -->
<property name="dataSource" ref="dataSource"></property>
<!-- 设置类型别名所对应的包 -->
<property name="typeAliasesPackage" value="com.atguigu.ssm.pojo">
</property>
<!--
设置映射文件的路径
若映射文件所在路径和mapper接口所在路径一致,则不需要设置
-->
<!--
<property name="mapperLocations" value="classpath:mapper/*.xml"></property>
-->
</bean>
<!--
配置mapper接口的扫描配置
由mybatis-spring提供,可以将指定包下所有的mapper接口创建动态代理
并将这些动态代理作为IOC容器的bean管理
-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.atguigu.ssm.mapper"></property>
</bean>
@Service
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
private EmployeeMapper employeeMapper;
@Override
public PageInfo<Employee> getEmployeePage(Integer pageNum) {
PageHelper.startPage(pageNum, 8);
List<Employee> list = employeeMapper.getEmployeePage();
PageInfo<Employee> page = new PageInfo<>(list, 5);
return page;
}
}