最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot 統(tǒng)一功能處理方案

 更新時間:2025年04月23日 10:30:09   作者:Bug退退退123  
在我們進行項目編寫時,有時相同的一段代碼在不同的地方使用多次,對于這種情況,spring 幫我們實現(xiàn)了統(tǒng)一功能處理,下面介紹一些常用的統(tǒng)一功能處理,感興趣的朋友一起看看吧

在我們進行項目編寫時,有時相同的一段代碼在不同的地方使用多次,對于這種情況,spring 幫我們實現(xiàn)了統(tǒng)一功能處理,下面介紹一些常用的統(tǒng)一功能處理。

一、攔截器

在有些項目中,是需要用戶登錄才能進行后續(xù)訪問的。但如果這時有人拿到了后端接口的 url,這時就能跳過用戶登錄進而訪問我們的網(wǎng)站,這就有可能對網(wǎng)站造成攻擊,對于這種情況,我們可以將用戶的部分信息存到 session 中,在每次訪問接口前,都可以先獲取到 session,再將用戶信息取出,看看這個用戶是否登錄,若登錄,就允許繼續(xù)訪問,若沒有登陸,就強制登錄。

但是,在我們的項目中,接口的數(shù)目可不小,若是在每個接口中都加上這段邏輯,就會顯得我們的代碼過于冗余,于是 Spring 就為我們構(gòu)造了攔截器。

攔截器主要用來攔截用戶的請求,在指定方法前后執(zhí)行攔截器中預(yù)設(shè)的代碼,也就是說,攔截器可以在用戶的請求之前發(fā)揮作用,也可以在用戶的請求之后發(fā)揮作用。

對于上述判斷用戶登錄的業(yè)務(wù),我們就可以在攔截器中寫明判斷用戶是否登錄的代碼,這樣在用戶發(fā)送請求時,就會先執(zhí)行這段代碼,若用戶沒有登錄,就會阻止用戶進行訪問,并跳轉(zhuǎn)到登陸頁面(這是前端干的事)。

下面介紹攔截器的具體用法。

在實現(xiàn)攔截器時,需要實現(xiàn) HandlerInterceptor 類中的 preHandle,postHandle,afterCompletion 方法,preHandle 是在目標方法執(zhí)行前執(zhí)行的,postHandle 是在目標方法執(zhí)行之后執(zhí)行的,afterCompletion 是在試圖渲染完成之后執(zhí)行的,但現(xiàn)在后端開發(fā)基本上都不會涉及到試圖,那么這個方法就不重點介紹了。

代碼如下:

@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
    //在目標方法執(zhí)行前執(zhí)行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("在目標方法執(zhí)行前執(zhí)行");
        return true;
    }
    //在目標方法之后執(zhí)行
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("在目方法執(zhí)行后執(zhí)行");
    }
    //試圖渲染完成之后執(zhí)行
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("視圖渲染完成后執(zhí)行");
    }
}

preHandle 有返回值,返回 true 表示不攔截請求,返回 false 表示攔截請求。

定義好攔截器的功能后,接下來就需要注冊攔截器。注冊攔截器需要實現(xiàn) WebMvcConfigurer 中的 addInterceptors,代碼如下:

@Slf4j
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private LoginInterceptor loginInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/test/**");
    }
}

使用 addInterceptor 即表示需要注冊的是哪個攔截器,使用 addPathPatterns 即表示需要攔截的路徑,即攔截器對哪些請求生效,這里的 /test/** 表示對 test 路徑下的所有方法均生效,還有其它的路徑表示,如下:

/* : 表示一級路徑,只能匹配 /test,不能匹配 /test/t1等;

/** : 表示任意級路徑,能匹配 /test,/test/t1等;

/test/* : 表示 /test 下的一級路徑,可以匹配 /test/t1,但不能匹配 /test/t1/t2等;

/test/** : 表示 /test 下的任意級路徑,可以匹配 /test/t1,/test/t1/t2,但不能匹配 /user/login 等。

當我們配置完攔截器和注冊完攔截器后,就可以開始運行代碼,我們使用下面的代碼來進行測試:

@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {
    @RequestMapping("/t1")
    public void t1() {
        log.info("攔截器測試...");
    }
}

代碼運行結(jié)果如下:

在這里我們可以看到,當訪問被攔截的方法時,首先執(zhí)行的是 preHandle,由于 postHandle 返回值為 true,就不會攔截用戶請求,于是就會先執(zhí)行 t1 方法,之后會順序執(zhí)行 postHandle 和 afterCompletion。

若 preHandle 返回值為 false,代碼的運行結(jié)果如下:

從結(jié)果中可以看出,程序只執(zhí)行了 preHandle,由于 t1 被攔截,于是 t1、postHandle、afterCompletion 就不會執(zhí)行。

在上述的攔截路徑中,我們將 /test 下的所有路徑都給攔截了,但是有的請求我們不需要攔截,那么我們就可以使用 excludPathPatterns 去去除掉不需要攔截的路徑,改動后的代碼如下:

@Slf4j
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private LoginInterceptor loginInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/test/**")
                .excludePathPatterns("/test/t2");
    }
}
@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {
    @RequestMapping("/t1")
    public void t1() {
        log.info("t1攔截器測試...");
    }
    @RequestMapping("/t2")
    public void t2() {
        log.info("不攔截t2測試");
    }
}

TestController 中新增了 t2 方法,只攔截 t1,不攔截 t2,代碼運行結(jié)果如下:

從圖中可以看出,t1被攔截,但 t2 沒有被攔截。

當我們知道如何使用攔截器之后,就可以在項目中進行運用。

當用戶在進行訪問時,就可以對其訪問進行攔截,在攔截器中判斷用戶是否登錄,若登錄就放行,若沒有登錄就跳轉(zhuǎn)到登錄頁面進行登錄,代碼如下:

package com.gjm.demo.interceptor;
import com.gjm.demo.constant.Constants;
import com.gjm.demo.enums.ResultStatusEnums;
import com.gjm.demo.model.Result;
import com.gjm.demo.model.UserInfo;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
 * 登錄攔截器
 */
@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {
    /**
     * 目標方法前執(zhí)行, 攔截器攔截到后,就會將response返回給前端,前端的error中就能就受到response
     * @param request
     * @param response
     * @param handler
     * @return true: 繼續(xù)執(zhí)行, false: 中斷后續(xù)操作
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("登錄之前執(zhí)行");
        //用戶未登錄的處理
        if (!checkUserInfo(request.getSession())) {
            response.setContentType("text/html;character=utf-8");
            response.setStatus(401);
            String errorMessage = "用戶未登錄";
            response.getOutputStream().write(errorMessage.getBytes("UTF-8"));
            return false;
        }
        return true;
    }
    /**
     * 對檢查用戶信息進行封裝
     * @param session
     * @return
     */
    public boolean checkUserInfo(HttpSession session) {
        //用戶未登錄
        if (session == null || session.getAttribute(Constants.SESSION_USER_KEY) == null) {
            return false;
        }
        //獲取用戶信息
        UserInfo userInfo = (UserInfo) session.getAttribute(Constants.SESSION_USER_KEY);
        //用戶信息不對
        if (userInfo == null || userInfo.getId() <= 0) {
            return false;
        }
        return true;
    }
}

 其中 check 的用處是檢查用戶是否登錄。

二、統(tǒng)一數(shù)據(jù)返回格式

在進行項目開發(fā)時,我需要向前端返回一個統(tǒng)一的數(shù)據(jù),這個數(shù)據(jù)是經(jīng)過封裝的,但是,在我們的接口中,有的返回的是 String,有的返回的是 boolean等,這就需要我們針對每一個接口都編寫封裝結(jié)果的代碼,這樣的代碼就有點冗余了。于是,Spring 就封裝了能夠統(tǒng)一返回數(shù)據(jù)格式的方法。

現(xiàn)在有一個結(jié)果類 Result,對于接口中的每一種返回值,都需要將其封裝為 Result 對象,實現(xiàn)的代碼如下:

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
    @Autowired
    private ObjectMapper objectMapper;
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        //false為不處理,true為處理
        return true;
    }
    @SneakyThrows//異常處理
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if (body instanceof String) {
            return objectMapper.writeValueAsString(Result.success(body));//將Result類型轉(zhuǎn)化為String類型
        }
        //body已經(jīng)是result類型,就不需要封裝
        if (body instanceof Result) {
            return body;
        }
        return Result.success(body);
    }
}

該類需實現(xiàn) ResponseBodyAdvice 接口,實現(xiàn) support 和 beforeBodyWrite 方法,而且需要加上 @ControllerAdvice 注解。

support 的返回值為 boolean,返回 true 表示對各類型的返回值都進行處理,返回 false 表示不處理。

beforeBodyWrite 即具體的實現(xiàn)類。在這里需要強調(diào),若接口中的返回值為 String,那么就需要對其進行單獨處理,不然就會報錯。

對于本來就是 Result 類型的對象,就不要進行處理,直接返回即可。

三、統(tǒng)一異常處理

在我們編寫代碼的時候,有時候可能判斷的不準確,不知道哪里會出現(xiàn)異常,那么如果我們不進行處理,就會影響程序的運行。對于這種情況,Spring 為我們封裝了一個能統(tǒng)一處理異常的方法,代碼如下:

@Slf4j
@ControllerAdvice
@ResponseBody
public class ExceptionAdvice {
    @ExceptionHandler
    public Result handler(Exception e) {
        log.error("發(fā)生異常, e: ", e);
        return Result.fail(ResultStatusEnums.ERROR, "內(nèi)部錯誤,請聯(lián)系管理員");
    }
    @ExceptionHandler
    public Result handler(NullPointerException e) {
        log.error("發(fā)生異常, e: ", e);
        return Result.fail(ResultStatusEnums.ERROR, "空指針異常,請聯(lián)系管理員");
    }
    @ExceptionHandler
    public Result handler(IndexOutOfBoundsException e) {
        log.error("發(fā)生異常, e: ", e);
        return Result.fail(ResultStatusEnums.ERROR, "數(shù)組越界異常,請聯(lián)系管理員");
    }
}

ExceptionAdvice 需要使用 @ControllerAdvice 和 @ResponseBody 注解。

在各個方法上需要使用 @ExceptionHandler 注解。

在這個類中,一共處理了三個異常,也可以繼續(xù)增加異常的種類。若代碼中拋出了異常并且沒有手動捕獲,就會拋給 ExceptionAdvice 類,在這個類中尋找與之距離最近的異常,若沒有,就會直接使用 Exception 代替。

上述的代碼還有另一種寫法,代碼如下:

@Slf4j
@ControllerAdvice
@ResponseBody
public class ExceptionAdvice {
    @ExceptionHandler(Exception.class)
    public Result handler1(Exception e) {
        log.error("發(fā)生異常, e: ", e);
        return Result.fail(ResultStatusEnums.ERROR, "內(nèi)部錯誤,請聯(lián)系管理員");
    }
    @ExceptionHandler(NullPointerException.class)
    public Result handler2(Exception e) {
        log.error("發(fā)生異常, e: ", e);
        return Result.fail(ResultStatusEnums.ERROR, "空指針異常,請聯(lián)系管理員");
    }
    @ExceptionHandler(IndexOutOfBoundsException.class)
    public Result handler3(Exception e) {
        log.error("發(fā)生異常, e: ", e);
        return Result.fail(ResultStatusEnums.ERROR, "數(shù)組越界異常,請聯(lián)系管理員");
    }
}

在每個 @ExceptionHandler 注解中標明捕獲的是什么類型的異常,這樣在每個方法的參數(shù)中就能直接使用 Exception 代替。

到此這篇關(guān)于SpringBoot 統(tǒng)一功能處理方案的文章就介紹到這了,更多相關(guān)SpringBoot 統(tǒng)一功能內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java實現(xiàn)字符串轉(zhuǎn)換為十進制ASCII碼的實戰(zhàn)指南

    Java實現(xiàn)字符串轉(zhuǎn)換為十進制ASCII碼的實戰(zhàn)指南

    將Java字符串轉(zhuǎn)換為十進制ASCII碼是文本處理、協(xié)議編碼、數(shù)據(jù)序列化和底層通信中的常見需求,下面我們就來看看具體的實現(xiàn)方法,希望對大家有所幫助
    2026-05-05
  • Java集合的Collection接口和List接口詳解

    Java集合的Collection接口和List接口詳解

    這篇文章主要為大家詳細介紹了Java集合的Collection接口和List接口,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • 淺談一下Java中的悲觀鎖和樂觀鎖

    淺談一下Java中的悲觀鎖和樂觀鎖

    這篇文章主要介紹了一下Java中的悲觀鎖和樂觀鎖,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • 詳解Java線程池的使用(7種創(chuàng)建方法)

    詳解Java線程池的使用(7種創(chuàng)建方法)

    這篇文章主要介紹了詳解Java線程池的使用(7種創(chuàng)建方法),線程池的創(chuàng)建?式總共包含7種,其中6種是通過Executors創(chuàng)建的,1種是通過ThreadPoolExecutor創(chuàng)建的,今天我們就來詳細說一下
    2023-03-03
  • Java中Object用法詳解

    Java中Object用法詳解

    Java是面向?qū)ο蟮木幊陶Z言,而在面向?qū)ο笾校械腏ava類都有一個共同的祖先類,這就是Object,那么Object都有哪些特性呢?今天小編就簡單跟大家分析一下,感興趣的同學(xué)可以跟著小編一起學(xué)習(xí)
    2023-05-05
  • 詳解Http請求中Content-Type講解以及在Spring MVC中的應(yīng)用

    詳解Http請求中Content-Type講解以及在Spring MVC中的應(yīng)用

    這篇文章主要介紹了Http請求中Content-Type講解以及在Spring MVC中的應(yīng)用的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • springcloud 中 zuul 修改請求參數(shù)信息的方法

    springcloud 中 zuul 修改請求參數(shù)信息的方法

    這篇文章主要介紹了springcloud 中 zuul 修改請求參數(shù)信息的方法,需要的朋友可以參考下
    2018-02-02
  • Java中Collection和Collections的區(qū)別

    Java中Collection和Collections的區(qū)別

    Collection是一個集合接口,集合類的頂級接口,Collections是一個包裝類,本文主要介紹了Java中Collection和Collections的區(qū)別,具有一定的參考價值,感興趣的可以了解一下
    2024-04-04
  • Java線程等待用法實例分析

    Java線程等待用法實例分析

    這篇文章主要介紹了Java線程等待用法,結(jié)合實例形式分析了obj.wait()實現(xiàn)線程等待相關(guān)原理與操作技巧,需要的朋友可以參考下
    2018-09-09
  • SpringMVC 方法四種類型返回值總結(jié)(你用過幾種)

    SpringMVC 方法四種類型返回值總結(jié)(你用過幾種)

    這篇文章主要介紹了SpringMVC 方法四種類型返回值總結(jié)(你用過幾種),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-05-05

最新評論

雅江县| 萍乡市| 黑山县| 宁河县| 商水县| 木里| 灯塔市| 阿克陶县| 夏津县| 西畴县| 康马县| 会东县| 祥云县| 清涧县| 保定市| 东源县| 鞍山市| 星子县| 天峨县| 荥经县| 宾阳县| 汨罗市| 柏乡县| 株洲市| 井陉县| 开原市| 石柱| 迁西县| 绍兴县| 兴和县| 将乐县| 搜索| 团风县| 科尔| 西乌珠穆沁旗| 嘉祥县| 遵化市| 江陵县| 阿拉善右旗| 兴国县| 饶阳县|