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;width:15%">Password</td>
38                 <td style="text-align: left;text-indent: 0px;width:85%"><a href="#">Forget password?</a></td>
39               </tr>
40               <tr>
41                 <td colspan="2" style="width: 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;width:60%;text-align:left;"><input type="text" name="valicode" id="valicode"/></td>
48                 <!-- <td style="padding-top:3px;width: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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM