Spring MVC 应用
1. Spring MVC 简介
1.1 MVC体系结构
三层架构
我们的开发架构⼀般都是基于两种形式,⼀种是 C/S 架构,也就是客户端/服务器;另⼀种是 B/S 架构,也就是浏览器服务器。在 JavaEE 开发中,⼏乎全都是基于 B/S 架构的开发。那么在 B/S 架构中,系统标准的三层架构包括:表现层、业务层、持久层。三层架构在我们的实际开发中使⽤的⾮常多,所以我们的案例也都是基于三层架构设计的。
三层架构中,每⼀层各司其职,接下来我们就说说每层都负责哪些⽅⾯:
- 表现层 : 也就是我们常说的web 层。它负责接收客户端请求,向客户端响应结果,通常客户端使⽤http协议请求web 层,web需要接收 http请求,完成http 响应。
表现层包括展示层和控制层:控制层负责接收请求,展示层负责结果的展示。
表现层依赖业务层,接收到客户端请求⼀般会调⽤业务层进⾏业务处理,并将处理结果响应给客户端。
表现层的设计⼀般都使⽤ MVC 模型。(MVC 是表现层的设计模型,和其他层没有关系)
- 业务层 : 也就是我们常说的 service 层。它负责业务逻辑处理,和我们开发项⽬的需求息息相关。web 层依赖业务层,但是业务层不依赖 web 层。
业务层在业务处理时可能会依赖持久层,如果要对数据持久化需要保证事务⼀致性。(也就是我们说的, 事务应该放到业务层来控制)
- 持久层 : 也就是我们是常说的 dao 层。负责数据持久化,包括数据层即数据库和数据访问层,数据库是对数据进⾏持久化的载体,数据访问层是业务层和持久层交互的接⼝,业务层需要通过数据访问层将数据持久化到数据库中。通俗的讲,持久层就是和数据库交互,对数据库表进⾏增删改查的。
MVC设计模式
MVC 全名是 Model View Controller,是 模型(model)-视图(view)-控制器(controller) 的缩写, 是⼀种⽤于设计创建 Web 应⽤程序表现层的模式。 MVC 中每个部分各司其职:
- Model(模型) :模型包含业务模型和数据模型,数据模型⽤于封装数据,业务模型⽤于处理业务。
- View(视图) : 通常指的就是我们的 jsp 或者 html。作⽤⼀般就是展示数据的。通常视图是依据模型数据创建的。
- Controller(控制器) : 是应⽤程序中处理⽤户交互的部分。作⽤⼀般就是处理程序逻辑的。
MVC提倡 :每⼀层只编写⾃⼰的东⻄,不编写任何其他的代码;分层是为了解耦,解耦是为了维护⽅便和分⼯协作
1.2 Spring MVC是什么
SpringMVC 全名叫 Spring Web MVC,是⼀种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级Web 框架,属于 SpringFrameWork 的后续产品。
SpringMVC 已经成为⽬前最主流的 MVC 框架之⼀,并且 随着 Spring3.0的发布,全⾯超越 Struts2,成为最优秀的 MVC 框架。 SpringMVC中要让⼀个java类能够处理请求只需要添加注解就ok
它通过⼀套注解,让⼀个简单的 Java 类成为处理请求的控制器,⽽⽆须实现任何接⼝。同时它还⽀持RESTful 编程⻛格的请求。
总之:Spring MVC和Struts2⼀样,都是 为了解决表现层问题 的web框架,它们都是基于 MVC 设计模式的。⽽这些表现层框架的主要职责就是处理前端HTTP请求。
Spring MVC 本质可以认为是对servlet的封装,简化了我们serlvet的开发
作⽤:1. 接收请求 2. 返回响应,跳转⻚⾯
2. Spring MVC 工作流程
2.1 开发过程
1)web.xml中配置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>mvc</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>
</servlet>
<servlet-mapping>
<servlet-name>mvc</servlet-name>
<!-- 拦截方式
方式一:带后缀,比如*.action *.do *.aaa
该种方式比较精确、方便,在以前和现在企业中都有很大的使用比例
方式二:/ 不会拦截 .jsp,但是会拦截.html等静态资源(静态资源:除了servlet和jsp之外的js、css、png等)
为什么配置为/ 会拦截静态资源???
因为tomcat容器中有一个web.xml(父),你的项目中也有一个web.xml(子),是一个继承关系
父web.xml中有一个DefaultServlet, url-pattern 是一个 /
此时我们自己的web.xml中也配置了一个 / ,覆写了父web.xml的配置
为什么不拦截.jsp?
因为父web.xml中有一个JspServlet,这个servlet拦截.jsp文件,而我们并没有覆写这个配置,
所以springmvc此时不拦截jsp,jsp的处理交给了tomcat
方式三:/* 拦截所有,包括.jsp
-->
<!--拦截匹配规则的url请求,进入springmvc框架处理-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
2)开发处理具体业务逻辑的Handler(@Controller、@RequestMapping)
@Controller
@RequestMapping("/demo")
public class DemoController {
@Autowired
private DemoService demoService;
@RequestMapping("/handler01")
public ModelAndView handler01(String name) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("name", demoService.getName(name));
modelAndView.setViewName("/WEB-INF/jsp/success.jsp");
return modelAndView;
}
}
3)xml配置⽂件配置controller扫描,配置springmvc三⼤件
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
https://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.example"></context:component-scan>
<!--
自动注册最合适的处理器映射器,处理器适配器(调用handler方法)
-->
<mvc:annotation-driven />
<!--配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
4)将xml⽂件路径告诉springmvc(DispatcherServlet)
<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>
</servlet>
2.2 Springmvc请求处理流程
流程说明
第⼀步:⽤户发送请求⾄前端控制器DispatcherServlet 第⼆步:DispatcherServlet收到请求调⽤HandlerMapping处理器映射器 第三步:处理器映射器根据请求Url找到具体的Handler(后端控制器),⽣成处理器对象及处理器拦截 器(如果 有则⽣成)⼀并返回DispatcherServlet 第四步:DispatcherServlet调⽤HandlerAdapter处理器适配器去调⽤Handler 第五步:处理器适配器执⾏Handler 第六步:Handler执⾏完成给处理器适配器返回ModelAndView 第七步:处理器适配器向前端控制器返回 ModelAndView,ModelAndView 是SpringMVC 框架的⼀个底层对 象,包括 Model 和 View 第⼋步:前端控制器请求视图解析器去进⾏视图解析,根据逻辑视图名来解析真正的视图。 第九步:视图解析器向前端控制器返回View 第⼗步:前端控制器进⾏视图渲染,就是将模型数据(在 ModelAndView 对象中)填充到 request 域 第⼗⼀步:前端控制器向⽤户响应结果
2.3 Spring MVC 九⼤组件
-
HandlerMapping(处理器映射器) HandlerMapping是⽤来查找Handler的,也就是处理器,具体的表现形式可以是类,也可以是⽅法。⽐如,标注了@RequestMapping的每个⽅法都可以看成是⼀个Handler。Handler负责具体实际的请求处理,在请求到达后,HandlerMapping 的作⽤便是找到请求相应的处理器Handler 和 Interceptor.
-
HandlerAdapter(处理器适配器) HandlerAdapter 是⼀个适配器。因为 Spring MVC 中 Handler 可以是任意形式的,只要能处理请求即可。但是把请求交给 Servlet 的时候,由于 Servlet 的⽅法结构都是doService(HttpServletRequest req,HttpServletResponse resp)形式的,要让固定的 Servlet 处理⽅法调⽤ Handler 来进⾏处理,便是 HandlerAdapter 的职责。
-
HandlerExceptionResolver HandlerExceptionResolver ⽤于处理 Handler 产⽣的异常情况。它的作⽤是根据异常设置ModelAndView,之后交给渲染⽅法进⾏渲染,渲染⽅法会将 ModelAndView 渲染成⻚⾯。
-
ViewResolver(视图解析器) ViewResolver即视图解析器,⽤于将String类型的视图名和Locale解析为View类型的视图,只有⼀ 个resolveViewName()⽅法。从⽅法的定义可以看出,Controller层返回的String类型视图名viewName 最终会在这⾥被解析成为View。View是⽤来渲染⻚⾯的,也就是说,它会将程序返回的参数和数据填⼊模板中,⽣成html⽂件。ViewResolver 在这个过程主要完成两件事情: ViewResolver 找到渲染所⽤的模板(第⼀件⼤事)和所⽤的技术(第⼆件⼤事,其实也就是找到视图的类型,如JSP)并填⼊参数。默认情况下,Spring MVC会⾃动为我们配置⼀个InternalResourceViewResolver,是针对 JSP 类型视图的。
-
RequestToViewNameTranslator RequestToViewNameTranslator 组件的作⽤是从请求中获取 ViewName.因为 ViewResolver 根据ViewName 查找 View,但有的 Handler 处理完成之后,没有设置 View,也没有设置 ViewName,便要通过这个组件从请求中查找 ViewName。
-
LocaleResolver ViewResolver 组件的 resolveViewName ⽅法需要两个参数,⼀个是视图名,⼀个是Locale。LocaleResolver ⽤于从请求中解析出 Locale,⽐如中国 Locale 是 zh-CN,⽤来表示⼀个区域。这个组件也是 i18n 的基础。
-
ThemeResolver ThemeResolver 组件是⽤来解析主题的。主题是样式、图⽚及它们所形成的显示效果的集合。Spring MVC 中⼀套主题对应⼀个 properties⽂件,⾥⾯存放着与当前主题相关的所有资源,如图⽚、CSS样式等。创建主题⾮常简单,只需准备好资源,然后新建⼀个“主题名.properties”并将资源设置进去,放在classpath下,之后便可以在⻚⾯中使⽤了。SpringMVC中与主题相关的类有ThemeResolver、ThemeSource和Theme。ThemeResolver负责从请求中解析出主题名, ThemeSource根据主题名找到具体的主题,其抽象也就是Theme,可以通过Theme来获取主题和具体的资源。
-
MultipartResolver MultipartResolver ⽤于上传请求,通过将普通的请求包装成 MultipartHttpServletRequest 来实现。MultipartHttpServletRequest 可以通过 getFile() ⽅法 直接获得⽂件。如果上传多个⽂件,还可以调⽤ getFileMap()⽅法得到Map<FileName,File>这样的结构,MultipartResolver 的作⽤就是封装普通的请求,使其拥有⽂件上传的功能。
-
FlashMapManager FlashMap ⽤于重定向时的参数传递,⽐如在处理⽤户订单时候,为了避免重复提交,可以处理完post请求之后重定向到⼀个get请求,这个get请求可以⽤来显示订单详情之类的信息。这样做虽然 可以规避⽤户重新提交订单的问题,但是在这个⻚⾯上要显示订单的信息,这些数据从哪⾥来获得呢?因为重定向时么有传递参数这⼀功能的,如果不想把参数写进URL(不推荐),那么就可以通 过FlashMap来传递。只需要在重定向之前将要传递的数据写⼊请求(可以通过ServletRequestAttributes.getRequest()⽅法获得)的属性OUTPUT_FLASH_MAP_ATTRIBUTE中,这样在重定向之后的Handler中Spring就会⾃动将其设置到Model中,在显示订单信息的⻚⾯上就可以直接从Model中获取数据。FlashMapManager 就是⽤来管理 FalshMap 的。
3. Spring MVC 参数绑定
3.1 原生servlet-api的支持,默认⽀持 Servlet API 作为⽅法参数
3.1.1 pom文件添加servlet-api依赖
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
3.1.2 添加handler()处理
/**
* SpringMVC 对原⽣servlet api的⽀持 url:/demo/handler02?id=1
* 如果要在SpringMVC中使⽤servlet原⽣对象,⽐如
* HttpServletRequest\HttpServletResponse\HttpSession,直接在Handler⽅法形参中声明使⽤即可
*
*/
@RequestMapping("/handler02")
public ModelAndView handler02(HttpServletRequest request) {
String id = request.getParameter("id");
System.out.println(id);
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("name", new Date());
modelAndView.setViewName("success");
return modelAndView;
}
3.1.3 测试页面 index.jsp
<%@ page isELIgnored="false" contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>SpringMVC 测试页</title>
<%-- <script type="text/javascript" src="/js/jquery.min.js"></script>--%>
<script>
$(function () {
$("#ajaxBtn").bind("click",function () {
// 发送ajax请求
$.ajax({
url: '/demo/handler07',
type: 'POST',
data: '{"id":"1","name":"李四"}',
contentType: 'application/json;charset=utf-8',
dataType: 'json',
success: function (data) {
alert(data.name);
}
})
})
})
</script>
<style>
div{
padding:10px 10px 0 10px;
}
</style>
</head>
<body>
<div>
<h2>Spring MVC 请求参数绑定</h2>
<fieldset>
<p>测试用例:SpringMVC 对原生servlet api的支持</p>
<a href="/demo/handler02?id=1">点击测试</a>
</fieldset>
<fieldset>
<p>测试用例:SpringMVC 接收简单数据类型参数</p>
<a href="/demo/handler03?id=1">点击测试</a>
</fieldset>
<fieldset>
<p>测试用例:SpringMVC 使用@RequestParam 接收简单数据类型参数(形参名和参数名不一致)</p>
</fieldset>
<fieldset>
<p>测试用例:SpringMVC接收pojo类型参数</p>
<a href="/demo/handler04?id=1&name=zhangsan">点击测试</a>
</fieldset>
<fieldset>
<p>测试用例:SpringMVC接收pojo包装类型参数</p>
<a href="/demo/handler05?user.id=1&user.name=zhangsan">点击测试</a>
</fieldset>
<fieldset>
<p>测试用例:SpringMVC接收日期类型参数</p>
<a href="/demo/handler06?birthday=2019-10-08">点击测试</a>
</fieldset>
</div>
<div>
<h2>SpringMVC对Restful风格url的支持</h2>
<fieldset>
<p>测试用例:SpringMVC对Restful风格url的支持</p>
<a href="/demo/handler/15">rest_get测试</a>
<form method="post" action="/demo/handler">
<input type="text" name="username"/>
<input type="submit" value="提交rest_post请求"/>
</form>
<form method="post" action="/demo/handler/15/lisi">
<input type="hidden" name="_method" value="put"/>
<input type="submit" value="提交rest_put请求"/>
</form>
<form method="post" action="/demo/handler/15">
<input type="hidden" name="_method" value="delete"/>
<input type="submit" value="提交rest_delete请求"/>
</form>
</fieldset>
</div>
<div>
<h2>Ajax json交互</h2>
<fieldset>
<input type="button" id="ajaxBtn" value="ajax提交"/>
</fieldset>
</div>
<div>
<h2>multipart 文件上传</h2>
<fieldset>
<%--
1 method="post"
2 enctype="multipart/form-data"
3 type="file"
--%>
<form method="post" enctype="multipart/form-data" action="/demo/upload">
<input type="file" name="uploadFile"/>
<input type="submit" value="上传"/>
</form>
</fieldset>
</div>
</body>
</html>
3.1.4 测试代码
3.2 简单数据类型
简单数据类型:1. ⼋种基本数据类型及其包装类型(参数类型推荐使⽤包装数据类型,因为基础数据类型不可以为null) 2. String
绑定简单数据类型参数,只需要直接声明形参即可(形参参数名和传递的参数名要保持⼀致,建议 使⽤包装类型,当形参参数名和传递参数名不⼀致时可以使用@RequestParam注解进⾏⼿动映射)
3.2.1 参数名称一致
3.2.2 参数名称不一致
/demo/handler03?ids=1
3.3 pojo类型
http://localhost:8088/demo/handler04?id=1&name=zhangsan
3.4 包装pojo类型
http://localhost:8088/demo/handler05?user.id=1&user.name=zhangsan
QueryVo
public class QueryVo {
private Integer id;
private User user;
public QueryVo() {
}
public QueryVo(Integer id, User user) {
this.id = id;
this.user = user;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
3.5 日期类型
http://localhost:8088/demo/handler06?birthday=2021-04-20
一般日期的格式太多,比如yyyy-MM-dd 、 yyyy.MM.dd 、 yyyy/MM/dd springmvc不知道该以何种方式解析日期,所以提供了Converter接口,可以自定义日期类型转换器
3.5.1 ⾃定义类型转换器
public class DateConverter implements Converter<String, Date> {
@Override
public Date convert(String dateStr) {
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
try {
Date parse = sf.parse(dateStr);
return parse;
} catch (ParseException e) {
sf = new SimpleDateFormat("yyyy/MM/dd");
Date parse = null;
try {
parse = sf.parse(dateStr);
} catch (ParseException ex) {
ex.printStackTrace();
}
return parse;
}
}
}
3.5.2 注册⾃定义类型转换器
<!--
自动注册最合适的处理器映射器,处理器适配器(调用handler方法)
-->
<mvc:annotation-driven conversion-service="conversionServiceBean" />
<!--
自定义日期转换器
id="conversionServiceBean" 这个id是固定的
FormattingConversionServiceFactoryBean中有一个converters集合,存放所有的转换器
-->
<bean id="conversionServiceBean" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.example.converter.DateConverter"></bean>
</set>
</property>
</bean>
3.5.3 测试日期转换
4. 请求⽅式过滤器 (将特定的post请求转换为put和delete请求)
4.1 form表单添加隐藏域
<form method="post" action="/demo/handler/15/lisi">
<input type="hidden" name="_method" value="put"/>
<input type="submit" value="提交rest_put请求"/>
</form>
4.2 定义handler处理
@RequestMapping(value = "/handler/{id}/{name}", method = RequestMethod.PUT)
public ModelAndView handler06(@PathVariable Integer id, @PathVariable String name) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("name", new Date());
modelAndView.setViewName("success");
return modelAndView;
}
4.3 web.xml中配置请求⽅式过滤器 将特定的post请求转换为put或者delete请求
<!--配置springmvc请求方式转换过滤器,会检查请求参数中是否有_method参数,如果有就按照指定的请求方式进行转换-->
<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>
4.4 测试代码
5. post请求编码过滤器
<!--springmvc提供的针对post请求的编码过滤器-->
<filter>
<filter-name>encoding</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>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
6. 静态资源配置
<!--静态资源配置,方案一-->
<!--
原理:添加该标签配置之后,会在SpringMVC上下文中定义一个DefaultServletHttpRequestHandler对象
这个对象如同一个检查人员,对进入DispatcherServlet的url请求进行过滤筛查,如果发现是一个静态资源请求
那么会把请求转由web应用服务器(tomcat)默认的DefaultServlet来处理,如果不是静态资源请求,那么继续由
SpringMVC框架处理
-->
<!--<mvc:default-servlet-handler/>-->
<!--静态资源配置,方案二,SpringMVC框架自己处理静态资源
mapping:约定的静态资源的url规则
location:指定的静态资源的存放位置
-->
<mvc:resources location="classpath:/" mapping="/resources/**"/>
<mvc:resources location="/WEB-INF/js/" mapping="/js/**"/>
7. 拦截器(Inteceptor)使⽤
7.1 监听器、过滤器和拦截器对⽐
-
Servlet:处理Request请求和Response响应
-
过滤器(Filter):对Request请求起到过滤的作⽤,作⽤在Servlet之前,如果配置为/*可以对所有的资源访问(servlet、js/css静态资源等)进⾏过滤处理
-
监听器(Listener):实现了javax.servlet.ServletContextListener 接⼝的服务器端组件,它随Web应⽤的启动⽽启动,只初始化⼀次,然后会⼀直运⾏监视,随Web应⽤的停⽌⽽销毁
作⽤⼀:做⼀些初始化⼯作,web应⽤中spring容器启动ContextLoaderListener 作⽤⼆:监听web中的特定事件,⽐如HttpSession,ServletRequest的创建和销毁;变量的创建、销毁和修改等。可以在某些动作前后增加处理,实现监控,⽐如统计在线⼈数,利⽤HttpSessionLisener等。
-
拦截器(Interceptor):是SpringMVC、Struts等表现层框架⾃⼰的,不会拦截jsp/html/css/image的访问等,只会拦截访问的控制器⽅法(Handler)。
从配置的⻆度也能够总结发现:serlvet、filter、listener是配置在web.xml中的,⽽interceptor是配置在表现层框架⾃⼰的配置⽂件中的
- 在Handler业务逻辑执⾏之前拦截⼀次
- 在Handler逻辑执⾏完毕但未跳转⻚⾯之前拦截⼀次
- 在跳转⻚⾯之后拦截⼀次
7.2 拦截器的执行流程
在运⾏程序时,拦截器的执⾏是有⼀定顺序的,该顺序与配置⽂件中所定义的拦截器的顺序相关。 单个拦截器,在程序中的执⾏流程如下图所示:
- 程序先执⾏preHandle()⽅法,如果该⽅法的返回值为true,则程序会继续向下执⾏处理器中的⽅法,否则将不再向下执⾏。
- 在业务处理器(即控制器Controller类)处理完请求后,会执⾏postHandle()⽅法,然后会通过DispatcherServlet向客户端返回响应。在DispatcherServlet处理完请求后,才会执⾏afterCompletion()⽅法。
7.3 多个拦截器的执行流程
多个拦截器(假设有两个拦截器Interceptor1和Interceptor2,并且在配置⽂件中, Interceptor1拦截器配置在前),在程序中的执⾏流程如下图所示:
从图可以看出,当有多个拦截器同时⼯作时,它们的preHandle()⽅法会按照配置⽂件中拦截器的配置 顺序执⾏,⽽它们的postHandle()⽅法和afterCompletion()⽅法则会按照配置顺序的反序执⾏。
代码示例
定义interceptor 两个interceptor
public class MyInterceptor1 implements HandlerInterceptor {
/**
* 执行handler之前执行
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor1中的preHandle.....");
return true;
}
/**
* 执行handler之后,返回页面之前执行
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor1中的postHandle.....");
}
/**
* 页面渲染完之后执行
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor1中的afterCompletion.....");
}
}
注册拦截器
<!--拦截所有handler-->
<!--<bean class="com.example.interceptor.MyInterceptor1"/>-->
<mvc:interceptors>
<mvc:interceptor>
<!--配置当前拦截器的url拦截规则,**代表当前⽬录下及其⼦⽬录下的所有url-->
<mvc:mapping path="/**"/>
<!--exclude-mapping可以在mapping的基础上排除⼀些url拦截-->
<!--<mvc:exclude-mapping path="/demo/**"/>-->
<bean class="com.example.interceptor.MyInterceptor1"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.example.interceptor.MyInterceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>
执行handler 查看日志
8. 处理multipart形式的数据
8.1 所需要的依赖
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
8.2 jsp页面
<div>
<h2>multipart 文件上传</h2>
<fieldset>
<%--
1 method="post"
2 enctype="multipart/form-data"
3 type="file"
--%>
<form method="post" enctype="multipart/form-data" action="/demo/upload">
<input type="file" name="uploadFile"/>
<input type="submit" value="上传"/>
</form>
</fieldset>
</div>
8.3 handler
@RequestMapping("/upload")
public String upload(MultipartRequest multipartRequest, MultipartFile uploadFile, HttpServletRequest request) {
// 获取源文件名称
MultipartFile requestFile = multipartRequest.getFile("uploadFile");
String originalFilename = uploadFile.getOriginalFilename();
// 获取⽂件的扩展名,如jpg
String extendName = originalFilename.substring(originalFilename.lastIndexOf(".") + 1, originalFilename.length());
// 生成新的文件名
String uuid = UUID.randomUUID().toString();
String newFileName = uuid + "." + extendName;
// 获取路径
String basePath = request.getSession().getServletContext().getRealPath("/uploads");
// 按照日期创建文件夹
String datePath = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
File file = new File(basePath + "/" + datePath);
if (!file.exists()) {
file.mkdirs();
}
try {
uploadFile.transferTo(new File(file, newFileName));
} catch (IOException e) {
e.printStackTrace();
}
return "success";
}
8.4 springmvc.xml中配置文件解析器
<!--配置文件解析器 id="multipartResolver"为固定值-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--设置允许上传的文件的最大大小-->
<property name="maxUploadSize" value="10000000"></property>
</bean>
8.5 查看测试结果
9. 异常处理器
9.1 异常处理类
/**
* 全局异常处理器
* @ControllerAdvice 增强处理器
* 可以处理:
全局异常处理
全局数据绑定
全局数据预处理
*/
@ControllerAdvice
public class GlobalExceptionResolver {
@ExceptionHandler(Exception.class)
public ModelAndView handlerException(Exception exception, HttpServletResponse response) {
ModelAndView modelAndView = new ModelAndView();
// 将异常信息添加到response中
modelAndView.addObject("msg", exception.getMessage());
// 返回到异常页面
modelAndView.setViewName("error");
return modelAndView;
}
}
9.2 异常测试
10. 基于Flash属性的跨重定向请求数据传递
重定向时请求参数会丢失,我们往往需要重新携带请求参数,我们可以进⾏⼿动参数拼接如下:
return "redirect:handle01?name=" + name;
但是上述拼接参数的⽅法属于get请求,携带参数⻓度有限制,参数安全性也不⾼,此时,我们可以使⽤SpringMVC提供的flash属性机制,向上下⽂中添加flash属性,框架会在session中记录该属性值,当跳转到⻚⾯之后框架会⾃动删除flash属性,不需要我们⼿动删除,通过这种⽅式进⾏重定向参数传递,参数⻓度和安全性都得到了保障,如下:
/**
* SpringMVC 重定向时参数传递的问题
*/
@RequestMapping("/handleRedirect")
public String handleRedirect(String name,RedirectAttributes
redirectAttributes) {
//return "redirect:handle01?name=" + name; // 拼接参数安全性、参数⻓度都有
局限
// addFlashAttribute⽅法设置了⼀个flash类型属性,该属性会被暂存到session中,在
跳转到⻚⾯之后该属性销毁
redirectAttributes.addFlashAttribute("name",name);
return "redirect:handle01";
}