JavaWeb--Servlet過(guò)濾器Filter和SpringMVC的HandlerInterceptor(Session和Cookie登錄認(rèn)證)

攔截一些請(qǐng)求進(jìn)行處理零抬,比如通過(guò)它來(lái)進(jìn)行權(quán)限驗(yàn)證,或者是來(lái)判斷用戶是否登陸宽涌,日志記錄平夜,編碼,或者限制時(shí)間點(diǎn)訪問(wèn)等等卸亮,是非常有必要的忽妒。所以就有了此篇文章啦。

文章結(jié)構(gòu):(1)Servlet過(guò)濾器Filter兼贸;(2)SpringMVC的HandlerInterceptor段直;(3)對(duì)比認(rèn)知。

一溶诞、Servlet過(guò)濾器Filter:

此部分是從趙四大佬那里學(xué)來(lái)的鸯檬,并補(bǔ)充自己的認(rèn)知

(1)概念:

能夠?qū)ervlet容器的請(qǐng)求和響應(yīng)對(duì)象進(jìn)行檢查和修改。

Servlet過(guò)濾器本身并不產(chǎn)生請(qǐng)求和響應(yīng)對(duì)象螺垢,它只能提供過(guò)濾作用喧务。Servlet過(guò)期能夠在Servlet被調(diào)用之前檢查Request對(duì)象赖歌,修改Request Header和Request內(nèi)容;在Servlet被調(diào)用之后檢查Response對(duì)象功茴,修改Response Header和Response內(nèi)容庐冯。

Servlet過(guò)期負(fù)責(zé)過(guò)濾的Web組件可以是Servlet、JSP或者HTML文件痊土。

總之就是:實(shí)現(xiàn)用戶在訪問(wèn)某個(gè)目標(biāo)資源之前肄扎,對(duì)訪問(wèn)的請(qǐng)求和響應(yīng)進(jìn)行攔截。

(2)特點(diǎn):

A.Servlet過(guò)濾器可以檢查和修改ServletRequest和ServletResponse對(duì)象

B.Servlet過(guò)濾器可以被指定和特定的URL關(guān)聯(lián)赁酝,只有當(dāng)客戶請(qǐng)求訪問(wèn)該URL時(shí),才會(huì)觸發(fā)過(guò)濾器

C.Servlet過(guò)濾器可以被串聯(lián)在一起旭等,形成管道效應(yīng)酌呆,協(xié)同修改請(qǐng)求和響應(yīng)對(duì)象

(3)作用:

A.查詢請(qǐng)求并作出相應(yīng)的行動(dòng)。

B.阻塞請(qǐng)求-響應(yīng)對(duì)搔耕,使其不能進(jìn)一步傳遞隙袁。

C.修改請(qǐng)求的頭部和數(shù)據(jù)。用戶可以提供自定義的請(qǐng)求弃榨。

D.修改響應(yīng)的頭部和數(shù)據(jù)菩收。用戶可以通過(guò)提供定制的響應(yīng)版本實(shí)現(xiàn)。

E.與外部資源進(jìn)行交互鲸睛。

(3)適用場(chǎng)合:

A.認(rèn)證過(guò)濾

B.登錄和審核過(guò)濾

C.圖像轉(zhuǎn)換過(guò)濾

D.?dāng)?shù)據(jù)壓縮過(guò)濾

E.加密過(guò)濾

F.令牌過(guò)濾

G.資源訪問(wèn)觸發(fā)事件過(guò)濾

H.XSL/T過(guò)濾

I.Mime-type過(guò)濾

(4)認(rèn)知Filter接口源碼:

public interface Filter {
        //Servlet過(guò)濾器的初始化方法娜饵,Servlet容器創(chuàng)建Servlet過(guò)濾器實(shí)例后將調(diào)用這個(gè)方法。在這個(gè)方法中可以讀取web.xml文件中Servlet過(guò)濾器的初始化參數(shù)
    public void init(FilterConfig filterConfig) throws ServletException;
    //完成實(shí)際的過(guò)濾操作官辈,當(dāng)客戶請(qǐng)求訪問(wèn)于過(guò)濾器關(guān)聯(lián)的URL時(shí)箱舞,Servlet容器將先調(diào)用過(guò)濾器的doFilter方法。FilterChain參數(shù)用于訪問(wèn)后續(xù)過(guò)濾器
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException;
         //Servlet容器在銷毀過(guò)濾器實(shí)例前調(diào)用該方法拳亿,這個(gè)方法中可以釋放Servlet過(guò)濾器占用的資源
    public void destroy();
}

(5)認(rèn)知Filter為何可以攔截請(qǐng)求:(本博主找不到具體的代碼調(diào)用晴股,只能找到相關(guān)的幾個(gè)接口估測(cè))

FilterChain

public interface FilterChain {
//此方法是由Servlet容器提供給開(kāi)發(fā)者的,用于對(duì)資源請(qǐng)求過(guò)濾鏈的依次調(diào)用肺魁,通過(guò)FilterChain調(diào)用過(guò)濾鏈中的下一個(gè)過(guò)濾  器电湘,如果是最后一個(gè)過(guò)濾器,則下一個(gè)就調(diào)用目標(biāo)資源鹅经。
    public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException;
}

FilterConfig寂呛。FilterConfig接口檢索過(guò)濾器名、初始化參數(shù)以及活動(dòng)的Servlet上下文瞬雹。

public interface FilterConfig {
 //返回web.xml部署文件中定義的該過(guò)濾器的名稱
    String getFilterName();
 //返回調(diào)用者所處的servlet上下文
    ServletContext getServletContext();
//返回過(guò)濾器初始化參數(shù)值的字符串形式昧谊,當(dāng)參數(shù)不存在時(shí),返回nul1.name是初始化參數(shù)名
    String getInitParameter(String var1);
//以Enumeration形式返回過(guò)濾器所有初始化參數(shù)值酗捌,如果沒(méi)有初始化參數(shù)呢诬,返回為空
    Enumeration<String> getInitParameterNames();
}

博主猜測(cè)是:web服務(wù)器的底層源碼機(jī)制的模板方法模式涌哲,默認(rèn)調(diào)用doFilter時(shí),先去執(zhí)行filterClain的doFilter尚镰。從而進(jìn)行攔截

(6)Servlet過(guò)濾器對(duì)響應(yīng)的過(guò)濾過(guò)程:

A.過(guò)濾器截獲客戶端的請(qǐng)求

B.重新封裝ServletResponse阀圾,在封裝后的ServletResponse中提供用戶自定義的輸出流

C.將請(qǐng)求向后續(xù)傳遞

D.Web組件產(chǎn)生響應(yīng)

E.從封裝后的ServletResponse中獲取用戶自定義的輸出流

F.將響應(yīng)內(nèi)容通過(guò)用戶自定義的輸出流寫(xiě)入到緩沖流中

G.在緩沖流中修改響應(yīng)的內(nèi)容后清空緩沖流,輸出響應(yīng)內(nèi)容

(7)實(shí)例:(取自上文介紹的趙四大佬那里)

1. 注冊(cè):在web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>testFilter</display-name>
  
  <!-- 請(qǐng)求url日志記錄過(guò)濾器 -->    
    <filter>    
        <filter-name>logfilter</filter-name>    
        <filter-class>com.fuzhu.LogFilter</filter-class>    
    </filter>    
    <filter-mapping>    
        <filter-name>logfilter</filter-name>    
        <url-pattern>/*</url-pattern>    
    </filter-mapping>  
      
<!-- 編碼過(guò)濾器 -->    
    <filter>    
        <filter-name>setCharacterEncoding</filter-name>    
        <filter-class>com.fuzhu.EncodingFilter</filter-class>    
        <init-param>    
            <param-name>encoding</param-name>    
            <param-value>utf-8</param-value>    
        </init-param>    
    </filter>    
    <filter-mapping>    
        <filter-name>setCharacterEncoding</filter-name>    
        <url-pattern>/*</url-pattern>    
    </filter-mapping>    
</web-app>

既然注冊(cè)了狗唉,那實(shí)現(xiàn)呢初烘?

package com.fuzhu;

import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class EncodingFilter implements Filter {    
    private String encoding;    
    private HashMap<String,String> params = new HashMap<String,String>();    
    // 項(xiàng)目結(jié)束時(shí)就已經(jīng)進(jìn)行銷毀    
    public void destroy() {    
        System.out.println("end do the encoding filter!");    
        params=null;    
        encoding=null;    
    }    
    public void doFilter(ServletRequest req, ServletResponse resp,FilterChain chain) throws IOException, ServletException {    
        System.out.println("before encoding " + encoding + " filter!");    
        req.setCharacterEncoding(encoding);    
        chain.doFilter(req, resp);          
        System.out.println("after encoding " + encoding + " filter分俯!");    
        System.err.println("----------------------------------------");    
    }    
     
    // 項(xiàng)目啟動(dòng)時(shí)就已經(jīng)進(jìn)行讀取    
    public void init(FilterConfig config) throws ServletException {    
        System.out.println("begin do the encoding filter!");    
        encoding = config.getInitParameter("encoding");    
        for (Enumeration<?> e = config.getInitParameterNames(); e.hasMoreElements();) {    
            String name = (String) e.nextElement();    
            String value = config.getInitParameter(name);    
            params.put(name, value);    
        }    
    }    
 }    

package com.fuzhu;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

public class LogFilter implements Filter {    
    
  public FilterConfig config;    
   
  public void destroy() {    
      this.config = null;    
      System.out.println("end do the logging filter!");  
  }    
   
  public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {    
      System.out.println("before the log filter!");    
      // 將請(qǐng)求轉(zhuǎn)換成HttpServletRequest 請(qǐng)求    
      HttpServletRequest hreq = (HttpServletRequest) req;    
      // 記錄日志    
      System.out.println("Log Filter已經(jīng)截獲到用戶的請(qǐng)求的地址:"+hreq.getServletPath() );    
      try {    
          // Filter 只是鏈?zhǔn)教幚砩隹穑?qǐng)求依然轉(zhuǎn)發(fā)到目的地址。    
          chain.doFilter(req, res);    
      } catch (Exception e) {    
          e.printStackTrace();    
      }    
      System.out.println("after the log filter!");    
  }    
   
  public void init(FilterConfig config) throws ServletException {    
      System.out.println("begin do the log filter!");    
      this.config = config;    
  }    
   
}    

接下來(lái)就是測(cè)試?yán)玻?/h3>
package com.fuzhu;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/FilterServlet")
public class FilterServlet extends HttpServlet {  
  
    private static final long serialVersionUID = 1L;  
  
    public void doGet(HttpServletRequest request, HttpServletResponse response)  
            throws ServletException, IOException {  
        response.setDateHeader("expires", -1);  
    }  
  
    public void doPost(HttpServletRequest request, HttpServletResponse response)  
            throws ServletException, IOException {  
    }  
  
}  

再著就是發(fā)布啦缸剪。注意下吗铐,我們先注冊(cè)日志過(guò)濾器,然后注冊(cè)編碼器

這里寫(xiě)圖片描述

(8)我們來(lái)看下注意事項(xiàng):

A.由于Filter杏节、FilterConfig唬渗、FilterChain都是位于javax.servlet包下,并非HTTP包所特有的奋渔,所以其中所用到的請(qǐng)求镊逝、響應(yīng)對(duì)象ServletRequest、ServletResponse在使用前都必須先轉(zhuǎn)換成HttpServletRequest嫉鲸、HttpServletResponse再進(jìn)行下一步操作撑蒜。

B.在web.xml中配置Servlet和Servlet過(guò)濾器,應(yīng)該先聲明過(guò)濾器元素充坑,再聲明Servlet元素

C.如果要在Servlet中觀察過(guò)濾器生成的日志减江,應(yīng)該確保在server.xml的localhost對(duì)應(yīng)的<host>元素中配置如下<logger>元素:

<Logger className = “org.apache.catalina.logger.FileLogger”

directory = “l(fā)ogs”prefix = “l(fā)ocalhost_log.”suffix=”.txt”

timestamp = “true”/>


二、SpringMVC的HandlerInterceptor(給出一個(gè)登錄功能的攔截Demo)

(1)springMVC攔截器的實(shí)現(xiàn)一般有兩種方式:

第一種方式是要定義的Interceptor類要實(shí)現(xiàn)了Spring的HandlerInterceptor 接口

第二種方式是繼承實(shí)現(xiàn)了HandlerInterceptor接口的類捻爷,比如Spring已經(jīng)提供的實(shí)現(xiàn)了HandlerInterceptor接口的抽象類HandlerInterceptorAdapter

(2)概念及作用:

概念:Spring MVC允許你通過(guò)處理攔截?cái)r截web請(qǐng)求辈灼,進(jìn)行前置處理和后置處理。處理攔截是在Spring的web應(yīng)用程序上下文中配置的也榄,因此它們可以利用各種容器特性巡莹,并引用容器中聲明的任何Bean。處理攔截是針對(duì)特殊的處理程序映射進(jìn)行注冊(cè)的甜紫,因此它只攔截通過(guò)這些處理程序映射的請(qǐng)求降宅。

主要作用是攔截用戶的請(qǐng)求并進(jìn)行相應(yīng)的處理,其他的作用比如通過(guò)它來(lái)進(jìn)行權(quán)限驗(yàn)證囚霸,或者是來(lái)判斷用戶是否登陸腰根,日志記錄,或者限制時(shí)間點(diǎn)訪問(wèn)拓型。

(3)認(rèn)識(shí)HandlerInterceptor接口:

public interface HandlerInterceptor {
//該方法將在請(qǐng)求處理之前進(jìn)行調(diào)用额嘿。該方法將在請(qǐng)求處理之前進(jìn)行調(diào)用瘸恼,只有該方法返回true,才會(huì)繼續(xù)執(zhí)行后續(xù)的Interceptor和Controller
    boolean preHandle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;
//在當(dāng)前請(qǐng)求進(jìn)行處理之后册养,也就是Controller 方法調(diào)用之后執(zhí)行
    void postHandle(HttpServletRequest var1, HttpServletResponse var2, Object var3, ModelAndView var4) throws Exception;
//該方法將在整個(gè)請(qǐng)求結(jié)束之后东帅,也就是在DispatcherServlet 渲染了對(duì)應(yīng)的視圖之后執(zhí)行。
    void afterCompletion(HttpServletRequest var1, HttpServletResponse var2, Object var3, Exception var4) throws Exception;
}

preHandle:

SpringMVC 中的Interceptor 是鏈?zhǔn)降恼{(diào)用的球拦,在一個(gè)應(yīng)用中或者說(shuō)是在一個(gè)請(qǐng)求中可以同時(shí)存在多個(gè)Interceptor 靠闭。每個(gè)Interceptor 的調(diào)用會(huì)依據(jù)它的聲明順序依次執(zhí)行,而且最先執(zhí)行的都是Interceptor 中的preHandle 方法坎炼,所以可以在這個(gè)方法中進(jìn)行一些前置初始化操作或者是對(duì)當(dāng)前請(qǐng)求的一個(gè)預(yù)處理愧膀,也可以在這個(gè)方法中進(jìn)行一些判斷來(lái)決定請(qǐng)求是否要繼續(xù)進(jìn)行下去。該方法的返回值是布爾值Boolean 類型的点弯,當(dāng)它返回為false 時(shí)扇调,表示請(qǐng)求結(jié)束,后續(xù)的Interceptor 和Controller 都不會(huì)再執(zhí)行抢肛;當(dāng)返回值為true 時(shí)就會(huì)繼續(xù)調(diào)用下一個(gè)Interceptor 的preHandle 方法,如果已經(jīng)是最后一個(gè)Interceptor 的時(shí)候就會(huì)是調(diào)用當(dāng)前請(qǐng)求的Controller 方法碳柱。

postHandle:

只能是在當(dāng)前所屬的Interceptor 的preHandle 方法的返回值為true 時(shí)才能被調(diào)用捡絮。Controller 方法調(diào)用之后執(zhí)行,但是它會(huì)在DispatcherServlet 進(jìn)行視圖返回渲染之前被調(diào)用莲镣,所以我們可以在這個(gè)方法中對(duì)Controller 處理之后的ModelAndView 對(duì)象進(jìn)行操作福稳。postHandle 方法被調(diào)用的方向跟preHandle 是相反的,也就是說(shuō)先聲明的Interceptor 的postHandle 方法反而會(huì)后執(zhí)行瑞侮。

afterCompletion:

該方法也是需要當(dāng)前對(duì)應(yīng)的Interceptor 的preHandle 方法的返回值為true 時(shí)才會(huì)執(zhí)行的圆。顧名思義,該方法將在整個(gè)請(qǐng)求結(jié)束之后半火,也就是在DispatcherServlet 渲染了對(duì)應(yīng)的視圖之后執(zhí)行越妈。這個(gè)方法的主要作用是用于進(jìn)行資源清理工作的。 我們的系統(tǒng)日志的攔截在這個(gè)方法中钮糖,可以記錄日志的相關(guān)的參數(shù)梅掠,檢測(cè)方法的執(zhí)行。

第一個(gè)和第二個(gè)方法分別是在處理程序處理請(qǐng)求之前和之后被調(diào)用的店归。第二個(gè)方法還允許訪問(wèn)返回的ModelAndView對(duì)象阎抒,因此可以在它里面操作模型屬性。最后一個(gè)方法是在所有請(qǐng)求處理完成之后被調(diào)用的(如視圖呈現(xiàn)之后).

(4)先來(lái)個(gè)Helloworld:

在springmvc配置文件那里配置攔截器消痛,攔截的請(qǐng)求且叁。

可以看到我一會(huì)實(shí)現(xiàn)的一個(gè)功能啦,登錄的認(rèn)證秩伞。
<!-- 配置攔截器 -->
    <mvc:interceptors>
        <!-- 配置登陸攔截器 -->
        <mvc:interceptor>
            <!--攔截后臺(tái)頁(yè)面的請(qǐng)求-->
            <!--<mvc:mapping path="/backend/**"/>-->
            <mvc:mapping path="/test/testMethod"/>
            <!--不攔截登錄頁(yè)和登錄的請(qǐng)求-->
            <!--<mvc:exclude-mapping path="/backend/loginPage"/>-->
            <!--<mvc:exclude-mapping path="/backend/login"/>-->
            <bean class="com.fuzhu.Interceptor.Myinterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

請(qǐng)求的實(shí)現(xiàn):

@RestController
@RequestMapping("/test")
public class TestController {
 @RequestMapping(value = "/testMethod",produces="text/html;charset=UTF-8", method = {RequestMethod.GET,RequestMethod.GET})
    public String test() {
        Score score = new Score();
//        score.setChangeType("玩游戲");
//        score.setScore(10);
//        scoreService.insertScore(score);
        return JSON.toJSONString(score);
    }
}
這里寫(xiě)圖片描述
這里寫(xiě)圖片描述

(5)實(shí)現(xiàn)后臺(tái)管理頁(yè)面的登錄攔截(其實(shí)就是面向前端的攔截)

作用是:就是在后臺(tái)管理者登錄之前逞带,都必須經(jīng)過(guò)登錄才可進(jìn)入管理界面欺矫,其他侵入性的接口也不可訪問(wèn)。

(一)注冊(cè)我們的攔截器先:

 <!-- 配置攔截器 -->
    <mvc:interceptors>
        <!-- 配置登陸攔截器 -->
        <mvc:interceptor>
            <!--攔截后臺(tái)頁(yè)面的請(qǐng)求-->
            <mvc:mapping path="/backend/**"/>
            <!--<mvc:mapping path="/test/testMethod"/>-->
            <!--不攔截登錄頁(yè)和登錄的請(qǐng)求-->
            <mvc:exclude-mapping path="/backend/loginPage"/>
            <mvc:exclude-mapping path="/backend/login"/>
            <!--<bean class="com.fuzhu.Interceptor.Myinterceptor"></bean>-->
            <bean class="com.fuzhu.Interceptor.LoginInterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

(二)實(shí)現(xiàn)攔截器:針對(duì)后臺(tái)管理系統(tǒng)的需要掰担,不能讓別人隨便用url直接訪問(wèn)到別的服務(wù)器應(yīng)用請(qǐng)求汇陆,必須先登錄。所以我們做一個(gè)登錄認(rèn)證的攔截器带饱。而且需要認(rèn)證一系列的cookie毡代,session

public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response, Object obj, Exception err)
            throws Exception {
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
                           Object obj, ModelAndView mav) throws Exception {

    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                             Object obj) throws Exception {
          //拿到cookie
          //也就是獲取session里的登錄狀態(tài)值
        String cookie= CookieUtil.getByName(request,"isLogin");
        if (cookie!=null){
        //session解密
            Map<String,Object> map= AuthUtil.decodeSession(cookie);
            String loginStatus= (String) map.get("isLogin");
            Long timestamp= (Long) map.get("timestamp");
            if (loginStatus!=null&&timestamp!=null&&new Date().getTime()-timestamp<1000*60*60*24*10){
                return true;
            }
        }
        //沒(méi)有找到登錄狀態(tài)則重定向到登錄頁(yè),返回false勺疼,不執(zhí)行原來(lái)controller的方法
        response.sendRedirect("/backend/loginPage");
        return false;
    }
}

(三)為了充分去了解Session和cookie機(jī)制教寂,本博主再做了兩個(gè)工具類,一個(gè)是session的工具類执庐,一個(gè)是cookie的工具類酪耕,還有另外一篇解析博客(附帶面向客戶端的Demo)--也是一個(gè)目前最流行的認(rèn)證方式--Token認(rèn)證

WEB后臺(tái)--基于Token的WEB后臺(tái)登錄認(rèn)證機(jī)制(并講解其他認(rèn)證機(jī)制以及cookie和session機(jī)制)

//session工具類
public class AuthUtil {
//這個(gè)類方法是面向手機(jī)客戶端的轨淌,從而實(shí)現(xiàn)的Token機(jī)制迂烁。實(shí)現(xiàn)請(qǐng)見(jiàn)上述文章:
    private static Map<String, Object> getClientLoginInfo(HttpServletRequest request) throws Exception {
        Map<String, Object> r = new HashMap<>();
        String sessionId = request.getHeader("sessionId");
        if (sessionId != null) {
            r = decodeSession(sessionId);
            return r;
        }
        throw new Exception("session解析錯(cuò)誤");
    }
//根據(jù)token拿去用戶id
    public static Long getUserId(HttpServletRequest request) throws Exception {
        return  Long.valueOf((Integer)getClientLoginInfo(request).get("userId"));

    }

    /**
     * session解密
     */
    public static Map<String, Object> decodeSession(String sessionId) {
        try {
            return verifyJavaWebToken(sessionId);
        } catch (Exception e) {
            System.err.println("");
            return null;
        }
    }
}

cookie工具類:

public class CookieUtil {

    public static final int TIME = 60 * 60 * 24 * 10;  //10天存活時(shí)間
//添加cookie
    public static void addCookie(HttpServletResponse response,
                                 String cookieName, String value) {
        Cookie cookie = new Cookie(cookieName, value);
        cookie.setPath("/");
        cookie.setMaxAge(TIME);
        response.addCookie(cookie);
    }
//刪除cookie
    public static void deleteCookie(HttpServletResponse response,
                                    String cookieName) {
        Cookie cookie = new Cookie(cookieName, null);
        cookie.setPath("/");
        cookie.setMaxAge(0);
        response.addCookie(cookie);
    }
//獲取用戶的cookie名字
    public static String getByName(HttpServletRequest request, String cookieName) {
        String value = null;
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (cookieName.equals(cookie.getName())) {
                    value = cookie.getValue();
                }
            }
        }
        return value;
    }

}

(四)怎么去使用這個(gè)機(jī)制以及攔截器呢?递鹉?

@Controller
@RequestMapping("/backend")
public class BackstageController {
//首先是登錄頁(yè)面
    @RequestMapping(value = "/loginPage", method = {RequestMethod.GET})
    public String loginPage(HttpServletRequest request, String account, String password) {
        return "login";
    }
//登錄的接口邏輯
    @RequestMapping(value = "/login", method = {RequestMethod.POST})
    public String login(HttpServletRequest request, HttpServletResponse response, RedirectAttributes model, String account, String password) {
    //后臺(tái)管理者的賬號(hào)密碼
        if ("fuzhu".equals(account) && "fuzhucheng".equals(password)) {
            Map<String, Object> loginInfo = new HashMap<>();
            loginInfo.put("isLogin", "yes!");
            loginInfo.put("timestamp", new Date());
            String sessionId = JavaWebToken.createJavaWebToken(loginInfo);//token機(jī)制盟步,詳情請(qǐng)看上文所說(shuō)的文章
            CookieUtil.addCookie(response,"isLogin",sessionId);//加cookie
            return "redirect:loginSuccess";//重定向
        } else {
            model.addFlashAttribute("error", "密碼錯(cuò)誤");
            return "redirect:loginPage";
        }
    }
    @RequestMapping(value = "/loginSuccess", method = {RequestMethod.GET})
    public String accusationPage(HttpServletRequest request) {
        return "success";
    }
    //主動(dòng)登出的時(shí)候使用
    @RequestMapping(value = "/logOut", method = {RequestMethod.GET})
    public String loginOut(HttpServletRequest request, HttpServletResponse response) {
        CookieUtil.deleteCookie(response,"isLogin");
        return "redirect:loginPage";
    }
}

(五)演示:

這里寫(xiě)圖片描述
登錄成功
這里寫(xiě)圖片描述
如果我們不登錄,直接訪問(wèn)登錄成功的url躏结。結(jié)果如下:默認(rèn)返回登錄頁(yè)面(因?yàn)槲覀償r截重定向了)
這里寫(xiě)圖片描述

三却盘、對(duì)比認(rèn)知:閱讀上文所述的接口并參考此文

(1)filter基于filter接口中的doFilter回調(diào)函數(shù),interceptor則基于Java本身的反射機(jī)制媳拴;

比如HandlerInterceptor是交給spring bean工廠去反射生成的黄橘。

(2)filter是依賴于servlet容器的,沒(méi)有servlet容器就無(wú)法回調(diào)doFilter方法屈溉,而interceptor與servlet無(wú)關(guān)塞关;

(3)filter的過(guò)濾范圍比interceptor大,filter除了過(guò)濾請(qǐng)求外通過(guò)通配符可以保護(hù)頁(yè)面语婴、圖片描孟、文件等,而interceptor只能過(guò)濾請(qǐng)求砰左,只對(duì)controller起作用匿醒,在controller之前開(kāi)始,在controller完成后結(jié)束(如被攔截缠导,不執(zhí)行action)廉羔;

(4)filter的過(guò)濾一般在加載的時(shí)候在init方法聲明,而interceptor可以通過(guò)在xml聲明是guest請(qǐng)求還是user請(qǐng)求來(lái)辨別是否過(guò)濾僻造;

(5)interceptor可以訪問(wèn)controller上下文憋他、值棧里的對(duì)象孩饼,而filter不能;

(6)在controller的生命周期中竹挡,攔截器可以被多次調(diào)用镀娶,而過(guò)濾器只能在容器初始化時(shí)被調(diào)用一次。


源碼下載:SpringMVC的HandlerInterceptor(Session和Cookie登錄認(rèn)證)

好了揪罕,JavaWeb--Servlet過(guò)濾器Filter和SpringMVC的HandlerInterceptor(Session和Cookie登錄認(rèn)證)講完了梯码,這是項(xiàng)目過(guò)程中一個(gè)必須登錄認(rèn)證機(jī)制,現(xiàn)在羅列給大家好啰,這是積累的必經(jīng)一步轩娶,我會(huì)繼續(xù)出這個(gè)系列文章,分享經(jīng)驗(yàn)給大家框往。歡迎在下面指出錯(cuò)誤鳄抒,共同學(xué)習(xí)!椰弊!你的點(diǎn)贊是對(duì)我最好的支持P斫Α!

更多內(nèi)容秉版,可以訪問(wèn)JackFrost的博客

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末闹司,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子沐飘,更是在濱河造成了極大的恐慌,老刑警劉巖牲迫,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件耐朴,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡盹憎,警方通過(guò)查閱死者的電腦和手機(jī)筛峭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)陪每,“玉大人影晓,你說(shuō)我怎么就攤上這事¢莺蹋” “怎么了挂签?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)盼产。 經(jīng)常有香客問(wèn)我饵婆,道長(zhǎng),這世上最難降的妖魔是什么戏售? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任侨核,我火速辦了婚禮草穆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘搓译。我一直安慰自己悲柱,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布些己。 她就那樣靜靜地躺著豌鸡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪轴总。 梳的紋絲不亂的頭發(fā)上直颅,一...
    開(kāi)封第一講書(shū)人閱讀 51,688評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音怀樟,去河邊找鬼功偿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛往堡,可吹牛的內(nèi)容都是我干的械荷。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼虑灰,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼吨瞎!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起穆咐,我...
    開(kāi)封第一講書(shū)人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤颤诀,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后对湃,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體崖叫,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年拍柒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了心傀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡拆讯,死狀恐怖脂男,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情种呐,我是刑警寧澤宰翅,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站陕贮,受9級(jí)特大地震影響堕油,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一掉缺、第九天 我趴在偏房一處隱蔽的房頂上張望卜录。 院中可真熱鬧,春花似錦眶明、人聲如沸艰毒。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)丑瞧。三九已至,卻和暖如春蜀肘,著一層夾襖步出監(jiān)牢的瞬間绊汹,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工扮宠, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留西乖,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓坛增,卻偏偏與公主長(zhǎng)得像获雕,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子收捣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容