1. 程式人生 > >SpringMVC(七)攔截器

SpringMVC(七)攔截器

SpringMVC(七)攔截器

當請求來到DispatcherServlet時,它會根據HandlerMapping的機制找到處理器,這樣就返回一個HandlerExecutionChain物件,這個物件包含處理器和攔截器。這裡的攔截器會對處理器進行攔截,這樣通過攔截器就可以增強處理器的功能。

攔截器的設計

所有攔截器都要實現HandlerInterceptor介面。

HandlerInterceptor原始碼

public interface HandlerInterceptor {

	//處理器執行前方法
	boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception; //處理器處理後方法 void postHandle( HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception; //處理器完成後方法 void afterCompletion( HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception; }

攔截器流程

具體的流程如下
攔截器執行過程

  • 執行preHandler方法,該方法會返回一個布林值。如果為false,就結束所有流程;如果為true,則執行下一步
  • 執行處理器的邏輯,它包含控制器的功能
  • 執行postHandler方法
  • 執行檢視解析和檢視模型
  • 執行afterCompetion方法

開發攔截器

通過實現HandlerInterceptor介面來寫一個簡單的攔截器

MyInterceptor

package com.lay.
mvc.interceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @Description: 簡單的攔截器 * @Author: lay * @Date: Created in 14:07 2018/11/15 * @Modified By:IntelliJ IDEA */ public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("處理器前方法"); //返回true,不會攔截後續的處理 return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("處理後方法"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("處理完成方法"); } }

這裡重寫了HandlerInterceptor的三個攔截器方法,在中間列印了一些資訊。

有了這個攔截器,spring mvc並不會發現它,它還需要進行註冊才能夠攔截處理器,為此需要在配置檔案中實現WebMmcConfigurer介面,並覆蓋addInterceptors方法進行註冊攔截器。

InterceptorCofig 攔截器註冊

package com.lay.mvc.config;

import com.lay.mvc.interceptor.MyInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @Description:攔截器配置
 * @Author: lay
 * @Date: Created in 14:18 2018/11/15
 * @Modified By:IntelliJ IDEA
 */
@Configuration
public class InterceptorCofig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //註冊攔截器到Spring MVC機制,然後它會返回一個攔截器註冊
        InterceptorRegistration ir = registry.addInterceptor(new MyInterceptor());
        //指定攔截匹配模式,限制攔截器攔截請求
        ir.addPathPatterns("/interceptor/*");
    }
}

這裡指定了攔截器的模式,所以它只會攔截與正則式"/interceptor/*"匹配的請求。

接著建立一個用於測試的控制器

InterceptorController

package com.lay.mvc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * @Description: 攔截器控制器
 * @Author: lay
 * @Date: Created in 14:23 2018/11/15
 * @Modified By:IntelliJ IDEA
 */
@Controller
@RequestMapping("/interceptor")
public class InterceptorController {
    @GetMapping("/start")
    public String start(){
        System.out.println("執行處理器邏輯");
        return "/welcome";
    }
}

這裡寫了處理器邏輯,並且返回一個檢視

welcome.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

<head>
    <meta charset="UTF-8">
    <title>檔案上傳</title>
</head>
<body>
    <h1>welcome</h1>
</body>
</html>

控制檯出如下

處理器前方法
執行處理器邏輯
處理後方法
處理完成方法

多個攔截器

註冊順序

registry.addInterceptor(new MyInterceptor1());
registry.addInterceptor(new MyInterceptor2());
registry.addInterceptor(new MyInterceptor3());

列印日誌

【MyInterceptor1】處理器前方法
【MyInterceptor2】處理器前方法
【MyInterceptor3】處理器前方法
執行處理器邏輯
【MyInterceptor3】處理後方法
【MyInterceptor2】處理後方法
【MyInterceptor1】處理後方法
【MyInterceptor3】處理完成方法
【MyInterceptor2】處理完成方法
【MyInterceptor1】處理完成方法

可以看到多個攔截器同時作用的時候,遵循責任鏈式規則。對於處理器前方法採用先註冊限制性,而處理器後方法和完成方法則是先註冊後執行的規則。但這也只是測試了所有攔截器前方法都返回true的場景。如果我們將MyInterceptor2的前方法preHandler返回值改為false

【MyInterceptor1】處理器前方法
【MyInterceptor2】處理器前方法
【MyInterceptor1】處理完成方法

從日誌可以看出,處理器前方法會執行,但是一旦返回false,則後續的攔截器、處理器和所有的攔截器的處理器後方法都不會執行。完成方法afterCompletion則不一樣,它只會執行返回true的攔截器的完成方法,而且順序是先註冊後執行。