2. Spring MVC 高级技术
2.1 拦截器(Inteceptor)使用
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是 配置在表现层框架自己的配置文件中的

2. 拦截器的执行流程
在运行程序时,拦截器的执行是有一定顺序的,该顺序与配置文件中所定义的拦截器的顺序相关。 单个
拦截器,在程序中的执行流程如下图所示:

程序先执行preHandle()方法,如果该方法的返回值为true,则程序会继续向下执行处理器中的方 法,否则将不再向下执行。
在业务处理器(即控制器Controller类)处理完请求后,会执行postHandle()方法,然后会通过 DispatcherServlet向客户端返回响应。
在DispatcherServlet处理完请求后,才会执行afterCompletion()方法。
3. 多个拦截器的执行流程
多个拦截器(假设有两个拦截器Interceptor1和Interceptor2,并且在配置文件中, Interceptor1拦截 器配置在前),在程序中的执行流程如下图所示:

从图可以看出,当有多个拦截器同时工作时,它们的preHandle()方法会按照配置文件中拦截器的配置 顺序执行,而它们的postHandle()方法和afterCompletion()方法则会按照配置顺序的反序执行。
示例代码
自定义SpringMVC拦截器
public class MyIntercepter01 implements HandlerInterceptor {
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("MyIntercepter01 preHandle......"); return true; }
@Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("MyIntercepter01 postHandle......"); }
@Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("MyIntercepter01 afterCompletion......"); } }
|
注册SpringMVC拦截器
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.lagou.edu.interceptor.MyIntercepter01"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.lagou.edu.interceptor.MyIntercepter02"/> </mvc:interceptor> </mvc:interceptors>
|
2.2 处理multipart形式的数据
文件上传
原生servlet处理上传的文件数据的,springmvc又是对serlvet的封装
添加所需jar包
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency>
|
配置文件上传解析器
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="1000000000"/> </bean>
|
前端Form
<%-- 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>
|
后台接收Handler
@RequestMapping("upload") public String upload(MultipartFile uploadFile, HttpServletRequest request) throws IOException { String originalFilename = uploadFile.getOriginalFilename(); String extendName = originalFilename.substring(originalFilename.lastIndexOf(".") + 1, originalFilename.length()); String uuid = UUID.randomUUID().toString(); String newName = uuid + "." + extendName; String realPath = request.getSession().getServletContext().getRealPath("/uploads"); String datePath = new SimpleDateFormat("yyyy-MM-dd").format(new Date()); File floder = new File(realPath + "/" + datePath); if(!floder.exists()) { floder.mkdirs(); } uploadFile.transferTo(new File(floder,newName)); return "success"; }
|
2.3 在控制器中处理异常
@ControllerAdvice public class GlobalExceptionResolver { @ExceptionHandler(ArithmeticException.class) public ModelAndView handleException(ArithmeticException exception, HttpServletResponse response) { ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("msg", exception.getMessage()); modelAndView.setViewName("error"); return modelAndView; } }
|
2.4 基于Flash属性的跨重定向请求数据传递
重定向时请求参数会丢失,我们往往需要重新携带请求参数,我们可以进行手动参数拼接如下:
return "redirect:handle01?name=" + name;
但是上述拼接参数的方法属于get请求,携带参数⻓度有限制,参数安全性也不高,此时,我们可以使 用SpringMVC提供的flash属性机制,向上下文中添加flash属性,框架会在session中记录该属性值,当 跳转到⻚面之后框架会自动删除flash属性,不需要我们手动删除,通过这种方式进行重定向参数传递, 参数⻓度和安全性都得到了保障,如下:
@RequestMapping("/handleRedirect") public String handleRedirect(String name,RedirectAttributes redirectAttributes) { redirectAttributes.addFlashAttribute("name",name); return "redirect:handle01"; }
|