欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

關于Spring的統(tǒng)一功能處理(攔截器)實現(xiàn)

 更新時間:2023年05月22日 11:38:08   作者:愛敲代碼的三毛  
這篇文章主要介紹了關于Spring的統(tǒng)一功能處理(攔截器)實現(xiàn),每個方法中都要單獨寫用戶登錄驗證的方法,即使封裝成公共方法,也一樣要傳參調用和在方法中進行判斷,需要的朋友可以參考下

Spring攔截器

SpringBoot統(tǒng)一功能處理。也就是AOP的具體實現(xiàn)。

1.統(tǒng)一用戶登錄權限校驗

最原始的用戶登錄驗證方法,我們通過封裝了一個方法來判斷用戶是否登錄,但如果實現(xiàn)的功能多了,那么每一個需要登錄的功能都要在對應的接口中來調用這個函數(shù)來判讀是否登錄。

public class LoginStatus {
    public static User getStatus(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if (session == null) {
            //當前用戶未登錄
            return null;
        }
        User user = (User) session.getAttribute("user");
        if (user == null) {
            //當前用戶未登錄
            return null;
        }
        return user;
    }
}

上面的代碼雖然已經(jīng)封裝成了方法,但是如果隨著程序功能的增多,那么每一個控制器都要調用這個接口進行判斷,就出現(xiàn)了代碼的冗余,也增加了代碼的維護成本。

這個時候就需要提供一個公共的方法來進行統(tǒng)一的用戶登錄權限驗證了。

1) SpringAOP 用戶統(tǒng)一驗證的問題

統(tǒng)一驗證我們可以使用SpringAOP的前置通知或者是環(huán)繞通知來實現(xiàn)

@Aspect // 說明該類為一個切面
@Component
public class UserAspect {
    // 定義切點,使用 AspectJ表達式語法,攔截UserController所有方法
    @Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
    public void pointcut(){}
    // 前置通知
    @Before("pointcut()")
    public void doBefore() {
        System.out.println("執(zhí)行Before前置通知");
    }
    // 添加環(huán)繞通知
    @Around("pointcut()")
    public Object doAround(ProceedingJoinPoint joinPoint) {
        Object result = null;
        System.out.println("執(zhí)行環(huán)繞通知的前置方法");
        try {
            // 執(zhí)行(攔截的)業(yè)務方法
            result = joinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("執(zhí)行環(huán)繞通知的后置方法");
        return result;
    }
}

我們發(fā)現(xiàn)原生的SpringAOP的切面實現(xiàn)用戶登錄權限的校驗功能,會有兩個問題

我們是獲取不到HttpSession對象的如果我們只對一部分方法進行攔截,像登錄和注冊這樣的方法就沒有必要攔截,這樣的很難定義排除對應方法的規(guī)則,甚至說沒有辦法定義。

那就可以使用Spring的攔截器

2) Spring攔截器

對于上面兩個問題Spring中提供了解決方案,提供了具體實現(xiàn)的攔截器:Handlerlnterceptor,攔截器的實現(xiàn)分為兩個步驟:

創(chuàng)建自定義攔截器,實現(xiàn)Handlerlnterceptor接口的preHandle(執(zhí)行具體方法之前的預處理)方法將自定義攔截器加入WebMvcConfigureraddInterceptors

1.自定義攔截器

用戶登錄權限校驗,自定義攔截器代碼實現(xiàn):

/**
 * 定義自定義攔截器實現(xiàn)用戶登錄校驗
 */
@Configuration
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession(false);
        if (session != null &&  session.getAttribute("userInfo") != null) {
            response.setStatus(200);
            return true;
        }
        response.setStatus(403);
        return false;
    }
}

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

將上一步自定義的攔截器加入到系統(tǒng)配置信息中,代碼實現(xiàn):

@Configuration
public class AppConfig implements WebMvcConfigurer {
    //添加攔截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor()) // 添加自定義攔截器
                .addPathPatterns("/**") //攔截所有接口
                .excludePathPatterns("/**/login")//排除的接口
    }
}
  • addPathPatterns:表示需要攔截的 URL,*”表示攔截任意?法(也就是所有?法)
  • excludePathPatterns:表示需要排除的 URL。
  • 以上的攔截規(guī)則可以攔截程序中使用的URL、靜態(tài)文件(圖片、前端文件等)

排除所有靜態(tài)的資源

@Configuration
public class AppConfig implements WebMvcConfigurer {
    //添加攔截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor()) // 添加自定義攔截器
                .addPathPatterns("/**")
                .excludePathPatterns("/**/*.html")//排除所有靜態(tài)資源
                .excludePathPatterns("/**/*.css")
                .excludePathPatterns("/**/*.js")
                .excludePathPatterns("/**/img/*");
    }
}

3) 攔截器實現(xiàn)原理

原本正常的調用流程是這樣的:

在這里插入圖片描述

但是添加了攔截器后,在調用Controller之前會進行相對應業(yè)務處理

在這里插入圖片描述

在這里插入圖片描述

?所有?法都會執(zhí)? DispatcherServlet 中的 doDispatch 調度?法,doDispatch 部分源碼如下

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
       //此處省略上面代碼
    // 調用預處理
    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
        return;
    }
    // 執(zhí)行Controller中的業(yè)務
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    if (asyncManager.isConcurrentHandlingStarted()) {
        return;
    }
    // ......后面代碼省略
}

從上述源碼可以看出在開始執(zhí)? Controller 之前,會先調? 預處理?法 applyPreHandle,? applyPreHandle ?法的實現(xiàn)源碼如下

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
        for(int i = 0; i < this.interceptorList.size(); this.interceptorIndex = i++) {
            // 獲取項?中使?的攔截器 HandlerIntercepto
            HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
            if (!interceptor.preHandle(request, response, this.handler)) {
                this.triggerAfterCompletion(request, response, (Exception)null);
                return false;
            }
        }
        return true;
    }

從上述源碼可以看出,在 applyPreHandle 中會獲取所有的攔截器 HandlerInterceptor 并執(zhí)?攔截器中 的 preHandle ?法,這樣就會咱們前?定義的攔截器對應上了,如下圖所示 :

在這里插入圖片描述

只有當我們重寫的方法放回true的時候才會繼續(xù)走調用Controller的業(yè)務代碼,否則就是直接放回給前端

在這里插入圖片描述

攔截器的實現(xiàn)原理:

  • 從宏觀上來講的話,它是根據(jù)AOP的思想來去執(zhí)行的,把統(tǒng)一的方法放到前置處理器來進行處理
  • 在Spring中的攔截器實現(xiàn),就是在調度器類里的調度方法,調度方法在真正調用Controller之前,它會有一個方法先去掃描當前Spring中所有攔截器的一個列表,然后去執(zhí)行這些攔截器,只有當攔截器執(zhí)行通過的時候,它才會繼續(xù)走后面的流程,才會去走Controller然后返回結果給前端。

4)同一訪問前綴添加

該方法可以給所有接口添加一個訪問前綴,讓前端訪問接口時都要加上blog,比如原來是/add,添加前綴后就是/blog/add

@Configuration
public class AppConfig implements WebMvcConfigurer {
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        configurer.addPathPrefix("blog",pre->true);
    }
}

其中第?個參數(shù)是?個表達式,設置為 true 表示啟動前綴

2. 統(tǒng)一異常處理

同一異常處理是通過@ControllerAdvice+@ExceptionHandler兩個注解結合實現(xiàn)的,@ControllerAdvice表示控制器通知類,@ExceptionHandler是異常處理,兩個結合起來就表示出現(xiàn)異常的時候執(zhí)行某一個通知,也就是執(zhí)行某個方法,代碼實現(xiàn):

@ControllerAdvice
public class ErrorAdvice  {
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Object handler(Exception e) {
        Map<String,Object> map = new HashMap<>();
        map.put("success",1);
        map.put("status",-1);
        map.put("message","服務器接口異常");
        return map;
    }
}

注意:方法名和返回值可以任意,重要的是注解。

這里的代碼表示的是發(fā)生任何異常都給前端返回一個HashMap,也可以指定異常進行處理代碼如下

@ControllerAdvice
public class ErrorAdvice  {
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Object exceptionAdvice(Exception e) {
        Map<String,Object> map = new HashMap<>();
        map.put("success",1);
        map.put("status",-1);
        map.put("message","服務器接口異常");
        return map;
    }
    @ExceptionHandler(NullPointerException.class)
    @ResponseBody
    public Object nullPointerExceptionAdvice(NullPointerException exception) {
        Map<String,Object> map = new HashMap<>();
        map.put("success",1);
        map.put("status",-1);
        map.put("message",exception.toString());
        return map;
    }
}

當有多個異常通知時,匹配順序為當前類及其?類向上依次匹配

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

1)統(tǒng)一數(shù)據(jù)返回的好處

統(tǒng)一數(shù)據(jù)返回格式有很多好處

  1. 方便前端程序員接收和解析后端接口返回的數(shù)據(jù)
  2. 降低前端程序員和后端程序員的溝通成本,只需要按照指定格式實現(xiàn)功能,所有接口放回值都是固定的
  3. 有利于項目整體的維護和修改,有利于后端統(tǒng)一標準規(guī)范。

2)統(tǒng)一數(shù)據(jù)返回實現(xiàn)

統(tǒng)一的數(shù)據(jù)返回格式可以使用@ControllerAdvice+ResponseBodyAdvice實現(xiàn)

  • supports方法返回true表示對返回內容進行重寫,就會執(zhí)行beforeBodyWrite方法
  • beforeBodyWrite方法中body就是Controller返回的內容
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
    /**
     * 內容是否需要重寫,此方法可以選擇部分控制器和方法進行重寫
     * 返回 true表示重寫
     */
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }
    /**
     *控制器方法返回之前會調用此方法
     */
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                  Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        Map<String,Object> result = new HashMap<>();
        result.put("success",200);
        result.put("status",1);
        result.put("data",body);
        return result;
    }
}

到此這篇關于關于Spring的統(tǒng)一功能處理(攔截器)實現(xiàn)的文章就介紹到這了,更多相關Spring的統(tǒng)一功能處理內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java線程池的拒絕策略實現(xiàn)詳解

    Java線程池的拒絕策略實現(xiàn)詳解

    這篇文章主要介紹了Java線程池的拒絕策略實現(xiàn)詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-09-09
  • Java 實現(xiàn)聲音播放程序

    Java 實現(xiàn)聲音播放程序

    這篇文章主要介紹了Java 實現(xiàn)聲音播放程序的示例代碼,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下
    2020-12-12
  • Java超詳細介紹抽象類與接口的使用

    Java超詳細介紹抽象類與接口的使用

    在類中沒有包含足夠的信息來描繪一個具體的對象,這樣的類稱為抽象類,接口是Java中最重要的概念之一,它可以被理解為一種特殊的類,不同的是接口的成員沒有執(zhí)行體,是由全局常量和公共的抽象方法所組成,本文給大家介紹Java抽象類和接口,感興趣的朋友一起看看吧
    2022-05-05
  • Java多線程間的5種通信方式小結

    Java多線程間的5種通信方式小結

    有兩個線程,A 線程向一個集合里面依次添加元素“abc”字符串,一共添加十次,當添加到第五次的時候,希望 B 線程能夠收到 A 線程的通知,然后 B 線程執(zhí)行相關的業(yè)務操作,本文介紹的5種通信方式都是基本這兩種模型來實現(xiàn)的,需要的朋友可以參考下
    2023-10-10
  • 通過Java壓縮JavaScript代碼實例分享

    通過Java壓縮JavaScript代碼實例分享

    這篇文章主要介紹了通過Java壓縮JavaScript代碼實例分享,具有一定參考價值,需要的朋友可以了解下。
    2017-12-12
  • GitLab在IDEA中回滾主分支問題

    GitLab在IDEA中回滾主分支問題

    這是工作中遇到的問題,記錄下來,也方便自己后面查看操作步驟,也方便各位遇到這個問題,不至于卡太久,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • Java8中Optional類型和Kotlin中可空類型的使用對比

    Java8中Optional類型和Kotlin中可空類型的使用對比

    這篇文章主要給大家介紹了關于Java8中Optional類型和Kotlin中可空類型的使用對比,文中通過示例代碼給大家介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。
    2017-09-09
  • Java concurrency之AtomicLongArray原子類_動力節(jié)點Java學院整理

    Java concurrency之AtomicLongArray原子類_動力節(jié)點Java學院整理

    這篇文章主要介紹了Java concurrency之AtomicLongArray原子類的相關知識,感興趣的朋友參考下吧
    2017-06-06
  • 簡單了解Spring beanfactory循環(huán)依賴命名重復屬性

    簡單了解Spring beanfactory循環(huán)依賴命名重復屬性

    這篇文章主要介紹了簡單了解Spring beanfactory循環(huán)依賴命名重復2大屬性,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-06-06
  • Java中的Semaphore信號量使用方法代碼實例

    Java中的Semaphore信號量使用方法代碼實例

    這篇文章主要介紹了Java中的Semaphore信號量使用方法代碼實例,Semaphore是一種基于計數(shù)的信號量,它可以設定一個閾值,基于此,多個線程競爭獲取許可信號,做自己的申請后歸還,超過閾值后,線程申請許可信號將會被阻塞,需要的朋友可以參考下
    2023-11-11

最新評論