SpringMVC攔截器

燕子去了發表於2024-04-07

攔截器

無攔截器-------------------------->controller------------------------------------>
有攔截器---->preHandle--|---true---controller--postHandle---afterCompletion--|------>
					   |---false--------------------------------------------|

攔截器(Interceptor)是一種動態攔截方法呼叫的機制,在SpringMVC中動態攔截控制器方法的執行;可以在指定的方法呼叫前後執行預先設定的程式碼,或者許可權控制阻止原始方法的執行,總的來說攔截器就是用來做增強。

攔截器和過濾器之間的區別

歸屬不同:Filter屬於Servlet技術,Interceptor屬於SpringMVC技術

攔截內容不同:Filter對所有訪問進行增強,Interceptor僅針對SpringMVC的訪問進行增強

過濾器1--過濾器2--mvc核心--攔截器1--攔截器2--處理器--攔截器2--攔截器1--過濾器2--過濾器1-->

攔截器開發

ProjectInterceptor:重寫HandlerInterceptor介面中的三個方法。

preHandler方法返回true代表放行,繼續執行原始Controller類中要請求的方法;返回false代表攔截,終止原始操作

package com.lmcode.interceptor;

@Component
public class ProjectInterceptor implements HandlerInterceptor {
    //原始方法呼叫前執行的內容
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle...");
        return true;
        /*返回false可以終止原始操作*/
    }
    //原始方法呼叫後執行的內容
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle...");
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }
    //原始方法呼叫完成後執行的內容
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion...");
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

新增攔截器:SpringMVCSupport

package com.lmcode.config;

@Configuration
public class SpringMVCSupport extends WebMvcConfigurationSupport {
    @Autowired
    private ProjectInterceptor projectInterceptor;

    // 放行靜態資源
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
        registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
    }

    // 新增攔截器
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
    }
}

SpringMvcConfig:新增SpringMvcSupport包掃描

package com.lmcode.config;

@Configuration
@ComponentScan({
        "com.lmcode.controller",
        "com.lmcode.advice",
        "com.lmcode.config",
        "com.lmcode.interceptor"})
@EnableWebMvc
public class SpringMvcConfig {
}

新增攔截器方法二【侵入性強,和spring強繫結】

使用SpringMvcConfig實現WebMvcConfigurer方法,可以放行靜態資源或新增攔截器

package com.lmcode.config;

@Configuration
@ComponentScan({"com.itheima.controller"})
@EnableWebMvc
//實現WebMvcConfigurer介面可以簡化開發,但具有一定的侵入性
public class SpringMvcConfig implements WebMvcConfigurer {
    @Autowired
    private ProjectInterceptor projectInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //配置多攔截器
        registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
    }
}

攔截器方法

  • request:請求物件
  • response:響應物件
  • handler:被呼叫的處理器物件,本質上是一個方法物件,對反射中的Method物件進行了再包裝
  • modelAndView:頁面跳轉相關資料
  • ex:如果處理器執行過程中出現異常物件,可以針對異常情況進行單獨處理

現在大多是非同步開發,而且有全域性異常處理器,所以ModelAndView和ex使用率不高;最常用的是preHandle,在這個方法中可以透過返回值來決定是否要進行放行:把業務邏輯放在該方法中,如果滿足業務則返回true放行,不滿足則返回false攔截。

前置處理方法:preHandle
@Override
public boolean preHandle(HttpServletRequest request,HttpServletResponse response,Object handler) throws Exception {
    System.out.println("preHandle");
    return true;
}

使用request物件或response物件可以獲取請求資料中的內容,如獲取請求頭的Content-Type

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    String contentType = request.getHeader("Content-Type");
    System.out.println("preHandle..."+contentType);
    return true;
}

使用handler引數,可以獲取當前方法的相關資訊

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    System.out.println(handler); // com.lmcode.controller.BookController#save(Book)
    System.out.println(handler.getClass()); // class org.springframework.web.method.HandlerMethod
    HandlerMethod hm = (HandlerMethod)handler;
    String methodName = hm.getMethod().getName(); // 獲取方法的名稱
    return true;
}
後置處理方法:postHandle
@Override
public void postHandle(HttpServletRequest request,HttpServletResponse response,Object handler,ModelAndView modelAndView) throws Exception {
    System.out.println("postHandle");
}
完成處理方法:afterCompletion
@Override
public void afterCompletion(HttpServletRequest request,HttpServletResponse response,Object handler,Exception ex) throws Exception {
    // 透過ex可以拿到原始的程式執行過程中出現的異常
    System.out.println("afterCompletion");
}

攔截器鏈

配置多個攔截器形成攔截器鏈

preHandle與配置順序相同,必定執行;postHandle與配置順序相反,可能不執行;afterCompletion與配置順序相反,可能不執行。

兩個攔截器時,當攔截器1返回false時,流程終止,攔截器2的pre也不執行了

三個攔截器時,當1,2正常執行,但是3返回false,最後只會執行1,2的after

package com.lmcode.interceptor;

@Component
public class ProjectInterceptor implements HandlerInterceptor {
    //原始方法呼叫前執行的內容
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle1...");
        return false;
        /*返回false可以終止原始操作*/
    }
    //原始方法呼叫後執行的內容
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle1...");
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }
    //原始方法呼叫完成後執行的內容
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion1...");
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}
package com.lmcode.interceptor;

@Component
public class ProjectInterceptor2 implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle2...");
        return false;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle2...");
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion2...");
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

按照配置攔截器的先後進行攔截

pre1--->pre2--程式碼--->post2--->post1--->after2--->after1

package com.lmcode.config;

@Configuration
public class SpringMVCSupport extends WebMvcConfigurationSupport {
    @Autowired
    private ProjectInterceptor projectInterceptor;
    private ProjectInterceptor2 projectInterceptor2;

    // 新增攔截器
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
        registry.addInterceptor(projectInterceptor2).addPathPatterns("/books","/books/*");
    }
}

相關文章