0 、概述
服务器端分成三层架构。
一、环境搭建
1.1 Maven环境的创建
-
导入坐标依赖
<!-- 版本锁定 --> <spring.version>5.0.2.RELEASE</spring.version> <!-- 配置依赖 --> <dependencies> <!-- spring IOC --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <!-- spring web --> <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>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency> </dependencies>
-
配置核心的控制器(类似
servlet
类 –dispatcherServlet
)<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Archetype Created Web Application</display-name> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
当<url-pattern>/</url-pattern>
时,默认就是拦截所有路径连静态资源也不能访问。但是Controller
中配置@RequestMapping
的路径是不会被拦截的,配置了@RequestMapping
就相当于在web.xml
中注<servlet>
。
1.2 第一个执行程序
1.2.1 引入SpringMVC配置文件
在resources
下新建springMVC.XML
配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
</beans>
1.2.2 编写控制器
// 控制器
@Controller
public class HelloController {
@RequestMapping("/hello") // 请求的资源路径
public String sayHello() {
System.out.println("Hello SpringMVC");
return "success"; // 需要跳转的页面,默认jsp文件名
}
}
- 控制器类配置
@Controller
注解,表明是控制器。 - 在具体的方法上配置
@RequestMapping
注解,参数即为访问时的资源路径 return
中的字符串,方法执行完需要跳转的页面
1.2.3 完善springMVC.xml
配置文件
- 控制器中加入注解,那么就需要配置需要扫描的包;
- 配置文件解析器,创建
IOC
容器对象,由Tomcat
负责调用; - 配置
spring
开启注解MVC
的支持
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置spring创建容器时要扫描的包 -->
<context:component-scan base-package="cn.lizhi"></context:component-scan>
<!-- 配置视图解析器 Ioc容器对象,由tomcat调用-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 文件具体所在的目录 -->
<property name="prefix" value="/WEB-INF/pages/"></property>
<!-- 文件解析的类型(后缀名) -->
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 配置spring开启注解mvc的支持 -->
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
WEB-INF
目录下的内容是对客户端不可见,只对服务端可见,即客户端不能直接对其进行访问。
1.2.4 完善web.xml
配置文件
由于上方的springMVC.XML
配置文件时在resources
目录下的,我们启动的是web
项目,就需要将该配置文件加载进Tomcat
服务器进行读取。
即:配置Servlet
的初始化参数,读取springMVC
的配置文件,创建spring
容器,用于加载配置文件。
当MVC
配置文件加载成功,那么其中的扫描就能够成功,继而将控制器中的类加载成对象。
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置Servlet的初始化参数,读取springMVC的配置文件,创建spring容器,用于加载配置文件
MVC配置文件加载成功,那么其中的扫描就成功,继而到控制器中类加载成对象
-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springMVC.xml</param-value>
</init-param>
<!-- 服务器在启动时,就加载资源
配置servlet的对象的创建时间点:应用加载时创建。-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<!-- 配置资源路径/表明所有的资源皆可被访问到 -->
<url-pattern>/</url-pattern>
<!-- 表明只有hello的资源路径可以被访问到
<url-pattern>/hello</url-pattern>
-->
</servlet-mapping>
</web-app>
二、Spring MVC 详解
2.1 执行过程及组件分析
2.1.1 执行过程
- 当启动
Tomcat
服务器的时候,因为配置了load-on-startup
标签,所以会创建DispatcherServlet
对象,就会加载springmvc.xml
配置文件。这里是服务器启动,应用被加载。读取到web.xml
中的配置创建spring
容器并且初始化容器中的对象。 - 在
springmvc.xml
配置文件中开启了注解扫描,那么相应的controller
对象(HelloController
)对象就会被创建。 - 从
index.jsp
发送请求,请求会先到达DispatcherServlet
核心控制器,根据配置@RequestMapping
注解找到执行的具体方法。浏览器发送请求,被DispatcherServlet
捕获,该Servlet
并不处理请求,而是把请求转发出去。转发的路径是根据请求URL
,匹配@RequestMapping
中的内容。 - 根据执行方法的返回值,再根据配置的视图解析器,去指定的目录下查找指定名称的
JSP
文件。即:根据方法的返回值,借助InternalResourceViewResolver
找到对应的结果视图。 Tomcat
服务器渲染页面,做出响应。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IfavgG6R-1617344854362)(https://s3.ax1x.com/2020/12/23/r6iFFs.png)]
2.1.2 组件分析
-
DispatcherServlet
:前端控制器用户请求到达前端控制器,它就相当于
MVC
模式中的c
,dispatcherServlet
是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet
的存在降低了组件之间的耦合性。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iavVPVW8-1617344854369)(https://s3.ax1x.com/2020/12/23/r6iCwQ.png)]
-
HandlerMapping
:处理器映射器HandlderMapping
负责根据用户请求找到Handler
,即处理器,SpringMVC
提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。 -
Handler
:处理器它就是开发中编写的具体业务控制器。由
DispatcherServlet
把用户请求转发到Handler。由Handler
对具体的用户请求进行处理。 -
Handler
:处理器适配器通过
HandlerAdapter
对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。 -
View Resolver
:视图解析器View Resolver
负责将处理结果生成View
视图,View Resolver
首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View
视图对象,最后对View
进行渲染将处理结果通过页面展示给用户。 -
View
:视图将数据视图展示给客户端,即用户。
2.1.3 <mvc:annotation-driver>
说明
在SpringMVC
的各个组件中,处理器映射器、处理器适配器、视图解析器成为SpringMVC
的三大组件。使用<mvc:annotation-driver>
自动加载RequestMappingHandlerMapping
(处理器映射器)和RequestMappingHandlerAdapter
(处理器适配器)。
2.2 常用注解说明
2.2.1 RequestMapping
作用:用于建立请求URL
和处理请求方法之间的对应关系。
2.2.2 RequestParam
作用:把请求中指定名称的参数给控制器中的形参赋值。(适用于请求名称与属性名不相同的情况)
属性:
value
:请求参数的名称。required
:请求参数中是否必须提供此参数。默认值:true
。表示必须提供,如果不提供将报错。
@RequestMapping("/useRequestParam")
public String useRequestParam(@RequestParam("name")String username,@RequestParam(value="age",required=false)Integer age){
System.out.println(username+","+age);
return "success";
}
2.2.3 RequestBody
作用:用于获取请求体内容。直接使用得到是key=value&key=value...
结构的数据。get
请求方式不适用。
属性:
required
:是否必须有请求体。默认值是:true
。当取值是true
时,get
请求方式会报错。如果取值为false
,get
请求得到是null
。
@RequestMapping("/useRequestBody")
public String useRequestBody(@RequestBody(required=false) String body){
System.out.println(body);
return "success";
}
2.2.4 PathVariable
作用:用于绑定url
中的占位符。例如:请求url
中 /delete/{id}
,这个{id}
就是url
占位符。url
支持占位符是spring3.0
之后加入的。是springmvc
支持rest
风格URL
的一个重要标志。
属性:
value
:用于指定url
中占位符名称。required
:是否必须提供占位符。
重点:restful
风格。
@RequestMapping("/usePathVariable/{id}")
public String usePathVariable(@PathVariable("id") Integer id){
System.out.println(id);
return "success";
}
2.2.5 RequestHeader
作用:用于获取请求消息头
属性:
value
:提供消息头名称,用于指定获取消息头中的哪一部分。required
:是否必须有此消息头。
@RequestMapping("/useRequestHeader")
public String useRequestHeader(@RequestHeader(value="Accept-Language",
required=false)String requestHeader){
System.out.println(requestHeader);
return "success";
}
将请求头内容的信息封装到requestHeader
参数中。
2.2.6 CookieValue
作用:用于把指定cookie
名称的值传入控制器方法参数。
属性:
value
:指定cookie
的名称。键值对的形式,通过键来获取到它的值。required
:是否必须有cookie
@RequestMapping("/useCookieValue")
public String useCookieValue(@CookieValue(value="JSESSIONID",required=false)
String cookieValue){
System.out.println(cookieValue);
return "success";
}
2.2.7 ModelAttribute
作用:该注解是SpringMVC4.3
版本以后新加入的。它可以用于修饰方法和参数。
出现在方法上,表示当前方法会在控制器的方法执行之前,先执行。它可以修饰没有返回值的方法,也可以修饰有具体返回值的方法。
出现在参数上,获取指定的数据给参数赋值。
属性:
value
:用于获取数据的key
。key
可以是POJO
的属性名称,也可以是Map
结构的key
。
应用场景:
当表单提交数据不是完整的实体类数据时,保证没有提交数据的字段使用数据库对象原来的数据。
例如:
当我们在编辑一个用户时,用户有一个创建信息字段,该字段的值是不允许被修改的。在提交表单数据时肯定没有此字段的内容,一旦更新会把该字段内容置为null
,此时就可以使用此注解解决问题。
示例1:
@ModelAttributepublic
public void showModel(User user) {
System.out.println("执行了showModel方法"+user.getUsername());
}
/***
接收请求的方法
* @param user* @return
*/
@RequestMapping("/testModelAttribute")
public String testModelAttribute(User user) {
System.out.println("执行了控制器的方法"+user.getUsername());
return "success";
}
即先执行showModel
方法,再执行控制器中的方法testModelAttribute
。
2.2.7.1 ModelAttribute 修饰方法带返回值
需求:修改用户信息,要求用户密码不能修改
前端代码:
<form action="springmvc/updateUser" method="post">
用户名称:<input type="text" name="username" ><br/>
用户年龄:<input type="text" name="age" ><br/>
<input type="submit" value="保存">
</form>
- 模拟查询数据库中用户信息
@ModelAttribute
public User showModel(String username) {
//模拟去数据库查询
User userByName = findUserByName(username);
System.out.println("执行了 showModel 方法"+userByName);
return userByName;
}
- 模拟修改用户方法
@RequestMapping("/updateUser")
public String testModelAttribute(User user) {
System.out.println("控制器中处理请求的方法:修改用户:"+user);
return "success";
}
- 模拟去数据库查询
private User findUserByName(String username) {
// 以下4句用来模拟数据库中的原有对象,即查询出来的对象
User user = new User();
user.setUsername(username);
user.setAge(19);
user.setPassword("123456");
return user;
}
首先通过前端请求,获取username
,而在showModel
方法中参数,就是由前端请求的参数username
。然后showModel
方法体中通过数据库查询对象,再将对象进行返回。返回的对象是数据中的相对应的原有对象。(类似过滤器,后续在控制器中将需要修改的值,进行修改,不变的值,就不需要再次改动)。
2.2.7.2 ModelAttribute 修饰方法不带返回值
需求:修改用户信息,要求用户的密码不能修改
- 前端代码
<!-- 修改用户信息 -->
<form action="springmvc/updateUser" method="post">
用户名称:<input type="text" name="username" ><br/>
用户年龄:<input type="text" name="age" ><br/>
<input type="submit" value="保存">
</form>
- 查询数据库中用户信息-- 模拟去数据库查询
@ModelAttribute
public void showModel(String username,Map<String,User> map) {
//模拟去数据库查询
User user = findUserByName(username);
System.out.println("执行了 showModel 方法"+user);
map.put("abc",user);
}
- 模拟修改用户方法
@RequestMapping("/updateUser")
public String testModelAttribute(@ModelAttribute("abc")User user) {
System.out.println("控制器中处理请求的方法:修改用户:"+user);
return "success";
}
- 模拟去数据库查询
private User findUserByName(String username) {
User user = new User();
user.setUsername(username);
user.setAge(19);
user.setPassword("123456");
return user;
}
第二种不带返回值的方式更容易理解,即将原有的对象存放在map
集合中,再通过注解,获取指定(根据map
中的键)的数据给参数赋值。最后,将前端请求的参数对应的封装到这个参数中,就能够保证这个参数对象的所有属性都能够有值。
2.2.8 SessionAttributes
作用:用于多次执行控制器方法间的参数共享。只能作用在类对象(Class
)上。
属性:
value
:用于指定存入的属性名称type
:用于指定存入的数据类型
- 前端代码
<!-- SessionAttribute 注解的使用 -->
<a href="springmvc/testPut">存入 SessionAttribute</a> <hr/>
<a href="springmvc/testGet">取出 SessionAttribute</a> <hr/>
<a href="springmvc/testClean">清除 SessionAttribute</a>
- 控制器中的代码
@Controller("sessionAttributeController")
@RequestMapping("/springmvc")
@SessionAttributes(value ={"username","password"},types={Integer.class})
public class SessionAttributeController {
/**
* 把数据存入 SessionAttribute
* @param model
* @return
* Model 是 spring 提供的一个接口,该接口有一个实现类 ExtendedModelMap
* 该类继承了 ModelMap,而 ModelMap 就是 LinkedHashMap 子类
*/
@RequestMapping("/testPut")
public String testPut(Model model){
model.addAttribute("username", "泰斯特");
model.addAttribute("password","123456");
model.addAttribute("age", 31);
//跳转之前将数据保存到 username、password 和 age 中,因为注解@SessionAttribute 中有这几个参数
return "success";
}
@RequestMapping("/testGet")
public String testGet(ModelMap model){
System.out.println(model.get("username")+";"+model.get("password")+";"+model.get("a
ge"));
return "success";
}
@RequestMapping("/testClean")
public String complete(SessionStatus sessionStatus){
sessionStatus.setComplete();
return "success";
}
}
通过model
对象进行值的存储操作,底层会将值存储在request
域中。而又使用@SessionAttributes
注解,具体有@SessionAttributes(value ={"username","password"},types={Integer.class})
。此时通过values
数组的指定 – username
、password
,则表明model
在存储操作时,不仅会将这两个的值存储在request
域对象中,同时也会存储在session
域对象中。
取值时,使用的model
实现类 – ModelMap
。
删除时,使用SessionStatus
。
2.3 请求参数的绑定
前端向后端进行请求时,表单中请求参数都是基于key=value
的。SpringMVC
绑定请求参数的过程是通过把表单请求参数,作为控制器中方法参数进行绑定的。
2.3.1 支持的数据类型
-
基本数据类型
- 基本数据类型
String
类型
-
POJO
类型参数(实现序列化接口)- 实体类
- 关联的实体类
-
数组和集合类型参数
包括
List
结构和Map
结构的集合(包括数组)
SpringMVC
绑定请求参数是自动实现的,但是想要使用,必须遵循使用要求。
2.3.2 使用要求
- 基本数据类型或者是String类型:
要求我们的参数名称必须和控制器中方法的形参名称保持一致。(严格区分大小写)
POJO
类型或者及其关联对象
如果表单中参数名称和POJO
类的属性名称保持一致。并且控制器方法的参数类型是POJO
类型。
-
如果是集合类型
-
第一种
要求集合类型的请求参数必须在
POJO
中。在表单中请求参数名称要和POJO
中集合属性名称相同。给
List
集合中的元素赋值,使用下标。给
Map
集合中的元素赋值,使用键值对。 -
第二种
接收的请求参数是
json
格式数据。需要借助一个注解实现。
-
-
SpringMVC
可以实现一些数据类型自动转换。其内置转换器全部都在:org.springframework.core.convert.support
包下。
2.3.3 使用实例
2.3.3.1 POJO类型作为参数
- 实体类代码
public class Account implements Serializable {
private Integer accountId;
private String accountName;
private Float money;
private Address address;
// getters and setters 方法
// toString方法
}
以上是Account
类。其中关联Address
类:
package cn.lizhi.domain;
public class Address {
private String provinceName;
private String cityName;
// getters and setters 方法
// toString方法
}
- 前端代码
<form action="account/saveAccount" method="post">
账户名称:<input type="text" name="name" ><br/>
账户金额:<input type="text" name="money" ><br/>
账户省份:<input type="text" name="address.provinceName" ><br/>
账户城市:<input type="text" name="address.cityName" ><br/>
<input type="submit" value="保存">
</form>
通过对象.属性
的方式进行赋值。
- 控制器代码
@RequestMapping("/saveAccount")
public String saveAccount(Account account) {
System.out.println("保存了账户。。。。"+account);
return "success";
}
2.3.3.2 POJO类中包含集合类型参数
- 实体类 –
User
类
package cn.lizhi.domain;
import java.util.Date;
import java.util.List;
import java.util.Map;
public class User {
private String username;
private String password;
private Integer age;
private Date date;
private List<Account> accounts;
private Map<String,Account> accountMap;
// getter and setter
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", age=" + age +
", date=" + date +
", accounts=" + accounts +
", accountMap=" + accountMap +
'}';
}
}
- 前端代码
<!-- POJO 类包含集合类型演示 -->
<form action="account/updateAccount" method="post">
用户名称:<input type="text" name="username" ><br/>
用户密码:<input type="password" name="password" ><br/>
用户年龄:<input type="text" name="age" ><br/>
账户 1 名称:<input type="text" name="accounts[0].name" ><br/>
账户 1 金额:<input type="text" name="accounts[0].money" ><br/>
账户 2 名称:<input type="text" name="accounts[1].name" ><br/>
账户 2 金额:<input type="text" name="accounts[1].money" ><br/>
账户 3 名称:<input type="text" name="accountMap['one'].name" ><br/>
账户 3 金额:<input type="text" name="accountMap['one'].money" ><br/>
账户 4 名称:<input type="text" name="accountMap['two'].name" ><br/>
账户 4 金额:<input type="text" name="accountMap['two'].money" ><br/>
<input type="submit" value="保存">
</form>
集合、列表赋值的方式。三要素:属性
、下标
、参数(属性)
- 控制器代码
@RequestMapping("/updateAccount")
public String updateAccount(User user) {
System.out.println("更新了账户。。。。"+user);
return "success";
}
2.4 请求参数乱码问题
在tomcat8
以后get
请求方式,中文正常显示;post
请求方式,中文会出现乱码问题。
在之前的serlvet
学习中,对乱码解决的方式,是通过Filter
过滤器。而现在SpringMVC
提供好现有的类供我们使用。
首先post
请求方式,在web.xml
中配置一个过滤器。
<!-- 配置解决中文乱码的过滤器 -->
<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>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<!-- 过滤所有请求 -->
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
如果想不过滤静态资源,在 Springmvc
的配置文件中可以配置,静态资源不过滤:
<!-- location 表示路径,mapping 表示文件,**表示该目录下的文件以及子目录的文件 -->
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/images/" mapping="/images/**"/>
<mvc:resources location="/scripts/" mapping="/javascript/**"/>
get
请求方式:
tomcat
对GET
和POST
请求处理方式是不同的,GET
请求的编码问题,要改tomcat
的server.xml
配置文件,如下:
<Connector connectionTimeout="20000" port="8080"
protocol="HTTP/1.1" redirectPort="8443"/>
改为:
<Connector connectionTimeout="20000" port="8080"
protocol="HTTP/1.1" redirectPort="8443"
useBodyEncodingForURI="true"/>
<!-- 如果遇到 ajax 请求仍然乱码,请把:-->
useBodyEncodingForURI="true"改为 URIEncoding="UTF-8"
2.5 自定义类型转换器
例如,在前端输入日期格式时:
<!-- 特殊情况之:类型转换问题 -->
<a href="account/deleteAccount?date=2018-01-01">根据日期删除账户</a>
可以看出,请求参数中,date=2018-01-01
。
当我们在后端接收到请求时:
@RequestMapping("/deleteAccount")
public String deleteAccount(String date) {
System.out.println("删除了账户:" + date);
return "success";
}
输出:删除了账户:2018-01-01
。如果当我们将接收参数的类型改为Date
类型时:
@RequestMapping("/deleteAccount")
public String deleteAccount(Date date) {
System.out.println("删除了账户:" + date);
return "success";
}
此时,前端再次请求时,会报400
。
下面便是我们自定义类型转化的方式:
首先,定义一个类,实现Convertet
接口,该接口有两个泛型。
public interface Converter<S, T> {//S:表示接受的类型,T:表示目标类型
/**
* 实现类型转换的方法
*/
@Nullable
T convert(S source);
}
其中,S
表示接受的类型,T
表示目标类型。
其实现类:
public class StringToDate implements Converter<String, Date> {
@Override
public Date convert(String source) {
if (source == null || source == "") {
throw new RuntimeException("请输入日期");
}
SimpleDateFormat format = new SimpleDateFormat("yyyy-mm-dd");
try {
Date data = format.parse(source);
return data;
} catch (ParseException e) {
throw new RuntimeException("请输入正确的日期格式");
}
}
}
其次,在Spring
配置文件中配置类型转换器。
Spring
配置类型转换器的机制是,将自定义的转换器注册到类型转换服务中去。
<bean id="converterService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<!-- 给工厂注入一个新的类型转换器 -->
<property name="converters">
<array>
<!-- 配置自定义类型转换器 -->
<bean class="cn.lizhi.utils.StringToDate"/>
</array>
</property>
</bean>
<!-- 配置spring开启注解mvc的支持 -->
<mvc:annotation-driven conversion-service="converterService"></mvc:annotation-driven>
通过查看源码:
public class ConversionServiceFactoryBean implements FactoryBean<ConversionService>, InitializingBean {
@Nullable
private Set<?> converters;
@Nullable
private GenericConversionService conversionService;
public ConversionServiceFactoryBean() {
}
public void setConverters(Set<?> converters) {
this.converters = converters;
}
public void afterPropertiesSet() {
this.conversionService = this.createConversionService();
ConversionServiceFactory.registerConverters(this.converters, this.conversionService);
}
protected GenericConversionService createConversionService() {
return new DefaultConversionService();
}
@Nullable
public ConversionService getObject() {
return this.conversionService;
}
public Class<? extends ConversionService> getObjectType() {
return GenericConversionService.class;
}
public boolean isSingleton() {
return true;
}
}
其中converters
是集合类型,并且有setter
方法,通过上方的spring
配置文件,给工厂注入一个新的类型转换器(不会覆盖原有的转换器)。
这样,在我们后面的使用中,便能够识别并对应转换成我们相应数据格式。
总之,实现转换器的方法以及对spring
的配置,就是在原有的转换器集合中,再加入一种我们自己编写的转换器,以供我们使用。
2.6 响应数据
2.6.1 方法返回值的分类
2.6.1.1 String 类型
Controller
方法返回字符串可以指定逻辑视图的名称,根据视图解析器为物理视图的地址。
即为前面所写的常规的返回值为String
的方法,返回值为所需要跳转的物理视图的名称(即为跳转页面名称 -->地址)。
@RequestMapping(value="/hello")
public String sayHello() {
System.out.println("Hello SpringMVC!!");
// 跳转到XX页面 -- 跳转到success页面
return "success";
}
模拟应用 – 模拟对数据库中的数据进行查询
- 前端代码
index.jsp页面
<!-- 模拟用户的修改 -->
<h3>修改用户</h3>
<a href="/user/initUpdate">模拟用户修改</a>
模拟update.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>首页</title>
</head>
<body>
<!-- 模拟用户的修改 -->
<h3>修改用户</h3>
<form action="/user/initUpdate" method="post">
姓名:<input type="text" name="username" value="${user.username}"><br>
密码:<input type="text" name="password" value="${user.password}"><br>
金额:<input type="text" name="money" value="${user.money}"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
- 后端控制器代码
@Controller("userController")
@RequestMapping("/user")
public class UserController {
@RequestMapping("/initUpdate")
public String initUpdate(Model model) {
// 模拟从数据库中查询数据
User user = new User();
user.setUsername("张三");
user.setPassword("123456");
user.setMoney(123d);
model.addAttribute("user", user);
return "update";
}
}
返回值是update
,即最后跳转到update
页面。
2.6.1.2 void类型
如果控制器的方法返回值是void
,在执行程序报404的异常,默认查找jsp
页面没有找到。
Type Status Report
消息 /WEB-INF/pages/user/initUpdate.jsp
描述 源服务器未能找到目标资源的表示或者是不愿公开一个已经存在的资源表示。
从上面的错误信息可以看出,它会默认跳转到控制器中@RequestMapping("/example")
中initUpdate
的页面。
在SpringMVC
中Servlet
原始API
可以作为控制器中方法的参数,即在controller
方法形参上可以定义request
和response
,使用request
或response
指定相应结果。
-
使用
request
(即为存储转发)转向页面request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request, response);
在存储转发中不需要写虚拟目录,但这里的资源路径需要写
webApp
中的全路径,没有像前面只写一个success
的原因是,前一种是交给了视图解析器进行管理;而这里没有用到视图解析器,是单纯由request
进行实现,故需要写出资源的全路径。 -
使用
response
进行页面的重定向response.sendRedirect(request.getContextPath() + "/page.jsp");
需要加上虚拟目录。
-
通过
response
指定响应结果,例如响应json
数据:response.setCharacterEncoding("utf-8"); response.setContentType("application/json;charset=utf-8"); response.getWriter().write("json串");
2.6.1.3 关键字的转发或重定向
使用关键字进行转发或重定向时,Spring
不会再通过视图解析器帮我们解析路径,需要我们自己手动配置。即就像上一小结中,资源路径需要写全。
Forward
转发
controller
方法在提供了String
类型的返回值之后,默认就是请求转发。当然,我们可以手动进行设置:
@RequestMapping("/testForward")
public String testForward() {
System.out.println("test1方法执行了...");
return "forward:/WEB-INF/pages/success.jsp";
}
如果用了forward:
,则路径必须写成实际视图url
,不能写逻辑视图。
它相当于它相当于request.getRequestDispatcher("**url**").forward(request,response)
。使用请求转发,既可以转发到jsp
(到视图解析器中),也可以转发到其他的控制器方法。
Redirect
重定向
controller
方法提供了一个String
类型返回值之后,它需要在返回值里使用:redirect:
@RequestMapping("/testRedirect")
public String testRedirect() {
System.out.println("testRedirect方法执行了...");
// return "redirect:testForward"; // 重定向至另一个servlet地址
return "redirect:/index.jsp"; // 重定向至jsp页面
}
它相当于response.sendRedirect(url)
。需要注意的是,如果是重定向到jsp
页面,则jsp
页面不能写在WEB-INF
目录中,否则无法找到。
原因:
重定向是客户端的,而转发是服务端内部的。
重定向是让客户端去访问重定向的地址,而WEB-INF下的文件是不能通过外部访问的!
2.6.1.4 ResponseBody响应json数据
作用:该注解用于将Controller
的方法返回的对象,通过HttpMessageConverter
接口转换为指定格式的数据。如:json
、xml
等,通过Response
响应给客户端。
需求:使用@ResponseBody
注解实现将controller
方法返回对象转换为json
响应给客户端。
前置:SpringMVC
默认用MappingJacksonHttpMessageConverter
对json
数据进行转换,需要加入jackson
的包。我们的项目中通过导入依赖的方法进行包的管理。
<!-- 对json处理的包,即能够使用@ResponseBody -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
需要配置前端控制器不拦截静态资源。
DispatcherServlet
会拦截到所有的资源,导致一个问题就是静态资源(img、css、js)也会被拦截到,从而
不能被使用。解决问题就是需要配置静态资源不进行拦截,在springmvc.xml
配置文件添加如下配置:
<!-- 设置静态资源不过滤 -->
<mvc:resources location="/css/" mapping="/css/**"/>
<!-- 样式 -->
<mvc:resources location="/images/" mapping="/images/**"/>
<!-- 图片 -->
<mvc:resources location="/js/" mapping="/js/**"/> <!-- javascript -->
其中,mvc:resources
标签配置不过滤谁。
location
元素表示webapp
目录下的包下的所有文件.mapping
元素表示以/static
开头的所有请求路径,如/static/a
或者/static/a/b
.
客户端发送ajax
的请求,传的是json
字符串,后端把json
字符串封装到user
对象中。
响应:将对象转换成json
字符串。
- 前端部分代码
<input type="button" value="异步请求测试" id="testJson">
<script>
$(function () {
$("#testJson").click(function () {
$.ajax({
type: "post",
url: "${pageContext.request.contextPath}/user/testResponseBody",
contentType: "application/json;charset=utf-8", // 发送信息至服务器时内容编码类型
data: '{"username":"张三","password":"123","money":123}', // 发送的json数据
dataType: "json", // 服务器返回的数据类型 -- json
success: function (data) {
alert(data)
}
});
});
})
</script>
- 控制器中的代码
@RequestMapping("/testResponseBody")
public @ResponseBody User testResponseBody(@RequestBody User user) {
System.out.println("异步请求:" + user);
return user;
}
在控制器中的代码,其中@RequestBody
将前端发送的ajax
请求的json
格式数据封装成JavaBean
。@ResponseBody
将后端返回值JavaBean
对象,格式化成json
数据类型返回给客户端,直接响应。
总结:首先通过@RequestBody
获取请求体数据,将前端请求的json
字符穿转换成JavaBean
对象,最后使用@ResponseBody
注解把JavaBean
对面转换成Json
字符串,直接响应。
2.6.1.5 ModelAndView对象
ModelAndView
对象是Spring
提供的一个对象,可以用来调整具体的JSP
视图,即可以用作控制方法的返回值。该对象中有两个方法:
方法1:addObject
public ModelAndView addObject(String attributeName, Object attributeValue) {
this.getModelMap().addAttribute(attributeName, attributeValue);
return this;
}
添加模型到该对象中,通过上面的代码可以看出,和前面所讲的请求参数封装中用到的对象是同一个。即jsp
页面中同样可以使用EL
表达式从request
域中获取值。
方法2:setViewName
public void setViewName(@Nullable String viewName) {
this.view = viewName;
}
用于设置逻辑视图名称,视图解析器会根据名称前往指定的视图。这也ModelAndView
和Model
最大的不同,它可以设置跳转的逻辑视图名称。
使用示例:
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView() {
System.out.println("testModelAndView...");
ModelAndView mv = new ModelAndView();
mv.addObject("username", "张三");
mv.setViewName("success");
return mv;
}
- 可以将对象存储到
request
域中。mv.addObject("key",value)
- 可以存储跳转到哪个页面中。
mv.setViewName("success")
– 选择视图解析器,进行解析。
前端代码:可以直接通过EL
表达式进行值的获取,${username} --> 张三
。
ModelAndView
和Model
两者的不同:
Model
是每次请求中都存在的默认参数,利用其addAttribute()
方法即可将服务器的值传递到jsp
页面中;ModelAndView
包含model
和view
两部分,使用时需要自己实例化,利用ModelMap
用来传值,也可以设置view
的名称。- 总而言之,就是
ModelAndView
除了同Model
一样包含存储的键值外,它还存储着跳转页面的名称地址,直接将ModelAndView
对象整体作为返回值,其对象中存储的地址自动由SpringMVC
进行视图解析。
2.7 SpringMVC实现文件上传
文件上传的前提:
form
表单的enctype
取值必须是:multipart/form-data
。默认值是:application/x-www-form-urlencoded
。enctype
:是表单请求正文的类型。method
属性取值必须是POST
- 提供一个文件选择域
<input type="file"/>
文件上传的原理:
当form 表单的enctype取值不是默认值后,request.getParameter()将失效。
enctype=”application/x-www-form-urlencoded”时,form 表单的正文内容是:
key=value&key=value&key=value
当form 表单的enctype取值为Mutilpart/form-data时,请求正文内容就变成:
每一部分都是 MIME 类型描述的正文
-----------------------------7de1a433602ac 分界符
Content-Disposition: form-data; name="userName" 协议头
aaa 协议的正文
-----------------------------7de1a433602ac
Content-Disposition: form-data; name="file";
filename="C:\Users\zhy\Desktop\fileupload_demofile\b.txt"
Content-Type: text/plain 协议的类型(MIME 类型)
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-----------------------------7de1a433602ac--
使用Commons-fileupload
组件实现文件上传,需要导入该组件相应的支撑jar
包:
Commons-fileupload
Commons-io
Commons-io
不属于文件上传组件的开发jar
文件,但Commons-fileupload
组件从1.1版本开始,它工作时需要commons-io
包的支持。
导入依赖:
<!-- 文件上传依赖 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
前端页面:
<form action="/user/testUpload" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload"/><br>
<input type="button" value="文件上传"/>
</form>
后端页面:
@RequestMapping("/testUpload")
public String testUpload(HttpServletRequest request) throws Exception {
// 先获取到要上传的文件目录 - 即需要上传的目录设置成uploads
String path = request.getSession().getServletContext().getRealPath("/uploads");
// 创建File对象,用于向该路径下上传文件
File file = new File(path);
// 判断路径是否存在,若不存在则创建该路径
if (!file.exists()) {
file.mkdirs();
}
// 创建磁盘文件项工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload fileUpload = new ServletFileUpload(factory);
// 解析request对象
List<FileItem> list = fileUpload.parseRequest(request);
// 遍历
for (FileItem fileItem : list) {
// 判断文件项是普通字段,还是上传的文件
if (fileItem.isFormField()) {
continue;
} else {
// 上传文件
// 获取到上传文件的名称
String name = fileItem.getName();
String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
// 将文件名唯一化
name = uuid + "_" + name;
// 上传文件
fileItem.write(new File(file, name));
// 删除临时文件
fileItem.delete();
}
}
return "success";
}
备注:request.getSession().getServletContext()
获取servlet
容器对象(最大的域对象),也可以理解为项目真正部署到tomcat
时获得的tomcat
(服务器)对象。因为session
是服务器端对象。而request.getSession().getServletContext().getRealPath()
用于获取指定目录在服务器端所真正部署的路径。
2.7.1 SpringMVC传统方式的文件上传
SpringMVC
传统方式的文件上传,指的是我们上传的文件和访问的应用存在于同一台服务器上,并且上传完成以后,浏览器可能跳转。
SpringMVC
框架提供了MultipartFile
对象,该对象表示上传的文件,要求变量名称必须和表单file
标签的name
属性名称相同。
- 配置文件解析器
<!-- 配置文件解析器对象,要求id名称必须是multipartResolver -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 配置文件最大上传的byte -->
<property name="maxUploadSize" value="10485760"/>
</bean>
- 控制器代码
@RequestMapping("/testSpringMVCUpload")
public String testSpringMVCUpload(HttpServletRequest request, MultipartFile upload) throws IOException { // 参数upload要和前端中的name属性相同
System.out.println("SpringMVC方式的文件上传..");
String path = request.getSession().getServletContext().getRealPath("/uploads");
File file = new File(path);
if (!file.exists()) {
file.mkdirs();
}
// 获取到要上传文件的名称
String filename = upload.getOriginalFilename();
String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
filename = uuid + "_" + filename;
// 上传文件
upload.transferTo(new File(path,filename));
return "success";
}
SpringMVC
文件上传的主要步骤图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4LL5b6Qj-1617344854371)(https://s3.ax1x.com/2020/12/23/r6iPoj.png)]
首先前端请求,经过前端控制器将请求交给配置文件解析器,由相应的处理器进行处理。
2.7.2 SpringMVC跨服务器方式的文件上传
在实际开发中,我们可能会处理很多不同功能的服务器。例如:
- 应用服务器:负责部署我们的应用
- 数据库服务器:运行我们的数据库
- 缓存和消息服务器:负责处理大并发访问的缓存和消息
- 文件服务器:负责存储用户上传文件的服务器
即每个服务器负责每一个功能模块,而不是由一个服务器承担全部。分服务器处理的目的是让服务器各司其职,从而提高我们项目的运行效率。请求都由应用服务器进行处理转发,而需要的功能都分发到每个单独的服务器进行处理。见下图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bqv4NhP6-1617344854372)(https://s3.ax1x.com/2020/12/23/r6iSOS.png)]
现在模拟图片上传:
- 导入开发需要的
Jar
包
<!-- 跨服务器上传需要的依赖 -->
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>1.18.1</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.18.1</version>
</dependency>
- 需要在图片服务器上的
web.xml
添加如下配置文件
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>readonly</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
即:接收文件的目标服务器可以支持写入操作。
- 编写应用服务器端的控制器代码
@RequestMapping("/testSpringMVCUpload2")
public String testSpringMVCUpload2(MultipartFile upload) throws IOException {
System.out.println("SpringMVC跨服务器上传...");
// 定义图片服务器的请求路径
String path = "http://localhost:8088/picture/uploads/";
// 获取到上传文件的名称
String filename = upload.getOriginalFilename();
String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
filename = uuid + "_" + filename;
// 向图片服务器上传文件
// 创建客户端对象
Client client = Client.create();
// 连接图片服务器地址
WebResource webResource = client.resource(path + filename);
// 上传文件
webResource.put(String.class,upload.getBytes());
return "success";
}
2.8 SpringMVC的异常处理
系统中的异常包括两类:预期异常和运行时异常RuntimeException
,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。
系统的dao
、service
、controller
出现都通过throws Exception
向上抛出,最后由SpringMVC
前端控制器交由异常处理器进行异常处理。SpringMVC
异常处理见下图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3HMbCpyk-1617344854373)(https://s3.ax1x.com/2020/12/23/r6i9eg.png)]
控制器中捕获异常,从下向上抛出异常。
其目的是为了在出现异常的时候,跳到另外一个“友好”页面。模拟应用步骤:
-
自定义一个异常类。(继承
Exception
)package cn.lizhi.other; public class SysException extends Exception { // 用于定义异常信息 private String message; public SysException(String message) { this.message = message; } public SysException() { } @Override public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
-
编写异常处理器类。
public class SysExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler, Exception ex) { // 异常信息打印 ex.printStackTrace(); SysException sysException = null; if (ex instanceof SysException) { // 如果抛出的是自定义异常则直接转换 sysException = (SysException) ex; } else { //如果抛出的不是系统自定义异常则重新构造一个系统错误异常。 sysException = new SysException("系统错误,请于管理员联系"); } ModelAndView mv = new ModelAndView(); mv.addObject("message", sysException.getMessage()); mv.setViewName("error"); return mv; } }
即异常处理器,实现接口
HandlerExceptionResolver
,其中ex
参数表示接收到的异常对象。其中创建的ModelAndView
用于存入异常信息,键值对;再设置跳转路径。这里我们可以通过判断不同的异常类型跳转到不同的页面显示。
-
bean
配置文件中配置异常处理器类。<!-- 配置自定义异常处理器 --> <bean id="handlerExceptionResolver" class="cn.lizhi.other.SysExceptionResolver"/>
-
模拟出现异常
@RequestMapping("testException") public String testException() { System.out.println("模拟异常处理器的处理方式"); int i = 3 / 0; return "success"; }
页面出现结果 --> 系统错误,请于管理员联系
2.9 SpringMVC中的拦截器
Spring MVC
的处理器拦截器类似于 Servlet
开发中的过滤器 Filter
,用于对处理器进行预处理和后处理。
用户可以自己定义一些拦截器来实现特定的功能。
谈到拦截器,还要向大家提一个词——拦截器链(Interceptor Chain)
。拦截器链就是将拦截器按一定的顺
序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0Un6zn4g-1617344854374)(https://s3.ax1x.com/2020/12/23/r6Pzy8.png)]
说到这里,可能大家脑海中有了一个疑问,这不是我们之前学的过滤器吗?是的它和过滤器是有几分相似,但
是也有区别,接下来我们就来说说他们的区别:
-
过滤器是
servlet
规范中的一部分,任何java web
工程都可以使用。 -
拦截器是
SpringMVC
框架自己的,只有使用了SpringMVC
框架的工程才能用。 -
过滤器在
url-pattern
中配置了/*
之后,可以对所有要访问的资源拦截。 -
拦截器它是只会拦截访问的控制器方法,如果访问的是
jsp
,html
,css
,image
或者js
是不会进行拦
截的。 -
它也是
AOP
思想的具体应用。 -
我们要想自定义拦截器, 要求必须实现:
HandlerInterceptor
接口。 -
HandlerInterceptor
拦截的是请求地址,所以针对请求地址做一些验证、预处理等操作比较合适。
2.9.1 自定义拦截器步骤
-
创建类,实现
HandlerInterceptor
接口,需要重写需要的方法public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("拦截器执行了...前"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("拦截器执行了...后"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("页面跳转完毕后..."); } }
-
preHandler
方法是在
controller
方法执行前,进行拦截的方法;返回结果为true
表示放行,返回结果为false
表示拦截(配合条件判断使用),因为提供了request
、response
参数,所以可以使用转发或者重定向直接跳转到指定的页面。调用:按拦截器定义顺序调用
作用:如果决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是需要业务处理器进行处理,则返回
true
;如果不需要再调用其他的组件去处理请求,则返回false
。 -
postHandler
后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过
modelAndView
(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView
也可能为null
。按拦截器定义逆序调用;在拦截器链内所有拦截器返回成功后进行调用。
作用:在业务处理器处理完请求后,但是
DispatcherServlet
向客户端返回响应前被调用,处理ModelAndView
中的值。 -
afterCompletion
调用顺序:按拦截器定义逆序调用
调用时机:对拦截器链内所有拦截器内返回成功的拦截器才调用它的
afterCompletion
方法。作用:在业务处理器处理完请求后,但是
DispathcerServlet
向客户端返回响应前被调用。可以在该方法中进行一些资源清理的操作。在
view
视图渲染完毕以后执行,不能再进行页面的跳转。
一旦在
preHandler
方法中返回了false
(等同于出现了异常),后续的拦截器和controller
方法就都不会再执行,也不会再执行postHandler
方法,只会倒叙执行afterCompletion
方法。 -
拦截器只能拦截Controller
中的方法。
-
在
springmvc.xml
配置文件中配置拦截器类<!-- 配置拦截器 --> <mvc:interceptors> <mvc:interceptor> <!-- 哪些方法进行拦截 --> <mvc:mapping path="/user/*"/> <!-- 哪些方法不进行拦截 <mvc:exclude-mapping path=""/> --> <!-- 注册拦截器对象 --> <bean id="myInterceptor" class="cn.lizhi.utils.MyInterceptor"/> </mvc:interceptor> </mvc:interceptors>
可以配置多个拦截器,拦截器执行的顺序就是配置文件中注册的拦截器对象的顺序。
2.9.2 HandlerInterceptor接口中的方法总结
-
preHandle
方法是controller
方法执行前拦截的方法-
可以使用
request
或者response
跳转到指定的页面 -
return true
放行,执行下一个拦截器,如果没有拦截器,执行controller
中的方法。 -
return false
不放行,不会执行controller
中的方法。
-
-
postHandle
是controller
方法执行后执行的方法,在JSP
视图执行前。-
可以使用
request
或者response
跳转到指定的页面 -
如果指定了跳转的页面,那么
controller
方法跳转的页面将不会显示。
-
-
postHandle
方法是在JSP
执行后执行request
或者response
不能再跳转页面了
三、SSM框架的整合
核心思想:通过Spring
整合另外两个框架。
整合方式:配置文件加注解的方式。
整合的思路:
- 搭建整合的环境
Spring
的配置搭建完成Spring
整合SpringMVC
框架Spring
整合Mybatis
框架
3.1 环境搭建
- 数据库创建
create database ssm;
use ssm;
create table account(
id INTEGER PRIMARY key auto_increment,
name VARCHAR(32),
money DOUBLE(7,2)
);
pom.xml
依赖导入
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.lizhi</groupId>
<artifactId>SpringMVC_03</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>SpringMVC_03 Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>5.0.2.RELEASE</spring.version>
<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>
<mysql.version>5.1.6</mysql.version>
<mybatis.version>3.4.5</mybatis.version>
</properties>
<dependencies>
<!-- spring -->
<!-- 切入点表达式 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.8</version>
</dependency>
<!-- springAOP AOP核心功能,例如代理工厂等 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- springIOC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<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>
<!-- spring整合junit -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- 事务控制 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- SpringJDBC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- log start -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- log end -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<!-- 数据库连接池 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<finalName>SpringMVC_03</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<showWarnings>true</showWarnings>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
- 实体类编写
public class Account implements Serializable {
private Integer id;
private String name;
private Double money;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}
dao
接口编写
由于我们是使用Mybatis
框架,所以不需要编写其实现类,只需要写接口即可。
public interface AccountDao {
public void saveAccount(Account account);
public List<Account> findAll();
}
- 编写
Service
接口和实现类
public interface AccountService {
public void saveAccount(Account account);
public List<Account> findAll();
}
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
@Override
public void saveAccount(Account account) {
System.out.println("对用户进行保存...");
accountDao.saveAccount(account);
}
@Override
public List<Account> findAll() {
System.out.println("业务层:查询所有用户");
List<Account> accounts = accountDao.findAll();
return accounts;
}
}
3.2 Spring框架代码的编写
3.2.1 搭建和测试Spring的开发环境
-
在项目中创建
applicationContext.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:aop="http://www.springframework.org/schema/aop" 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 http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 开启注解扫描,要扫描的是service层和dao层的注解,要忽略web层注解,因为web层(Controller层)让SpringMVC框架去管理 --> <context:component-scan base-package="cn.lizhi"> <!-- 配置要忽略的注解 --> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> </beans>
-
编写测试方法,进行测试
@Test public void testSpring() { // 获取Spring容器 ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); AccountService accountService = ac.getBean("accountService", AccountService.class); accountService.findAll(); }
3.3 Spring整合SpringMVC框架
-
在
web.xml
中配置DispatcherServlet
前端控制器<!-- 配置前端控制器:服务器启动必须加载,需要加载springmvc.xml配置文件 --> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet </servlet-class> <!-- 配置初始化参数,创建完DispatcherServlet对象,加载springmvc.xml配置文件 --> <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>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
-
在
web.xml
中配置DispatcherServlet
过滤器解决中文乱码<!-- 配置解决中文乱码的过滤器 --> <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> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
-
创建
SpringMVC.xml
的配置文件,编写配置文件<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" 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 http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 扫描Controller(web层)的注解,别的不扫描 --> <context:component-scan base-package="cn.lizhi"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!-- 配置视图解析器 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- JSP文件所在的目录 --> <property name="prefix" value="/WEB-INF/pages/"/> <!-- 文件的后缀名 --> <property name="suffix" value=".jsp"/> </bean> <!-- 设置静态资源不过滤 --> <mvc:resources location="/css/" mapping="/css/**"/> <mvc:resources location="/images/" mapping="/images/**"/> <mvc:resources location="/js/" mapping="/js/**"/> <!-- 开启对SpringMVC注解的支持 --> <mvc:annotation-driven/> </beans>
-
测试
SpringMVC
的框架搭建是否成功-
编写
index.jsp
和list.jsp
前端页面<!-- index页面 --> <a href="/account/findAll" >查询所有</a> <!-- list页面 --> <h3>查询所有</h3>
-
编写控制器方法
@Controller("accountController") @RequestMapping("/account") public class AccountController { @RequestMapping("/findAll") public String findAll() { System.out.println("表面层:查询所有用户..."); return "list"; } }
结果:查询所有 。
-
-
Spring
整合SpringMVC
框架-
目的:在
Controller
层中能成功调用service
对象中的方法。 -
如果想在服务器启动的时候,获取到
Spring
的容器,那么就需要在项目启动的时候就去加载applicationContext.xml
的配置文件。在web.xml
中配置ContextLoaderListener
监听器(该监听器只能加载WEB-INF
目录下的applicationContext.xml
的配置文件)。监听器的作用:监听器的作用是监听一些事件的发生从而进行一些操作,比如监听
ServletContext
,HttpSession
的创建,销毁,从而执行一些初始化加载配置文件的操作,当Web容器启动后,Spring
的监听器会启动监听,监听是否创建ServletContext
的对象,如果发生了创建ServletContext
对象这个事件(当web容器启动后一定会生成一个ServletContext
对象,所以监听事件一定会发生),ContextLoaderListener
类会实例化并且执行初始化方法,将Spring
的配置文件中配置的bean
注册到Spring
容器中,监听的操作是读取WEB-INF/applicationContext.xml
,但是我们可以在web.xml
中配置多个需要读取的配置文件,如下方所示,读取完成后所有的配置文件中的bean都会注册到spring容器中。<context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/config/application-context.xml /WEB-INF/config/cache-context.xml /WEB-INF/config/captcha-context.xml /WEB-INF/config/jeecms/jeecore-context.xml /WEB-INF/config/jeecms/jeecms-context.xml /WEB-INF/config/shiro-context.xml /WEB-INF/config/plug/**/*-context.xml /WEB-INF/config/quartz-task.xml /WEB-INF/config/zxw/zxw-context.xml </param-value> </context-param>
web.xml
中对监听器的配置:<!-- 配置Spring的监听器 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 配置加载类路径的配置文件 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param>
-
在
Controller
中注入service
对象,调用service
对象的方法进行测试@Controller("accountController") @RequestMapping("/account") public class AccountController { @Autowired private AccountService accountService; @RequestMapping("/findAll") public String findAll() { List<Account> accounts = accountService.findAll(); System.out.println("表现层:查询所有用户..."); return "list"; } }
输出结果:
业务层:查询所有用户
表现层:查询所有用户…
-
3.4 Spring整合Mybatis框架
3.4.1 搭建和测试MyBatis的环境
-
在
web
项目中编写SqlMapConfig.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> <environments default="mysql"> <environment id="mysql"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql:///ssm?useUnicode=true&characterEncoding=utf8"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> <!-- 使用的是注解 --> <mappers> <!-- <mapper class="cn.itcast.dao.AccountDao"/> --> <!-- 该包下所有的dao接口都可以使用 --> <package name="cn.itcast.dao"/> </mappers> </configuration>
-
在
AccountDao
接口的方法上添加注解,编写SQL
语句public interface AccountDao { @Insert("insert into account (name,money) values(#{name},#{money})") public void saveAccount(Account account); @Select("select * from account") public List<Account> findAll(); }
-
编写测试方法
@Test public void saveAccount() throws IOException { Account account = new Account(); account.setName("小黑"); account.setMoney(234d); // 加载配置文件 InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); // 创建工厂 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(is); // 获取sqlSession对象 SqlSession session = factory.openSession(); // 常见代理对象 AccountDao accountDao = session.getMapper(AccountDao.class); accountDao.saveAccount(account); // 提交事务 session.commit(); // 释放资源 session.close(); is.close(); }
3.4.2 Spring整合MyBatis框架
目的:把SqlMapConfig.xml
配置文件中的内容配置到applicationContext.xml
配置文件中。由Spring
为我们进行对象的管理。从上面的测试文件中,可以看出我们需要将工厂对象,session
对象代理对象交由Spring
容器进行管理。即:把Mybatis
配置文件(SqlMapConfig.xml
)中内容配置到spring
配置文件中。
注意:
- 当我们使用的是代理
dao
的模式,dao
具体实现类由Mybatis
使用代理方式创建,此时Mybatis
配置文件不能删除。 - 整合
Spring
和Mybatis
时,Mybatis
创建的Mapper.xml
文件名必须和dao
接口文件名一致。
- 配置文件
<!-- 配置C3P0的连接池对象 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///ssm?useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<!-- 配置SqlSession的工厂 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置扫描dao的包 -->
<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.itcast.dao"/>
</bean>
可以删除SqlSessionMap
配置文件。
- 给
dao
接口加上注解@Repository
- 在
service
中注入dao
对象,进行测试。 - 配置
Spring
框架声明式事务管理
-
配置事务管理器
<!-- 配置Spring的声明式事务管理 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean>
-
配置事务通知
<!-- 配置事务的通知 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="*" propagation="REQUIRED" read-only="false"/> <tx:method name="find*" propagation="SUPPORTS" read-only="true"/> </tx:attributes> </tx:advice>
-
配置
AOP
增强<!-- 配置 aop --> <aop:config> <!-- 配置切入点表达式 --> <aop:pointcut expression="execution(* cn.lizhi.service.impl.*.*(..))" id="pt1"/> <!-- 建立通知和切入点表达式的关系 --> <aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"/> </aop:config>
4. 附常用配置文件
4.1 web.xml
配置文件
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!-- 配置前端控制器:服务器启动必须加载,需要加载springmvc.xml配置文件 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置初始化参数,创建完DispatcherServlet对象,加载springmvc.xml配置文件 -->
<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>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 配置解决中文乱码的过滤器 -->
<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>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 配置Spring的监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 配置加载类路径的配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- 4、使用Rest风格的URI,将页面普通的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>
<filter>
<filter-name>HttpPutFormContentFilter</filter-name>
<filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HttpPutFormContentFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
4.2 pom.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.lizhi</groupId>
<artifactId>SpringMVC_03</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>SpringMVC_03 Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>5.0.2.RELEASE</spring.version>
<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>
<mysql.version>5.1.6</mysql.version>
<mybatis.version>3.4.5</mybatis.version>
</properties>
<dependencies>
<!-- spring -->
<!-- 切入点表达式 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.8</version>
</dependency>
<!-- springAOP AOP核心功能,例如代理工厂等 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- springIOC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<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>
<!-- spring整合junit -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- 事务控制 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- SpringJDBC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- log start -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- log end -->
<!-- Mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<!-- 数据库连接池 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<!--引入pageHelper分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.0.0</version>
</dependency>
<!-- MBG -->
<!-- https://mvnrepository.com/artifact/org.mybatis.generator/mybatis-generator-core -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.5</version>
</dependency>
<!--JSR303数据校验支持;tomcat7及以上的服务器,
tomcat7以下的服务器:el表达式。额外给服务器的lib包中替换新的标准的el
-->
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.4.1.Final</version>
</dependency>
<!-- 对json处理的包,即能够使用@ResponseBody -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
</dependencies>
<build>
<finalName>ssm_crud</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<showWarnings>true</showWarnings>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
4.3 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/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!--SpringMVC的配置文件,包含网站跳转逻辑的控制,配置 -->
<context:component-scan base-package="cn.lizhi" use-default-filters="false">
<!--只扫描控制器。 -->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--配置视图解析器,方便页面返回 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!--两个标准配置 -->
<!-- 将springmvc不能处理的请求交给tomcat -->
<mvc:default-servlet-handler/>
<!-- 能支持springmvc更高级的一些功能,JSR303校验,快捷的ajax...映射动态请求 -->
<mvc:annotation-driven/>
</beans>
4.4 Spring配置文件 – applicationContext.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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- 注解扫描,不扫描controller层,controller层交给SpringMVC进行管理 -->
<context:component-scan base-package="cn.lizhi">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
<!-- Spring的配置文件,这里主要配置和业务逻辑有关的 -->
<!--=================== 数据源,事务控制,xxx ================-->
<!-- 引入数据源配置文件 -->
<context:property-placeholder location="classpath:dbconfig.properties" />
<!-- 数据源配置 -->
<bean id="pooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--================== 配置和MyBatis的整合=============== -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 指定mybatis全局配置文件的位置 -->
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<property name="dataSource" ref="pooledDataSource"></property>
<!-- 指定mybatis,mapper文件的位置 -->
<property name="mapperLocations" value="classpath:mapper/*.xml"></property>
</bean>
<!-- 配置扫描器,将mybatis接口的实现加入到ioc容器中 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--扫描所有dao接口的实现,加入到ioc容器中 -->
<property name="basePackage" value="cn.lizhi.dao"></property>
</bean>
<!-- 配置一个可以执行批量的sqlSession -->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"></constructor-arg>
<constructor-arg name="executorType" value="BATCH"></constructor-arg>
</bean>
<!--============================================= -->
<!-- ===============事务控制的配置 ================-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--控制住数据源 -->
<property name="dataSource" ref="pooledDataSource"></property>
</bean>
<!--开启基于注解的事务,使用xml配置形式的事务(必要主要的都是使用配置式) -->
<aop:config>
<!-- 切入点表达式 -->
<aop:pointcut expression="execution(* cn.lizhi.service..*(..))" id="txPoint"/>
<!-- 配置事务增强 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/>
</aop:config>
<!--配置事务增强,事务如何切入 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 所有方法都是事务方法 -->
<tx:method name="*"/>
<!--以get开始的所有方法 -->
<tx:method name="get*" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- Spring配置文件的核心点(数据源、与mybatis的整合,事务控制) -->
</beans>
4.5 Mybatis全局配置文件 – 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>
<typeAliases>
<package name="cn.lizhi.bean"/>
</typeAliases>
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!--分页参数合理化 -->
<property name="reasonable" value="true"/>
</plugin>
</plugins>
</configuration>
4.6 Mybatis逆向工程的配置文件 – mbg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="DB2Tables" targetRuntime="MyBatis3">
<!-- 关闭注释 -->
<commentGenerator>
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!-- 配置数据库连接 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://url:3306/ssm?useUnicode=true&characterEncoding=utf8"
userId="username"
password="password">
</jdbcConnection>
<javaTypeResolver >
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- 指定javaBean生成的位置 targetPackage为包的路径,targetProject为项目路径,即两个能够连接在一起 -->
<javaModelGenerator targetPackage="cn.lizhi.bean" targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- 指定sql映射文件生成的位置 -->
<sqlMapGenerator targetPackage="mapper" targetProject="./src/main/resources">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!-- 指定dao接口生成的位置,mapper接口 -->
<javaClientGenerator type="XMLMAPPER" targetPackage="cn.lizhi.dao" targetProject="./src/main/java">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<!-- table指定每个表的生成策略 -->
<table tableName="tbl_emp" domainObjectName="Employee"></table>
<table tableName="tbl_dept" domainObjectName="Department"></table>
</context>
</generatorConfiguration>
4.7 日志配置文件 – log4j.properties
# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
log4j.rootCategory=info, CONSOLE, LOGFILE
# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
4.8 数据库连接池 – dbconfig.properties
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql://url:3306/ssm?useUnicode=true&characterEncoding=utf8
jdbc.user=username
jdbc.password=password