自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Spring Boot攔截器詳解

開發(fā) 前端
攔截器在不同框架中有不同的實現(xiàn)方式。比如,在 Spring MVC 中,可以實現(xiàn) HandlerInterceptor 接口或繼承 HandlerInterceptorAdapter 類。需要實現(xiàn) preHandle()、postHandle() 和 afterCompletion() 等方法。

攔截器(Interceptor)與過濾器(Filter)類似,是面向切面編程的一種具體實現(xiàn)。你可以使用攔截器執(zhí)行某些任務(wù),比如在控制器處理請求前記錄日志、更新配置等。在 Spring 中,當請求發(fā)送到控制器時,在被控制器處理之前,它必須經(jīng)過攔截器。

攔截器與過濾器的區(qū)別

攔截器(Interceptor)和過濾器(Filter)的主要區(qū)別在于作用范圍和實現(xiàn)方式。

作用范圍

  • 過濾器作用于整個 Web 應(yīng)用程序,可以過濾所有請求和響應(yīng)。它是 Servlet 規(guī)范的一部分,由 Servlet 容器管理。
  • 攔截器通常作用于特定框架。比如,在 Spring Boot 中,它主要攔截特定框架的請求處理流程,并在特定框架內(nèi)處理請求。

實現(xiàn)方式

  • 過濾器實現(xiàn) javax.servlet.Filter 接口,并在 web.xml 中或通過注解進行配置。需要實現(xiàn) init()、doFilter() 和 destroy() 等方法。
  • 攔截器在不同框架中有不同的實現(xiàn)方式。比如,在 Spring MVC 中,可以實現(xiàn) HandlerInterceptor 接口或繼承 HandlerInterceptorAdapter 類。需要實現(xiàn) preHandle()、postHandle() 和 afterCompletion() 等方法。

攔截器的作用

  1. 登錄驗證和訪問控制:攔截器可用于檢查用戶的登錄狀態(tài)和權(quán)限,并根據(jù)需要執(zhí)行相關(guān)處理。比如,可以使用攔截器驗證用戶的登錄狀態(tài)。如果未登錄,則重定向到登錄頁面或返回相應(yīng)的錯誤信息。
  2. 異常處理和統(tǒng)一錯誤處理:攔截器可以捕獲并處理請求處理過程中發(fā)生的異常??梢愿鶕?jù)異常類型執(zhí)行適當?shù)奶幚恚热绶祷刈远x錯誤頁面或錯誤信息,或執(zhí)行特定的錯誤處理邏輯。當然,它還有許多其他應(yīng)用場景,這里不再一一列舉。

自定義攔截器

如果你需要自定義攔截器,必須實現(xiàn) org.springframework.web.servlet.HandlerInterceptor 接口或繼承 org.springframework.web.servlet.handler.HandlerInterceptorAdapter 類,并且需要重寫以下三個方法:

  1. **preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)**:此方法在請求處理之前調(diào)用。該方法在攔截器類中首先執(zhí)行,用于一些預初始化操作或?qū)Ξ斍罢埱筮M行預處理。你還可以進行一些判斷,以確定請求是否應(yīng)該繼續(xù)。此方法的返回值為布爾類型。當它返回 false 時,表示請求結(jié)束,后續(xù)的攔截器和控制器將不再執(zhí)行。當它返回 true 時,將調(diào)用下一個攔截器的 preHandle 方法。如果已經(jīng)是最后一個攔截器,則將調(diào)用當前請求的控制器方法。
  2. **postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)**:此方法在當前請求處理完成后執(zhí)行,即在控制器方法被調(diào)用之后。但是,它將在 DispatcherServlet 渲染視圖之前被調(diào)用。因此,我們可以在此方法中在控制器處理后對 ModelAndView 對象進行操作。
  3. **afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex)**:只有當相應(yīng)攔截器類的 postHandle 方法的返回值為 true 時,此方法才會執(zhí)行。顧名思義,此方法將在整個請求結(jié)束后執(zhí)行,即在 DispatcherServlet 渲染相應(yīng)視圖之后。此方法主要用于資源清理。

接下來,讓我們通過實際代碼學習。以用戶登錄權(quán)限驗證為例:

用戶登錄權(quán)限驗證

1.自定義攔截器

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

@Component
publicclass LoginInterceptor implements HandlerInterceptor {

    // 在調(diào)用目標方法之前執(zhí)行的方法。
    // 返回 true 表示攔截器驗證成功,執(zhí)行目標方法。
    // 返回 false 表示攔截器驗證失敗,不執(zhí)行后續(xù)業(yè)務(wù)邏輯。
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 用戶登錄判斷業(yè)務(wù)。
        HttpSession session = request.getSession(false);
        if (session!= null && session.getAttribute("session_userinfo")!= null) {
            // 用戶已登錄。
            returntrue;
        }
        response.setStatus(401);
        returnfalse;
    }
}

代碼中的 preHandle 方法是攔截器的主要方法,在目標方法被調(diào)用之前執(zhí)行。它接收三個參數(shù):HttpServletRequest 對象表示當前 HTTP 請求,HttpServletResponse 對象表示當前 HTTP 響應(yīng),Object handler 表示被攔截的處理器(通常是控制器中的一個方法)。

在 preHandle 方法中,首先通過 request.getSession(false)(如果存在)獲取當前請求的 HttpSession 對象,然后判斷這個 HttpSession 對象是否為 null 以及是否存在名為“session_userinfo”的屬性。

如果這個條件為真,則表示用戶已登錄,可以繼續(xù)執(zhí)行后續(xù)業(yè)務(wù),所以返回 true。否則,驗證失敗,將 HTTP 響應(yīng)的狀態(tài)碼設(shè)置為 401,表示未授權(quán),然后返回 false,不再繼續(xù)執(zhí)行后續(xù)業(yè)務(wù)。

2.將自定義攔截器添加到系統(tǒng)配置中

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
publicclass MyConfig implements WebMvcConfigurer {

    // 注入。
    @Autowired
    private LoginInterceptor loginInterceptor;

    // 添加攔截器。
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)
              .addPathPatterns("/**") // 攔截所有 URL。
              .excludePathPatterns("/user/login") // 排除 URL:/user/login(登錄)。
              .excludePathPatterns("/user/reg") // 排除 URL:/user/reg(注冊)。
              .excludePathPatterns("/image/**") // 排除“image”文件夾下的所有文件。
              .excludePathPatterns("/**/*.js") // 排除任意深度目錄下的所有“.js”文件。
              .excludePathPatterns("/**/*.css");
    }
}

在配置類中,重寫 addInterceptors 方法。此方法用于注冊攔截器。在這里,通過調(diào)用 InterceptorRegistry 的 addInterceptor 方法添加攔截器,并設(shè)置攔截路徑和排除路徑。

具體來說,通過調(diào)用 addInterceptor(loginInterceptor) 添加 LoginInterceptor 攔截器。然后使用 addPathPatterns 方法指定需要攔截的 URL 路徑模式。這里,“/**”用于表示攔截所有 URL。使用 excludePathPatterns 方法排除一些不會被攔截的特定 URL 路徑。

3.用戶控制器

@RestController
@RequestMapping("/user")
publicclass UserController {

    @RequestMapping("/login")
    public String login() {
        return"login";
    }

    @RequestMapping("/index")
    public String index() {
        return"index";
    }

    @RequestMapping("/reg")
    public String reg() {
        return"reg";
    }
}

使用瀏覽器訪問路徑/user/login 的結(jié)果輸出如下:圖片

然后,使用瀏覽器訪問路徑/user/index 的結(jié)果輸出如下:

圖片可以看到,返回了 401 錯誤,這是預期的結(jié)果。

然后,使用瀏覽器訪問路徑/user/reg 的結(jié)果輸出如下:

圖片

添加統(tǒng)一訪問前綴

在 WebMvcConfigurer 接口中,configurePathMatch 方法用于配置路徑匹配規(guī)則。這里我們給所有請求地址添加前綴“pre”。

@Configuration
public class MyConfig implements WebMvcConfigurer {

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        configurer.addPathPrefix("pre", new Predicate<Class<?>>() {
            @Override
            public boolean test(Class<?> aClass) {
                return true;
            }
        });
    }
}

在這個例子中,傳遞給 addPathPrefix 方法的前綴是“pre”,Predicate 對象是一個實現(xiàn)了 Predicate<Class<?>>接口的匿名內(nèi)部類。Predicate 接口是 Java 8 中引入的一個函數(shù)式接口,其 test 方法用于判斷傳入的類是否滿足條件。

在這個匿名內(nèi)部類中,重寫 test 方法使其始終返回 true,這意味著所有類都滿足條件,并且將添加統(tǒng)一的訪問前綴。

因此,通過這段代碼的配置,所有請求路徑都將在前面添加“pre”前綴。比如,如果原始路徑是“example”,添加前綴后的路徑變?yōu)椤?pre/example”。這樣可以實現(xiàn)對請求路徑的統(tǒng)一處理。

注意:如果添加了前綴,攔截器的排除路徑也應(yīng)該相應(yīng)更改。

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(loginInterceptor)
          .excludePathPatterns("/pre/user/login") // 排除 URL:/user/login(登錄)。
          .excludePathPatterns("/pre/user/reg") // 排除 URL:/user/reg(注冊)。
          .addPathPatterns("/**") // 攔截所有 URL。
          .excludePathPatterns("/pre/image/**") // 排除“image”文件夾下的所有文件。
          .excludePathPatterns("/pre/**/*.js") // 排除任意深度目錄下的所有“.js”文件。
          .excludePathPatterns("/pre/**/*.css");
}

配置本地資源映射路徑

實現(xiàn) WebMvcConfigurer 接口并重寫 addResourceHandlers(ResourceHandlerRegistry registry) 方法,其中:

  • addResourceHandler() 添加訪問路徑;
  • addResourceLocations() 添加映射的真實路徑。映射的真實路徑末尾必須跟“/”,否則無法映射?!?”在 Windows 和 Linux 中都適用。

示例代碼:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
publicclass MyWebMVCConfig implements WebMvcConfigurer {

    @Value("${file.location}") // D:/test/
    private String fileLocation;

    @Value("${file.path}") // /file/**
    private String filePath;

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        // 當資源處理器匹配時,將 URL 映射到位置,即本地文件夾。
        registry.addResourceHandler(filePath).addResourceLocations("file:///" + fileLocation); // 這里的最后一個“/”不能省略。
    }
}

這段代碼將配置一個攔截器。如果訪問路徑是 addResourceHandler 中的路徑,那么它將被映射到 addResourceLocations 參數(shù)中的路徑。這樣,其他人就可以訪問服務(wù)器上的本地文件,如本地圖片或本地音樂視頻。

統(tǒng)一異常處理

猜猜訪問以下代碼后會返回什么?

@RestController
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/login")
    public String login() {
        Object object = null;
        object.hashCode();
        return "login";
    }
}

答案是:

圖片有沒有一種方法可以在發(fā)生異常時返回有用信息,而不是這樣混亂的錯誤消息?這就是統(tǒng)一異常處理。

@ControllerAdvice
@ResponseBody
public class MyExceptionAdvice {
    @ExceptionHandler(NullPointerException.class)
    public HashMap<String, Object> handleNPE(NullPointerException e) {
        HashMap<String, Object> result = new HashMap<>();
        result.put("code", 1001);
        result.put("msg", "npe:" + e.getMessage());
        result.put("data", null);
        return result;
    }
}
  1. @ControllerAdvice 注解表示這個類是一個全局異常處理器。它將捕獲應(yīng)用程序中拋出的異常并執(zhí)行相應(yīng)的處理邏輯。
  2. @ExceptionHandler(NullPointerException.class) 注解指定處理 NullPointerException 類型異常的方法 handleNPE()。
  3. handleNPE() 方法的參數(shù)是一個 NullPointerException 類型的異常對象,表示具體捕獲的異常實例。
  4. handleNPE() 方法返回一個 HashMap<String, Object>對象,用于封裝異常處理結(jié)果。

這段代碼的作用是,當捕獲到 NullPointerException 異常時,執(zhí)行 handleNPE() 方法并返回一個包含異常處理結(jié)果的 HashMap 對象。這個結(jié)果將以 JSON 格式返回給客戶端。

訪問 localhost:8080/user/login 的結(jié)果如下:

圖片

當有多個異常處理器時,處理順序如下: 異常處理器按照它們在代碼中定義的順序執(zhí)行。如果一個異常匹配多個異常處理器,將首先執(zhí)行與異常類型更具體匹配的那個。如果沒有具體匹配,則可能考慮更通用的異常處理器。

比如,如果有一個針對異常的特定子類的異常處理器和另一個針對更通用的超類異常的異常處理器,將優(yōu)先執(zhí)行針對特定子類的處理器。

@ControllerAdvice
@ResponseBody
publicclass MyExceptionAdvice {

    @ExceptionHandler(NullPointerException.class)
    public HashMap<String, Object> handleNPE(NullPointerException e) {
        HashMap<String, Object> result = new HashMap<>();
        result.put("code", -1);
        result.put("msg", "npe:" + e.getMessage());
        result.put("data", null);
        return result;
    }

    @ExceptionHandler(Exception.class)
    public HashMap<String, Object> handleAllException(Exception e) {
        HashMap<String, Object> result = new HashMap<>();
        result.put("code", -1);
        result.put("msg", "Exception:" + e.getMessage());
        result.put("data", null);
        return result;
    }
}

再次嘗試訪問/user/login。圖片

結(jié)論是:如果有匹配,子類優(yōu)先。如果沒有匹配,查找父類。

責任編輯:武曉燕 來源: 程序猿技術(shù)充電站
相關(guān)推薦

2011-11-21 14:21:26

SpringMVCJava框架

2012-02-03 13:27:16

2009-06-24 16:00:00

2009-09-27 17:37:32

Hibernate攔截

2023-09-05 08:58:07

2011-05-16 10:14:11

Hibernate

2009-07-08 17:02:11

JDK實現(xiàn)調(diào)用攔截器

2020-03-25 17:55:30

SpringBoot攔截器Java

2009-06-25 15:54:42

Struts2教程攔截器

2009-02-04 14:19:38

2013-11-04 09:35:38

Firefox插件攔截FLASH

2024-12-16 08:10:00

Spring開發(fā)

2024-01-08 08:33:53

AOPSpring攔截器

2017-04-26 11:00:34

Spring BootHelloWorld詳解

2009-06-19 18:26:38

Spring事務(wù)配置

2021-11-03 17:04:11

攔截器操作Servlet

2024-12-27 08:39:10

2025-01-02 10:10:51

2021-05-17 08:11:24

Axios 開源項目HTTP 攔截器

2009-05-19 16:55:17

IE攔截器惡意軟件卡巴斯基
點贊
收藏

51CTO技術(shù)棧公眾號