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
的攔截器的完成方法,而且順序是先註冊後執行。