SpringMVC
1、SpringMVC简介
大部分java应用都是web应用,展现层是web应用最为重要的部分。Spring为展现层提供了一个优秀的web框架——Spring MVC。和众多其他web框架一样,它基于MVC的设计理念,此外,它采用了松散耦合可插拔组件结构,比其他MVC框架更具扩展性和灵活性。
SpringMVC通过一套MVC注解,让POJO成为处理请求的控制器,无需实现任何接口,同时,SpringMVC还支持REST风格的URL请求。此外,SpringMVC在数据绑定、视图解析、本地化处理及静态资源处理上都有许多不俗的表现。它在框架设计、扩展性、灵活性等方面全面超越了Struts、WebWork等MVC框架,从原来的追赶者一跃成为MVC的领跑者。
SpringMVC框架围绕DispatcherServlet这个核心展开,DispatcherServlet是SpringMVC框架的总导演、总策划,它负责截获请求并将其分派给相应的处理器处理。
1.1、Spring体系简介
1.2、回顾MVC设计模式
- 用户将请求发送到控制器,控制器本身没有处理业务逻辑的能力;
- 将请求委托给模型做处理,模型将处理结果返回到控制器;
- 控制器将模型对视图做渲染;
- 将最终的视图(html)返回给用户;
注意:MVC不是java独有的,其他语言也有,它是一种模式!它也不是B/S独有的,C/S也有!
1.3、SpringMVC整体架构
- 用户发起请求到前端控制器(DispatcherServlet),前端控制器没有能力处理业务逻辑;
- 通过HandlerMapping查找模型(Controller、Handler);
- 返回执行链,执行链包含了2部分内容,Handler对象以及拦截器(组):n个HandlerInterceptor;
- 根据处理器Handler找到适配器HandlerAdapter,再通过HandlerAdapter去适配、执行模型(Handler)
- 适配器调用Handler对象处理业务逻辑;
- 模型处理完业务逻辑,返回ModelAndView对象,view不是真正的视图对象,而是视图名称;
- 将ModelAndView对象返回给前端控制器;
- 前端控制器通过视图名称经过视图解析器(ViewResolver)查找视图对象;
- 返回视图对象;
- 前端控制器渲染视图;
- 返回给前端控制器;
- 前端控制器将视图(html、json、xml、Excel)返回给用户;
1.4、我的第一个SpringMVC程序
- 配置SpringMVC框架入口-web.xml
1 <!-- SpringMVC框架的入口 --> 2 <servlet> 3 <servlet-name>springmvc</servlet-name> 4 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 5 <load-on-startup>1</load-on-startup> 6 <!-- 默认查找配置文件规则 /WEB-INF/servletName-servlet.xml --> 7 </servlet> 8 <servlet-mapping> 9 <servlet-name>springmvc</servlet-name> 10 <!-- 所有请求以*.do会进入MVC框架(.do是struts1的后缀) --> 11 <url-pattern>*.do</url-pattern> 12 </servlet-mapping>
默认查找配置文件规则 /WEB-INF/servletName-servlet.xml
- 配置核心组件_springmvc-servlet.xml
- 配置HandlerMapping
1 <!-- 注册HandlerMapping --> 2 <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
通过beanName查找,/hello.do è cn.itcast.springmvc.controller.HelloController
- 配置适配器
1 <!-- 注册简单适配器 --> 2 <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
- 定义Controller
1 <!-- 自定义Handler --> 2 <bean name="/hello.do" class="cn.itcast.springmvc.controller.HelloController"/>
要指定名称:/hello.do;
- 定义视图解析器
1 <!-- prefix="/WEB-INF/jsp/", suffix=".jsp", viewname="test" -> "/WEB-INF/jsp/test.jsp" --> 2 <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 3 <!-- 前缀 --> 4 <property name="prefix" value="/WEB-INF/views/"/> 5 <!-- 后缀 --> 6 <property name="suffix" value=".jsp"/> 7 </bean>
设置前缀和后缀,得到具体视图路径;
prefix="/WEB-INF/jsp/", suffix=".jsp", viewname="test" -> "/WEB-INF/jsp/test.jsp"
- 配置HandlerMapping
- 测试
- 执行过程
- SpringMVC的默认装载组件
在org.springframework.web.servlet/DispatcherServlet.properties 默认配置
# Default implementation classes for DispatcherServlet's strategy interfaces. # Used as fallback when no matching beans are found in the DispatcherServlet context. # Not meant to be customized by application developers. org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\ org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\ org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\ org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\ org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\ org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
1.5、我的第一个SpringMVC注解程序
- 创建Controller
1 @RequestMapping("/demo") //标识请求进入Controller的url path 2 @Controller //用来标识这个一个Controller(Handler) 3 public class Demo1Controller { 4 5 @RequestMapping("/show1") //标识请求进入Controller的url path 6 public ModelAndView show1() { 7 ModelAndView mv = new ModelAndView(); 8 mv.setViewName("demo1"); 9 mv.addObject("msg", "我的第一个注解程序!"); 10 return mv; 11 } 12 }
- 配置扫描器
1 <!-- 扫描包,使@Controller生效 --> 2 <context:component-scan base-package="cn.itcast.springmvc.controller"/>
- 配置视图解析器
1 <!-- prefix="/WEB-INF/jsp/", suffix=".jsp", viewname="test" -> "/WEB-INF/jsp/test.jsp" --> 2 <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 3 <!-- 前缀 --> 4 <property name="prefix" value="/WEB-INF/views/"/> 5 <!-- 后缀 --> 6 <property name="suffix" value=".jsp"/> 7 </bean>
- 创建jsp页面
创建页面:/WEB-INF/views/demo1.jsp
1 <%@ page language="java" contentType="text/html; charset=UTF-8" 2 pageEncoding="UTF-8"%> 3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 4 <html> 5 <head> 6 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 7 <title>Insert title here</title> 8 </head> 9 <body> 10 <h1>${msg}</h1> 11 </body> 12 </html>
- 测试
1.6、推荐使用的注解的HandlerMapping和HandlerAdapter
1 <!-- 推荐使用的注解的HandlerMapping --> 2 <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> 3 4 <!-- 推荐使用的注解适配器 --> 5 <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
其实这两个适配器也是不需要配置的,可以只配置下面提到的mvc注解驱动即可!
1.7、使用MVC注解驱动
在servlet配置文件中加入注解驱动标签即可:
1 <!-- mvc的注解驱动 --> 2 <mvc:annotation-driven/>
- 注解驱动背后处理逻辑
org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser
2、@RequestMapping映射
在SpringMVC中的众多Controller以及每个Controller的众多方法,请求是如何映射到具体的处理方法上?这个就是靠@RequestMapping完成的。
@RequestMapping既可以定义在类上也可以定义在方法上,
请求映射的规则是:类上的@RequestMapping.value + 方法上的@RequestMapping.value
@RequestMapping(value = "/hello") 和 @RequestMapping("/hello") 等效;
映射:
- 标准URL映射
- Ant风格的URL映射
- 占位符映射
- 限制请求方法映射
- 限制参数映射
2.1、标准URL映射
标准URL映射是最简单的一种映射,例如:@RequestMapping("/hello") 或 @RequestMapping(value="/hello")
请求url:http://localhost/hello.action
2.2、Ant风格的URL映射
1 /** 2 * Ant风格的通配符映射! 3 * 4 * @return 5 */ 6 @RequestMapping(value = "/demo/**/show3") 7 public ModelAndView show3() { 8 ModelAndView mv = new ModelAndView(); 9 mv.setViewName("hello"); 10 mv.addObject("msg", "Ant风格的通配符(**)映射!"); 11 return mv; 12 }
2.3、占位符映射
Url中可以通过一个或多个{xxxx}占位符映射。通过@PathVariable(“xxx”)绑定到方法的入参中。
例如:@RequestMapping(“/user/{userId}/query")
请求URL:http://localhost/user/8/query
RESTFul风格:http://127.0.0.1/demo/123/show4.....
1 /** 2 * url占位符 3 * 这里参数id改为String,也可以传中文,但会有乱码,所以一般传递中文参数会选择post提交 4 * @return 5 */ 6 @RequestMapping(value = "/demo/{id}/show4") 7 public ModelAndView show4(@PathVariable("id") Long id) { 8 ModelAndView mv = new ModelAndView(); 9 mv.setViewName("hello"); 10 mv.addObject("msg", "url占位符测试 id = " + id + "!"); 11 return mv; 12 }
2.4、@PathVariable小误区
小结:只有在开发时debug的环境下@PathVariable(xxxx) 可以简写为:@PathVariable!因此不要简写!
2.5、限定请求方式的映射
在Http请求中最常用的请求方法是GET、POST,还有其他的一些方法,DELET、PUT、HEAD等。
例如:
@RequestMapping(value = "/{userId}/query",method=RequestMethod.GET)
@RequestMapping(value = "/{userId}/query",method={RequestMethod.GET,RequestMethod.POST})
1 /** 2 * 限制请求方法GET、POST 3 * 4 * @return 5 */ 6 @RequestMapping(value = "/demo/test/show5", method = RequestMethod.POST) 7 public ModelAndView show5() { 8 ModelAndView mv = new ModelAndView(); 9 mv.setViewName("hello"); 10 mv.addObject("msg", "你使用的是POST请求!"); 11 return mv; 12 } 13 14 /** 15 * 限制请求方法GET、PUT 16 * 17 * @return 18 */ 19 @RequestMapping(value = "/demo/test/show6", method = { RequestMethod.GET, RequestMethod.PUT }) 20 public ModelAndView show6() { 21 ModelAndView mv = new ModelAndView(); 22 mv.setViewName("hello"); 23 mv.addObject("msg", "你使用的是GET或PUT请求!"); 24 return mv; 25 }
2.6、限定参数映射
设定请求的参数来映射URL,例如:@RequestMapping(value="/query",params="userId"),要求请求中必须带有userId参数。
参数的限制规则如下:
params=”userId” 请求参数中必须包含userId
params=”!userId” 请求参数中不能包含userId
params=”userId!=1” 请求参数必须包含userId,但其值不能为1
params={“userId”,”name”} 必须包含userId和name参数
1 /** 2 * 限制请求参数 3 * 4 * @return 5 */ 6 @RequestMapping(value = "/demo/test/show7", params = "id") 7 public ModelAndView show7(@RequestParam("id") String id) { 8 ModelAndView mv = new ModelAndView(); 9 mv.setViewName("hello"); 10 mv.addObject("msg", "现在请求参数 id = " + id + "!"); 11 return mv; 12 } 13 14 /** 15 * 限制多个请求参数 16 * 17 * @return 18 */ 19 @RequestMapping(value = "/demo/test/show8", params = { "id", "name" }) 20 public ModelAndView show8(@RequestParam("id") String id, @RequestParam("name") String name) { 21 ModelAndView mv = new ModelAndView(); 22 mv.setViewName("hello"); 23 mv.addObject("msg", "现在请求参数 id = " + id + " name = " + name + "!"); 24 return mv; 25 }
3、获取参数
3.1、绑定servlet内置对象
在Controller中获取Servlet的内置对象(Request、Response、Session)是非常简单的,如下:
public void test(HttpServletRequest request){……}
public void test(HttpServletResponse response){……}
public void test(HttpSession session){……}
public void test(Model model){……}//Model:数据模型,主要存储要返回到客户端的数据的,功能类似于Request对象。
1 /** 2 * 获取Servlet内置对象 3 * @param request 4 * @param response 5 * @param session 6 * @return 7 */ 8 @RequestMapping(value = "/demo/test/show9") 9 public ModelAndView show9(HttpServletRequest request,HttpServletResponse response,HttpSession session){ 10 ModelAndView mv = new ModelAndView(); 11 mv.setViewName("servlet"); 12 13 StringBuilder sb = new StringBuilder(); 14 sb.append("request = " + request); 15 sb.append("<br/>response = " + response); 16 sb.append("<br/>session = " + session); 17 18 request.setAttribute("param1", "在Request中参数!"); 19 20 mv.addObject("msg", sb); 21 return mv; 22 }
结果:
3.2、@PathVariable
通过@PathVariable可以绑定占位符参数到方法参数中,可以认为是url中?前面的参数,例如:@PathVariable("userId") Long userId
参考@RequestMapping映射/占位符映射部分!
3.3、@RequestParam
@RequestParam有三个参数(url中?后面的参数):
- value:参数名;
- required:是否必需,默认为true,表示请求参数中必须包含该参数,如果不包含抛出异常。
- defaultValue:默认参数值,如果设置了该值自动将required设置为false,如果参数中没有包含该参数则使用默认值。
示例:@RequestParam(value = "userId", required = false, defaultValue = "1")
1 /** 2 * 获取?后面传递的参数 3 * 4 * @return 5 */ 6 @RequestMapping(value = "/demo/test/show10") 7 public ModelAndView show10(@RequestParam(value = "id", required = false, defaultValue = "000")String id){ 8 ModelAndView mv = new ModelAndView(); 9 mv.setViewName("hello"); 10 mv.addObject("msg", "现在请求参数 id = "+id+" !"); 11 return mv; 12 }
3.4、@ CookieValue
在SpringMVC中获取cookie值更加方便了,@CookieValue可以绑定cookie值,和@RequestParam一样有三个参数,使用方法:
public void test(@CookieValue("JSESSIONID") String jsessionid)
1 /** 2 * 获取cookie中数据 3 * 4 * @return 5 */ 6 @RequestMapping(value = "/demo/test/show11") 7 public ModelAndView show11(@CookieValue("JSESSIONID")String JSESSIONID){ 8 ModelAndView mv = new ModelAndView(); 9 mv.setViewName("hello"); 10 mv.addObject("msg", "JSESSIONID = "+JSESSIONID+" !"); 11 return mv; 12 }
结果:
3.5、POJO对象绑定参数
SpringMVC会将请求过来的参数名和POJO实体中的属性名进行匹配,如果名称一致,将把值填充到对象中。
1 /** 2 * POJO对象绑定 3 * 4 * @return 5 */ 6 @RequestMapping(value = "/demo/test/show12") 7 public ModelAndView show12(User user){ 8 ModelAndView mv = new ModelAndView(); 9 mv.setViewName("hello"); 10 mv.addObject("msg", "user = "+user+" !"); 11 return mv; 12 }
http://127.0.0.1/demo/test/show12?id=1&userName=123&password=111&name=abc
3.6、JAVA的基本数据类型绑定
Spring对Java的基本数据类型的转换支持的非常多,基本能满足日常开发需要,默认支持的数据类型在org.springframework.beans.PropertyEditorRegistrySupport中定义。
- testForm.html
1 <!DOCTYPE> 2 <form action="/demo/test/show13.action" method="post"> 3 <div>姓名:</div> 4 <div><input name="name" value="张三"/></div> 5 <div class="clear"></div> 6 <div>年龄:</div> 7 <div><input name="age" value="20"/></div> 8 <div class="clear"></div> 9 <div>收入:</div> 10 <div><input name="income" value="100000"/></div> 11 <div class="clear"></div> 12 <div>结婚:</div> 13 <div> 14 <input type="radio" name="isMarried" value="true" checked="checked"/>是 15 <input type="radio" name="isMarried" value="false"/>否</div> 16 <div class="clear"></div> 17 <div>兴趣:</div> 18 <div> 19 <input type="checkbox" name="interests" value="听歌" checked="checked"/>听歌 20 <input type="checkbox" name="interests" value="书法" checked="checked"/>书法 21 <input type="checkbox" name="interests" value="看电影" checked="checked"/>看电影 22 </div> 23 <div class="clear"></div> 24 <div><input type="submit" value="提交表单"/></div> 25 </form>
- java测试代码
1 @RequestMapping("/demo/test/show13") 2 @ResponseStatus(value = HttpStatus.OK)// 无需跳转页面,直接返回200状态 3 public void show13(String name, Integer age, Double income, Boolean isMarried, String[] interests) { 4 System.out.println("简单数据类型绑定========="); 5 System.out.println("名字:" + name); 6 System.out.println("年龄:" + age); 7 System.out.println("收入:" + income); 8 System.out.println("已结婚:" + isMarried); 9 System.out.println("兴趣:"); 10 for (String interest : interests) { 11 System.out.println(interest); 12 } 13 System.out.println("===================="); 14 }
3.7、集合List绑定
List的绑定需要将List对象包装到一个类中才能绑定。
4、SpringMVC和Struts2的区别(面试)
- SpringMVC的入口是Servlet,Struts2的入口是Filter,两者的实现机制不同;
- SpringMVC基于方法设计,传递参数是通过方法形参,其实现是单例模式(也可以改为多例,推荐用单例),Struts2基于类设计,传递参数是通过类的属性,只能是多例实现,性能上SpringMVC更高一些。
- 参数传递方面,Struts2是用类的属性接收的,也就是在多个方法间共享,而SpringMVC基于方法,多个方法间不能共享。
5、视图与视图解析器
5.1、JSP和JSTL视图解析器
InternalResourceViewResolver默认使用的是JSTL解析器,要想使用JSTL标签需要导入JSTL的依赖。
1 <dependency> 2 3 <groupId>jstl</groupId> 4 5 <artifactId>jstl</artifactId> 6 7 <version>1.2</version> 8 9 </dependency>
具体扩展知识点参考文档:
- user.jsp
1 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 2 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 3 <!DOCTYPE html> 4 <html> 5 <head> 6 <title>JSTL Demo</title> 7 </head> 8 9 <body> 10 <table> 11 <thead> 12 <tr> 13 <th>ID</th> 14 <th>UserName</th> 15 <th>Name</th> 16 <th>Age</th> 17 </tr> 18 </thead> 19 <tbody> 20 <c:forEach items="${users}" var="user"> 21 <tr> 22 <td>${user.id}</<td> 23 <td>${user.userName}</<td> 24 <td>${user.name}</<td> 25 <td>${user.age}</<td> 26 </tr> 27 </c:forEach> 28 </tbody> 29 </table> 30 </body> 31 </html>
- 构造List<User>
1 /** 2 * 测试JSTL标签 3 * @return 4 */ 5 @RequestMapping("/demo/test/show14") 6 public ModelAndView show14() { 7 ModelAndView modelAndView = new ModelAndView("users");//通过构造直接赋视图名 8 List<User> users = new ArrayList<User>(); 9 10 for (int i = 0; i < 10; i++) { 11 User user = new User(); 12 user.setAge(20 + i); 13 user.setCreated(new Date()); 14 user.setId(Long.valueOf(i)); 15 user.setName("name_" + i); 16 user.setPassword("123456"); 17 user.setSex(i / 2); 18 user.setUpdated(user.getCreated()); 19 user.setUserName("userName_" + i); 20 users.add(user); 21 } 22 modelAndView.addObject("users", users); 23 return modelAndView; 24 }
5.2、@ResponseBody
补充:@ResponseBody注解,除了可以返回json,还可以返回xml等其他视图,但是用的最多的是返回json
1 /** 2 * 测试@ResponseBody 3 * 4 * @return 5 */ 6 @RequestMapping(value = "/demo/test/show15") 7 @ResponseBody 8 public User show15() { 9 User user = new User(); 10 Integer i = 0; 11 user.setAge(20 + i); 12 user.setCreated(new Date()); 13 user.setId(Long.valueOf(i)); 14 user.setName("name_" + i); 15 user.setPassword("123456"); 16 user.setSex(i / 2); 17 user.setUpdated(user.getCreated()); 18 user.setUserName("userName_" + i); 19 return user; 20 } 21 22 /** 23 * 测试@ResponseBody,返回集合 24 * 25 * @return 26 */ 27 @RequestMapping(value = "/demo/test/show16") 28 @ResponseBody 29 public List<User> show16() { 30 List<User> users = new ArrayList<User>(); 31 32 for (int i = 0; i < 10; i++) { 33 User user = new User(); 34 user.setAge(20 + i); 35 user.setCreated(new Date()); 36 user.setId(Long.valueOf(i)); 37 user.setName("name_" + i); 38 user.setPassword("123456"); 39 user.setSex(i / 2); 40 user.setUpdated(user.getCreated()); 41 user.setUserName("userName_" + i); 42 users.add(user); 43 } 44 return users; 45 }
5.3、@RequestBody
java代码:
1 /** 2 * 测试@RequestMapping,将json字符转化为java对象 3 * @param user 4 * @return 5 */ 6 @RequestMapping(value = "/demo/test/show17") 7 public ModelAndView show17(@RequestBody User user) { 8 ModelAndView mv = new ModelAndView(); 9 mv.setViewName("hello"); 10 mv.addObject("msg", "user = " + user + " !"); 11 return mv; 12 }
测试:
6、文件上传
上传原理:首先先保存到一个临时文件中,然后将这个临时文件写到目标文件中,最后将那个临时文件删除!
- 加入上传组件依赖-pom.xml
1 <!-- 文件上传组件 --> 2 <dependency> 3 <groupId>commons-fileupload</groupId> 4 <artifactId>commons-fileupload</artifactId> 5 <version>1.3.1</version> 6 </dependency>
- 定义文件上传解析器_ springmvc-servlet.xml
1 <!-- 定义文件上传解析器 --> 2 <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> 3 <!-- 设定默认编码 --> 4 <property name="defaultEncoding" value="UTF-8"></property> 5 <!-- 设定文件上传的最大值5MB,5*1024*1024 --> 6 <property name="maxUploadSize" value="5242880"></property> 7 </bean>
- 定义Controller
1 @RequestMapping("/file") 2 @Controller 3 public class FileUploadController { 4 5 @RequestMapping("/upload") 6 public String upload(@RequestParam("file") MultipartFile multipartFile) throws Exception { 7 if (multipartFile != null) { 8 // multipartFile.getOriginalFilename() 获取文件的原始名称 9 multipartFile.transferTo(new File("C:\\tmp\\" + multipartFile.getOriginalFilename())); 10 } 11 return "redirect:/html/success.html";//重定向跳转 12 } 13 }
- fileUpload.html
1 <!DOCTYPE> 2 <form action="/file/upload.action" method="post" enctype="multipart/form-data"> 3 文件: <input name="file" type="file" /><br/> 4 <input type="submit" value=" 提交 "/> 5 </form>
- 测试
7、拦截器
7.1、理解HandlerExecutionChain
HandlerExecutionChain是一个执行链,从HandlerMapping返回给DispatcherServlet,其中包含了Handler对象和Interceptor(拦截器)对象,SpringMVC的拦截器接口定义了三个方法:
- preHandle 调用handler之前执行;
- postHandle 调用handler之后执行;
- afterCompletion 视图渲染完之后执行;
7.2、拦截的执行过程
- 前置方法是正序执行:
- 后置方法是倒序执行:
- 完成方法是倒序执行:
7.3、自定义拦截器
- 实现org.springframework.web.servlet.HandlerInterceptor
1 public class MyHandlerInterceptor implements HandlerInterceptor{ 2 3 /** 4 * 前置方法,会在handler执行之前执行 5 */ 6 @Override 7 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 8 throws Exception { 9 System.out.println("前置方法 执行 。。。。。。。。"); 10 return true; 11 } 12 13 /** 14 * 后置方法,会在handler执行之后执行 15 */ 16 @Override 17 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, 18 ModelAndView modelAndView) throws Exception { 19 System.out.println("后置方法 执行 。。。。。。。。"); 20 } 21 22 /** 23 * 完成方法 24 */ 25 @Override 26 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, 27 Exception ex) throws Exception { 28 System.out.println("完成方法 执行 。。。。。。。。"); 29 } 30 31 }
- 配置拦截器
1 <!-- 自定义拦截器 --> 2 <mvc:interceptors> 3 <mvc:interceptor> 4 <!-- 2个*代表包含子目录 --> 5 <mvc:mapping path="/**/*.action"/> 6 <bean class="cn.itcast.springmvc.interceptor.MyHandlerInterceptor" /> 7 </mvc:interceptor> 8 </mvc:interceptors>
7.4、拦截器总结:
- 拦截器的执行过程和Struts2的拦截器执行过程类似;
- 拦截器的前置方法是正序执行,如果其中一个返回false则请求返回;
- 拦截器的后置方法是倒序执行,后置方法只有在前置方法全部执行后才能被执行;
- 拦截器的完成方法是倒序执行,完成方法不仅是在最后执行,而且如果前置方法返回false也会被执行(已经通过执行的拦截器的完成方法)。