Spring入门-Interceptor基本使用

SpringMVC提供了拦截器Interceptor,可以用于验证用户登录,它跟过滤器是有区别的,拦截器是Spring提供的,而过滤器是Servlet提供的。

使用拦截器的条件

使用拦截器前面需要进行配置,包括导包、web.xml中配置DispatcherServlet,Spring启动读取文件中配置组件扫描、注解驱动、视图解析器和拦截器。其他就是需要写一个控制器用来进行请求分发处理,还有自定义拦截器。

自定义拦截器

自定义拦截器需要实现HandlerInterceptor接口,实现接口定义的方法。

 1 package Interceptors;
 2 
 3 import javax.servlet.http.HttpServletRequest;
 4 import javax.servlet.http.HttpServletResponse;
 5 
 6 import org.springframework.web.servlet.HandlerInterceptor;
 7 import org.springframework.web.servlet.ModelAndView;
 8 /**
 9  * 拦截器类需要实现HandlerInterceptor接口
10  * @author yangchaolin
11  *
12  */
13 public class SomeInterceptor implements HandlerInterceptor{
14     /**
15      * DispatcherServlet在收到请求后,会先调用preHandler方法,如果该方法的返回值为true,则继续向后调用Controller的方法
16      * 如果返回值是false,则中断请求
17      * 
18      * DispatcherServlet,拦截器、Controller会共享同一个request,response
19      * handler:Controller的方法对象,利用了java反射机制,后面了解学习
20      */
21     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
22             throws Exception {
23         System.out.println("拦截器的preHandle方法执行了");
24         return true;
25     }
26     /**
27      * 是Controller处理完后,在将ModelAndView返回给前端控制器DispatcherServlet之前,执行的方法
28      * 可以在该方法里,修改ModelAndView的处理结果
29      */
30     public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
31             ModelAndView modelAndView) throws Exception {
32         System.out.println("拦截器的postHandle方法执行了");        
33     }
34     /**
35      * 最后执行
36      * ex:是处理器Controller所抛出的异常
37      * 可以写一个拦截器专门处理Controller抛出的异常
38      */
39     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
40             throws Exception {
41         System.out.println("拦截器的afterCompletion方法执行了");        
42     }
43 }

Controller

写一个Controller来测试拦截器方法的执行顺序,里面为了测试多级目录写了两个方法。

 1 package Controller;
 2 
 3 import org.springframework.stereotype.Controller;
 4 import org.springframework.web.bind.annotation.RequestMapping;
 5 
 6 @Controller
 7 public class HelloController {
 8     @RequestMapping("/hello.do")
 9     public String hello() {
10         System.out.println("控制器的hello()方法执行了");
11         return "hello";
12         
13     }
14     /**
15      * 如果路径加一个demo,然而拦截器mapping还是/*的话,将不会拦截
16      * 如果想实现各种路径的拦截,不论几层都能实现拦截效果的话,需要将mapping修改为/**
17      * @return
18      */
19     @RequestMapping("/demo/hello.do")
20     public String hello1() {
21         System.out.println("hello1()");
22         return "hello";        
23     }
24 }

配置拦截器

在Spring启动默认读取文件applicationContext.xml文件中添加拦截器配置,这里只设置了一个拦截器,可以配置多个拦截器,执行顺序从上往下拦截。

 1     <!-- 设置拦截器Interceptor -->
 2     <!-- 如果想要拦截所有的请求,path应该写成/** -->    
 3     <mvc:interceptors>
 4       <!-- 第一个拦截器 -->
 5       <mvc:interceptor>
 6         <mvc:mapping path="/**"/>       
 7         <bean class="Interceptors.SomeInterceptor"></bean>
 8       </mvc:interceptor>
 9       <!-- 后面可以配置多个拦截器,拦截顺序从上到下 -->
10     </mvc:interceptors>

运行结果,只展示hello.do请求,多级目录/demo/hello.do也可以拦截。

控制台输出情况

可以看出来拦截器方法的执行顺序

(1)DispatcherServlet接受到请求后,首先会根据HandlerMapping配置请求的结果(这里使用注解@RequestMapping来完成),查看是否有对应请求Mapping

(2)如果没有匹配路径不再往下执行,如果有请求匹配的话,会先执行拦截器方法preHandle,返回true则继续执行Controller的方法

(3)Controller执行完逻辑准备将结果(String或者ModelAndView)返回给前端控制器前,先执行postHandle方法,如果有异常,接下来在afterCompletion方法中进行处理,最后将结果返回给前端控制器

拦截器用于登录验证

接下来使用拦截器,在前面登录案例的基础上,添加一个用户登录验证,即登录成功的才跳转到后面页面,否则返回到登录页面,前期配置参考博文。

(1)JSP准备

登录页面、主页,sub页,主页用于登录验证,主页直接登录,sub页直接登录。

 1 <%@page pageEncoding="utf-8"%>
 2 <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
 3 <!doctype html>
 4 <html>
 5     <head>
 6       <title>欢迎登录Color Filter-JavaScript登录验证</title>
 7       <meta charset="utf-8">
 8       <link rel="stylesheet" type="text/css" href="css/login.css" />
 9       <!-- <script type="text/javascript" src="script/login.js"></script> -->
10     </head>
11     <body>
12        <!--logo区+段落区-->
13        <div class="logo">
14            <img src="image/LogoCF.jpg">
15            <p id="logoDesc">Sign in to Color Filter</p>
16        </div>
17        <!--主体登录区-->
18        <div class="main">
19           <div id="login">
20               <!--5行2列-->
21               <!--表单用于输入登录信息,提交给服务器  -->
22               <!-- 
23                 onsubmit是表单提交事件,在点击提交按钮时触发。触发时先调用onsubmit内的方法,若该方法返回true则会自动提交表单
24                 返回false则不提交,此处声明的方法可以起到拦截提交的作用,避免账号名和密码都不对时也能提交到服务器
25                 onsubmit="return ((check_username()+check_pwd())==2)"
26                -->
27               <form action="logincheck.do" method="get">
28               <table>
29               <tr>
30                 <td colspan="2" style="text-align: left;text-indent: 29px">Username or email address</td>
31               </tr>
32               <tr>
33                 <!-- 增加切换光标确认用户名格式是否正确 -->
34                 <td colspan="2"><input type="text" name="user"  id="username" onblur="check_username();" value="${username }"></td>
35               </tr>
36               <tr>
37                 <td style="text-align: left;text-indent: 29px;15%">Password</td>
38                 <td style="text-align: left;text-indent: 0px;85%"><a href="#">Forget password?</a></td>
39               </tr>
40               <tr>
41                 <td colspan="2" style=" 345px"><input type="password" name="pwd" id="pwd" onblur="check_pwd();" value="${password }"></td>
42               </tr>
43               <tr>
44                 <td colspan="2" style="text-align: left;text-indent: 29px">Security Code</td>
45               </tr>
46               <tr>
47                 <td style="padding-left:32px;60%;text-align:left;"><input type="text" name="valicode" id="valicode"/></td>
48                 <!-- <td style="padding-top:3px;40%;text-align:right;padding-right:32px"><img alt="验证码" src="createIMG.do" onclick="this.setAttribute('src','createIMG.do?x='+Math.random())"></td> -->
49                 <!-- 添加登录失败提示 -->
50                 <td>${login_fail}</td>
51               </tr>     
52               <tr>
53                 <td colspan="2" id="buttontd"><input type="submit" name="btn" value="Sign in" id="button"></td>
54               </tr>                     
55               </table>
56               </form>  
57           </div>
58           <div id="regist">
59              <p style="text-align: center;">New to Color Filter? <a href="#">Create an account.</a></p>
60           </div> 
61        </div>
62        <!--版权、隐私、法律相关-->
63        <div class="foot">
64           <p><a href="#">Terms</a>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#">Privacy</a>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#">Security</a>&nbsp;&nbsp;&nbsp;&nbsp;Contact Color Filter</p>
65        </div>   
66     </body>
67 
68 </html>
View Code
 1 <%@page pageEncoding="utf-8" contentType="text/html; charset=utf-8"%>
 2 <h1>欢迎登陆</h1><br/>
 3 <!-- 得到服务器返回的user参数,采用el表达式获取 -->
 4 ${user }
 5 <!-- 拦截器测试 -->
 6 <div>
 7   <form action="toSubPage.do" method="post">
 8     <a href="javascript:document.forms[0].submit();">点我继续访问</a>
 9   </form>
10 </div>
View Code
1 <%@page pageEncoding="utf-8" contentType="text/html; charset=utf-8"%>
2 <h1>欢迎来到subPage</h1>
View Code

(2)自定义拦截器类及拦截器配置

拦截器类

 1 package com.boe.interceptor;
 2 
 3 import javax.servlet.http.HttpServletRequest;
 4 import javax.servlet.http.HttpServletResponse;
 5 
 6 import org.springframework.web.servlet.HandlerInterceptor;
 7 import org.springframework.web.servlet.ModelAndView;
 8 
 9 /**
10  * 配置自定义拦截器
11  * @author yangchaolin
12  */
13 public class LoginInterceptor implements HandlerInterceptor{
14     //在一次请求中,DispatcherServlet、拦截器和Controller共用一个request和response
15     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
16             throws Exception {
17         //进行登录验证拦截,除了toLogin.do,logincheck.do都进行拦截
18         Object obj=request.getSession().getAttribute("loginData");
19         if(obj==null) {
20             //返回登录页面
21             System.out.println("没有登录,进行拦截");
22             //重定向,使用不带"/",相对路径
23             response.sendRedirect("toLogin.do");
24             return false;
25         }else {
26             System.out.println("登录成功,继续访问");
27             return true;
28         }        
29     }
30 
31     public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
32             ModelAndView modelAndView) throws Exception {
33         // TODO Auto-generated method stub
34         
35     }
36 
37     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
38             throws Exception {
39         // TODO Auto-generated method stub
40         
41     }
42 }
View Code

applicationContext.xml文件中配置拦截器

1 <!-- 添加拦截器,不拦截进入登录页面,登录验证 -->
2     <mvc:interceptors>
3       <mvc:interceptor>
4         <mvc:mapping path="/**"/>
5         <mvc:exclude-mapping path="/toLogin.do"/>
6         <mvc:exclude-mapping path="/logincheck.do"/>
7         <bean class="com.boe.interceptor.LoginInterceptor"></bean>
8       </mvc:interceptor>
9     </mvc:interceptors>

(3)修改LoginController控制器方法,登录成功后将用户信息保存到session中。

 1 package com.boe.controller;
 2 
 3 import javax.annotation.Resource;
 4 import javax.servlet.http.HttpSession;
 5 
 6 import org.springframework.stereotype.Controller;
 7 import org.springframework.ui.ModelMap;
 8 import org.springframework.web.bind.annotation.RequestMapping;
 9 
10 import com.boe.entity.Admin;
11 import com.boe.entity.userInfo;
12 import com.boe.exception.ApplicationException;
13 import com.boe.service.LoginService;
14 
15 @Controller
16 public class mainController {
17     @Resource(name="loginServiceImpl")
18     private LoginService service;
19     
20     //去到登录页面
21     @RequestMapping("/toLogin.do")
22     public String toLogin() {
23         System.out.println("去到登录页面");
24         return "login";
25     }
26     
27     //验证登录
28     @RequestMapping("/logincheck.do")
29     public String login(userInfo data,ModelMap mm,HttpSession session) {
30         System.out.println("登录验证");
31         System.out.println("用户名为:"+data.getUser());
32         System.out.println("密码为:"+data.getPwd());
33         //处理业务层异常
34         try {
35             Admin admin=service.checkLogin(data.getUser(), data.getPwd());
36             if(admin!=null) {
37                 System.out.println("登录成功");
38                 mm.addAttribute("user",data.getUser());
39                 //登录成功后,将admin信息存入session
40                 session.setAttribute("loginData", admin);
41             }            
42         }catch(Exception e) {
43             //应用错误,即用户填写错误
44             if(e instanceof ApplicationException) {
45                 mm.addAttribute("login_fail", e.getMessage());
46                 mm.addAttribute("username",data.getUser());
47                 mm.addAttribute("password", data.getPwd());
48                 return "login";
49             }
50             //系统错误
51             return "loginNG";
52         }
53         return "loginOK";
54     }
55     
56     //直接进入主页,拦截器测试
57     @RequestMapping("/loginOK.do")
58     public String toMainPage() {
59         System.out.println("准备进入loginOK主页");
60         return "loginOK";
61     }
62     //直接进入sub页,拦截器测试
63     @RequestMapping("/toSubPage.do")
64     public String toSubPage() {
65         System.out.println("准备进入subPage副页");
66         return "subPage";
67     }    
68 }
View Code

(4)测试不登录的情况下,进入loginOK页面,发现被拦截了,并提示没有登录。

控制台情况,显示执行了自定义拦截器的preHandle方法,并返回false,不再执行controller里的方法,进行重定向到登录页面。

(5)测试登录的情况下,访问loginOK.do和toSubPage.do 。

控制台情况,可以看出验证登录是没有拦截的,登录成功后进入主页,然后点击链接时就会被拦截到,因为有登录所以拦截器的preHandle方法返回true并打印出了"登录成功,继续访问",后进入LoginController继续处理逻辑,打印出了"准备进入subPage副页",并返回String结果给前端控制器,让前端控制器分发视图解析器最后完成副页展示。

总结

拦截器可以用于登录验证,但是其属于Spring,如果前端更换框架则不再生效,而过滤器是servlet范畴,配置了过滤器无论怎么更换都会过滤,相比较来说过滤器范围更广。

参考博文:

(1)https://www.cnblogs.com/youngchaolin/p/11354307.html springMVC完成登录页面

(2)https://www.cnblogs.com/youngchaolin/p/10549020.html 过滤器和拦截器

(3)https://blog.csdn.net/koflance/article/details/79635240 URI、URL和URN

原文地址:https://www.cnblogs.com/youngchaolin/p/11363118.html