(八)
异常解析器用于统一处理 servlet 中的异常;
拦截器用于统一处理业务中需要统一处理的页面(比如登录判断等), 可抽取出来统一处理.
下面举例说明一下拦截器的使用
如果不使用拦截器, 我们可能需要在多个handler中写用户是否登录的逻辑判断, 产生代码冗余, 如下例:
@RequestMapping("/inter") @Controller @SessionAttributes("loginID") /** * 如果不使用拦截器, 可能发生这种情况: 多个handler中都要添加逻辑判断, 且这些逻辑判断可能是重复的, 造成重复代码 * 如test1和test2中的判断用户是否登录代码 */ public class InterBean { @RequestMapping("/login") public String login(Model model){ //登录后留取状态标记 model.addAttribute("loginID","613025"); System.out.println("访问login..."); //返回登录页面 return "afterIndexPage"; } @RequestMapping("/test1") public String test1(Model model){ System.out.println("访问test1..."); if(model.asMap().get("loginID") != null){ System.out.println("loginID有值"); return "afterIndexPage"; } System.out.println("loginID无值"); return "indexPage"; } @RequestMapping("test2") public String test2(Model model){ System.out.println("访问test2..."); if(model.asMap().get("loginID") != null){ System.out.println("loginID有值"); return "afterIndexPage"; } System.out.println("loginID无值"); return "indexPage"; } }
直接访问/inter/test1:
先访问/inter/login 在访问 /inter/test1:
使用拦截器:
创建拦截器 MyInterceptor.java:(实现 HandlerInterceptor 接口并重写其三个方法)
public class MyInterceptor implements HandlerInterceptor { //在handler之前执行, 在这里写handler中冗余的功能 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //判断登录状态 HttpSession session = request.getSession(); if (session.getAttribute("loginID") != null){ System.out.println("loginID有值"); //return true即放行, 执行后续的handler return true; } //中断之前, 响应请求 System.out.println("loginID无值"); response.sendRedirect("/indexPage.jsp"); return false; } //在handler之后, 响应之前执行, 一般不使用 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("post handler"); } //在视图渲染完毕后执行, 如一些资源的回收操作, 一般不使用 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("after completion"); } }
则原来的 handler 中的登录判断逻辑都可以省略(此处把代码放到一个新的servlet: InterBeanPro中):
@RequestMapping("/interPro")
@Controller
@SessionAttributes("loginID")
public class InterBeanPro { @RequestMapping("/login") public String login(Model model){ //登录后留取状态标记 model.addAttribute("loginID","613025"); System.out.println("访问login..."); //返回登录页面 return "afterIndexPage"; } @RequestMapping("/test1") public String test1(Model model){ System.out.println("访问test1..."); return "afterIndexPage"; } @RequestMapping("test2") public String test2(Model model){ System.out.println("访问test2..."); return "afterIndexPage"; } }
在 mvc.xml 中添加拦截器:
... <!--拦截器--> <mvc:interceptors> <mvc:interceptor> <!-- 需要添加拦截的路径--> <mvc:mapping path="/interPro/test1"/> <mvc:mapping path="/interPro/test2"/> <!-- 拦截器--> <bean class="com.ryan.testInterceptor.MyInterceptor"/> </mvc:interceptor> </mvc:interceptors> </beans>
这样, 拦截器就生效了, 当有请求访问 /interPro/test1(2) 时, 请求会被 MyInterceptor.java 拦截, 并在这里进行登录判断, 若用户未登录, 则重定向到登录页面; 若用户已登录, 则正常访问:
直接访问 localhost:8080/interPro/test1, 会被拦截并跳转到登录页面:
先访问/interPro/login 在访问 /interPro/test1:
补充: 添加拦截器的其他方式:
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/interPro/test1"/> <mvc:mapping path="/interPro/test2"/> <mvc:mapping path="/interPro/test*"/> <!--匹配test开头的handler--> <mvc:mapping path="/inter/**"/> <!--匹配任意多级路径--> <mvc:exclude-mapping path="inter/a/**"/> <!--不拦截此路径--> <bean class="com.ryan.testInterceptor.MyInterceptor"/> </mvc:interceptor> </mvc:interceptors>