1. Spring MVC拦截器应用 1-1
1.1. Spring MVC拦截器概述 1-1
1.2. Spring MVC拦截器编写及基本配置 1-2
1.3. Spring MVC拦截器链及配置实现 1-4
2. Spring MVC异常处理 2-6
2.1. Spring MVC 异常概述 2-6
2.2. Spring MVC 异常处理 2-7
3. Spring MVC 进阶总结 3-8
3.1. 重点和难点分析 3-8
3.2. 课后必须完成作业 3-8
3.3. 课后扩展作业(一) 3-8
3.4. 课后扩展作业(二) 3-10

Spring MVC拦截器应用

Spring MVC拦截器概述

拦截器是SpringMVC中的一个核心应用组件,主要用于处理多个
Controller的共性问题.当我们的请求由DispatcherServlet派发
到具体Controller之前首先要执行拦截器中一些相关方法,在这些
方法中可以对请求进行相应预处理(例如权限检测,参数验证),这些方法可以决定对这个请求进行拦截还是放行.
通过spring mvc 架构图分析,拦截器在Spring MVC中处理流程中的一个位置

回顾Spring MVC详细架构图

(*)SPRING-MVC-拦截器&异常 - 图1

各组件在企业架构中定位

(*)SPRING-MVC-拦截器&异常 - 图2

思考:
1)假如对请求数据进行编码,是应在过滤器还是拦截器?推荐使用过滤器.
2)拦截器有哪些有些应用场景呢?(处理后台控制业务的共性)
a)进行身份认证(判定用户是否是合法用户)
b)进行系统监控
c)进行日志记录
d)……….

Spring MVC拦截器编写及基本配置

拦截器如何编写?

我们自己编写Spring MVC拦截器需要实现HandlerInterceptor接口或者继承此接口的实现类 HandlerInterceptorAdapter(继承这个类时可根据需求重写必要的方法)
例如定义一个拦截器,计算controller方法的执行时间

public class TimeInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler)
throws Exception {
System.out.println(“time.preHandle”);
long startTime=System.nanoTime();
request.setAttribute(“startTime”, startTime);
return true;//true表示放行,false表示拦截
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println(“time.postHandle”);
}
@Override
public void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println(“time.afterCompletion”);
long endTime=System.nanoTime();
long startTime=(Long)request.getAttribute(“startTime”);
System.out.println(“time:”+(endTime-startTime));
}
}

这些方法的简易执行流程点如下图所示:
(*)SPRING-MVC-拦截器&异常 - 图3

这些方法的详细的执行时间点如下:(如何知道如下执行流程?)

(*)SPRING-MVC-拦截器&异常 - 图4

我们自己的拦截器编写完成以后需要在spring配置文件中进行配置,,
例如:







<!—
拦截器(这个bean也可以通过ref方式引用,前提是在外面要通过xml或注解方式定义) —>


课堂练习:基于拦截器实现控制层方法监控,计算控制层方法执行时长,具体参考课堂练习文档。

Spring MVC拦截器链及配置实现

当我们系统中有多个拦截器时,这些拦截器可以构成一个拦截器链.其原理类似过滤器中的过滤链。在多个拦截器应用中仅当所有匹配的拦截器的preHandle()都执行之后,才会调用Controller中处理请求的方法,然后再执行所有匹配的拦截器的postHandler(),再执行所有匹配的拦截器的afterCompletion()。
在拦截器链中,各拦截器的执行先后顺序取决于配置文件中配置的节点的先后顺序!
例如:再定义一个日志拦截器

@Component
public class LogInterceptor extends HandlerInterceptorAdapter{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println(“log.preHandler”);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println(“log.afterCompletion”);
}
}

配置日志拦截器
















课堂练习:模仿12306实现按时间段对系统进行访问控制。

思考:

  1. 多个拦截器时,其执行顺序有什么决定?(配置顺序)

  2. 拦截器对象何时创建?(启动时创建)

  3. 拦截器对象在内存中有几份?(一份)

  4. 拦截器中存在变量共享时可能会有线程安全问题吗?(有)

  5. Spring管理的Bean对象中存在变量共享时可能会有线程安全吗?(有)

  6. 多个拦截器对象如何共享数据?

(通过request,session,ServletContext,)

  1. 拦截器对象的生命周期何时结束?(容器销毁时)

  2. 拦截器可以解决什么问题?(Controller中共性问题,例如日志处理,系统监控,…)

  3. ……

Spring MVC异常处理

Spring MVC 异常概述

实际项目中我们经常会采用分层架构设计程序,每一层都可能会有异常,假如异常信息没有处理,可能会选择抛出,假如这些被抛出的异常与具体业务相关,那到控制层以后我们一般都进行相应的处理(处理方式应该相对友好)
在Spring mvc 项目中,边界出现异常以后我们通常会在Controller中进行处理,常用分层架构中的异常分析:

(*)SPRING-MVC-拦截器&异常 - 图5

Spring MVC 异常处理

在spring中处理异常时,通常会在Controller中定义具体的异常处理方法,这个方法上使用@HandlerException注解进行描述.例如在指定Controller中定义异常处理方法:

@ExceptionHandler(value=Exception.class)
@ResponseBody
public String handleException(Exception e){
System.out.println(“局部异常处理”);
return e.getMessage();
}

当多个异常处理类中很多异常处理的方式是相同的,还可以将这个异常处理方法提取到父类,以实现方法的重用。
假如不希望将共性的异常处理方法提取到父类,还可以在外部定义一个全局的异常处理类,这个类使用@ControllerAdvice注解进行修饰.然后在这个类中定义具体的异常处理方法,这些方法再使用@HandlerExcpeiton进行修饰,例如

@ControllerAdvice
public class AdviceExceptionHandler {
@ExceptionHandler(Throwable.class)
@ResponseBody
public String handlerException(Throwable e){
System.out.println(“全局的异常处理”);
return e.getMessage();
}
}

Spring MVC中异常处理机制总结:

  1. 为什么要进行异常处理?(提高系统的容错能力,让系统表现的更加友好)

  2. Spring MVC中异常处理的方式?(局部的,全局的)

  3. 局部方式异常处理如何实现?(Controller类中直接定义异常处理方法,使用@ExceptionHandler进行修饰)

  4. 全局方式异常处理如何实现?(通过继承将共性提取到父类或者

通过@ControllerAdvice注解修饰类,然后类中定义异常处理方法)

  1. 出现异常后,异常处理的具体机制是怎样的(首先会在当前Controller(包含父类)中查找有没有定义异常处理方法,假如有则查看注解中定义的异常类型是否与当前异常类型相匹配,假如匹配则直接处理,假如不匹配则查看当前类中有没有父类类型的异常处理方法与当前异常匹配,假如有则直接处理,没有则找全局异常处理。全局也没有则直接不友好的输出错误信息)

说明:实际项目中在controller的方法中除了要对正确的业务数据进行封装之外,还会对异常信息进行封装(例如封装到JsonResult),然后转换为json格式的字符串,输出到客户端。

Spring MVC 进阶总结

重点和难点分析

  1. Spring MVC 拦截器是什么?

  2. Spring MVC 拦截器应用场景?

  3. Spring MVC 拦截器的编写及配置?

  4. Spring MVC 中如何进行异常处理?

课后必须完成作业

  1. 对课堂内容进行总结(刻意总结,不是读老师的文档)

  2. 独立完成课堂练习中的时间监控

  3. 独立完成模拟12306的访问控制