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

java接口用戶上下文的設(shè)計(jì)與實(shí)現(xiàn)

 更新時(shí)間:2023年11月03日 08:55:01   作者:sum墨  
這篇文章主要為大家介紹了接口用戶上下文的設(shè)計(jì)與實(shí)現(xiàn)實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

作為一名從業(yè)已達(dá)六年的老碼農(nóng),我的工作主要是開發(fā)后端Java業(yè)務(wù)系統(tǒng),包括各種管理后臺(tái)和小程序等。在這些項(xiàng)目中,我設(shè)計(jì)過單/多租戶體系系統(tǒng),對接過許多開放平臺(tái),也搞過消息中心這類較為復(fù)雜的應(yīng)用,但幸運(yùn)的是,我至今還沒有遇到過線上系統(tǒng)由于代碼崩潰導(dǎo)致資損的情況。這其中的原因有三點(diǎn):一是業(yè)務(wù)系統(tǒng)本身并不復(fù)雜;二是我一直遵循某大廠代碼規(guī)約,在開發(fā)過程中盡可能按規(guī)約編寫代碼;三是經(jīng)過多年的開發(fā)經(jīng)驗(yàn)積累,我成為了一名熟練工,掌握了一些實(shí)用的技巧。

考慮到文字太過寡淡,我先上一張圖

在Spring Boot中,默認(rèn)情況下,每個(gè)請求到達(dá)時(shí)都會(huì)分配一個(gè)單獨(dú)的線程來處理,而且請求的發(fā)起人也不一定都是同一個(gè)人,所以一個(gè)請求對應(yīng)一個(gè)用戶上下文,并且要求線程隔離,即不同線程的用戶上下文互不影響,最后用戶上下文還需要隨著線程的結(jié)束而刪除。
本文我會(huì)從用戶上下文如何構(gòu)建、如何使用、如何刪除這三個(gè)方面解釋接口用戶上下文的設(shè)計(jì)與實(shí)現(xiàn)。

本文參考項(xiàng)目源碼地址:summo-springboot-interface-demo

一、接口用戶上下文的構(gòu)建、使用、清除

1. 利用Filter攔截到每一個(gè)請求

由于接口散落在各個(gè)Controller中,且絕大部分接口都是需要這個(gè)用戶上下文的(注:也不排除不需要用戶上下文的接口存在),所以這里需要統(tǒng)一入口進(jìn)行創(chuàng)建、銷毀。看起來可以使用AOP的方式來實(shí)現(xiàn),

不過這里有一個(gè)更合適的方案,利用SpringBoot自帶的Filter【javax.servlet.Filter】來實(shí)現(xiàn)。

實(shí)現(xiàn)起來非常簡單,我這邊自定義了一個(gè)WebFilter,代碼如下:

WebFilter.java

package com.summo.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.summo.context.GlobalUserContext;
import com.summo.context.UserContext;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class WebFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
        throws IOException, ServletException {
        try {
            //獲取本次接口的唯一碼
            String token = java.util.UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
            MDC.put("requestId", token);
            //獲取請求頭
            HttpServletRequest httpServletRequest = (HttpServletRequest)servletRequest;
            HttpServletResponse httpServletResponse = (HttpServletResponse)servletResponse;
            log.info("當(dāng)前請求鏈接為:[{}]", httpServletRequest.getRequestURL());
            //設(shè)置用戶上下文
            UserContext userContext = new UserContext();
            userContext.setUserId(1L);
            GlobalUserContext.setUserContext(userContext);
            //執(zhí)行doFilter,這行一定要加,否則程序會(huì)中斷掉
            filterChain.doFilter(httpServletRequest, httpServletResponse);
        } catch (Exception e) {
            log.error("do doFilter exception", e);
        } finally {
            GlobalUserContext.clear();
            MDC.remove("requestId");
        }
    }
    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

 這段代碼的核心方法是:public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)我們可以在這個(gè)方法里面獲取到ServletRequest和ServletResponse,這兩個(gè)類能獲取到代表著我們可以操作整個(gè)請求過程,這里如何確定當(dāng)前請求的用戶?下面有一張流程圖供大家參考:

還有一種做法是使用JWT來當(dāng)做用戶token,因?yàn)镴WT本身就可以存儲(chǔ)一些信息,所以我們就不需要去緩存用戶信息了,直接解析JWT即可,這種做法在分布式應(yīng)用中很常見。

2. 獲取當(dāng)前請求的線程

上面已經(jīng)獲取到用戶信息了,現(xiàn)在需要將用戶信息放入用戶上下文中,但由于請求的發(fā)起人不一定都是同一個(gè)人,所以一個(gè)請求對應(yīng)著一個(gè)用戶上下文,也即一個(gè)線程設(shè)置一個(gè)上下文。那么這里就需要獲取到當(dāng)前線程才能設(shè)置上下文。

獲取當(dāng)前線程有很多辦法,這里推薦使用阿里巴巴開源的TTL框架(TransmittableThreadLocal)來實(shí)現(xiàn),功能強(qiáng)大且用法簡單。

引入方法如下:

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>transmittable-thread-local</artifactId>
  <version>2.11.1</version>
</dependency>

使用方法如下:

private static final TransmittableThreadLocal<UserContext> USER_HOLDER = new TransmittableThreadLocal<>();

直接new一個(gè)對象就行,而且支持泛型。

3. 用戶上下文生命周期管理

對于用戶上下文的生命周期管理需要定義3個(gè)方法:

  • 設(shè)置上下文用戶信息;
  • 獲取上下文用戶信息

清除上下文用戶信息

以上方法均為靜態(tài)方法。

下面是一個(gè)簡單的例子:

GlobalUserContext.java

package com.summo.context;
import com.alibaba.ttl.TransmittableThreadLocal;
public class GlobalUserContext {
    private static final TransmittableThreadLocal<UserContext> USER_HOLDER = new TransmittableThreadLocal<>();
    /**
     * 設(shè)置上下文用戶信息
     *
     * @param user 用戶信息
     */
    public static void setUserContext(UserContext user) {
        USER_HOLDER.set(user);
    }
    /**
     * 獲取上下文用戶信息
     */
    public static UserContext getUserContext() {
        return USER_HOLDER.get();
    }
    /**
     * 清除上下文用戶信息
     */
    public static void clear() {
        USER_HOLDER.remove();
    }
}

UserContext.java

package com.summo.context;
import lombok.Data;
@Data
public class UserContext {
    /**
     * 用戶ID
     */
    private Long userId;
}

調(diào)用方式如下:

設(shè)置上下文用戶信息:GlobalUserContext.setUserContext(userContext);
獲取上下文用戶信息:GlobalUserContext.getUserContext();
清除上下文用戶信息:GlobalUserContext.clear();

4. 用戶上下文的使用

獲取用戶上下文很方便,調(diào)用GlobalUserContext.getUserContext();就行了,這里我主要講一下用戶上下文的使用場景。

a. 身份認(rèn)證

可以將用戶的身份認(rèn)證信息(如用戶名、密碼、權(quán)限等)保存在用戶上下文中,在需要進(jìn)行鑒權(quán)的地方進(jìn)行驗(yàn)證。

b. 用戶日志記錄

正如《優(yōu)化接口設(shè)計(jì)的思路》系列:第三篇—在用戶使用系統(tǒng)過程中留下痕跡 的方法三.

c. 防止接口數(shù)據(jù)越權(quán)

舉個(gè)例子,比如有些業(yè)務(wù)需要獲取當(dāng)前登錄用戶的信息、當(dāng)前登錄用戶的收藏、當(dāng)前登錄用戶的瀏覽記錄,這樣的接口總不能在接口上傳一個(gè)userId吧?真要這樣干了,非得給安全罵死。。。

利用用戶上下文的話,接口就可以不用傳遞任何參數(shù)獲取到當(dāng)前用戶的userId,實(shí)現(xiàn)你的需求啦。

d. 跨服務(wù)調(diào)用

在分布式系統(tǒng)中,可以將用戶上下文信息傳遞給其他服務(wù),以保持用戶的一致性和連貫性。

e. 監(jiān)控和統(tǒng)計(jì)

可以將用戶上下文中的信息用于系統(tǒng)的監(jiān)控和統(tǒng)計(jì),如請求的處理時(shí)間、請求的次數(shù)等。

5. 用戶上下文的刪除

刪除很簡單,調(diào)用GlobalUserContext.clear();即可,詳情可見WebFilter.java內(nèi)容。

二. 用戶登錄&認(rèn)證

上面主要是說怎么獲取到接口請求的用戶以及怎么設(shè)置用戶上下文,但沒說用戶身份是什么時(shí)候確認(rèn)的以及怎么確認(rèn)的,這里說一下常見做法。
想要確認(rèn)用戶信息就不得不提到用戶登錄&認(rèn)證這套東西了,登錄的方式非常多,簡單的有賬號(hào)密碼登錄、手機(jī)驗(yàn)證碼登錄,復(fù)雜的就是單點(diǎn)登錄、三方授權(quán)登錄如微信掃碼、支付寶掃碼等。雖然方式多,但是結(jié)果都一樣的:確認(rèn)當(dāng)前用戶身份。

當(dāng)前用戶身份確認(rèn)好之后,系統(tǒng)一般會(huì)根據(jù)當(dāng)前用戶信息生成一個(gè)唯一的并帶有時(shí)效性的token,放入下一次請求的cookie中。等到下一次請求來的時(shí)候,我們就可以從cookie中獲取這個(gè)token,利用這個(gè)token獲取這個(gè)用戶的信息。

由于用戶認(rèn)證情況太多,這里我就不貼代碼了,上面是賬號(hào)密碼登錄用戶認(rèn)證的的時(shí)序圖,供大家參考。

以上就是接口用戶上下文的設(shè)計(jì)與實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于接口用戶上下文的設(shè)計(jì)與實(shí)現(xiàn)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • SpringBoot中注解@ConfigurationProperties與@Value的區(qū)別與使用詳解

    SpringBoot中注解@ConfigurationProperties與@Value的區(qū)別與使用詳解

    本文主要介紹了SpringBoot中注解@ConfigurationProperties與@Value的區(qū)別與使用,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • selenium+java破解極驗(yàn)滑動(dòng)驗(yàn)證碼的示例代碼

    selenium+java破解極驗(yàn)滑動(dòng)驗(yàn)證碼的示例代碼

    本篇文章主要介紹了selenium+java破解極驗(yàn)滑動(dòng)驗(yàn)證碼的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-01-01
  • ZooKeeper Java API編程實(shí)例分析

    ZooKeeper Java API編程實(shí)例分析

    本文主要通過實(shí)例給大家詳細(xì)分析了ZooKeeper用JAVA實(shí)現(xiàn)API編程的知識(shí)要點(diǎn)。
    2017-11-11
  • 手把手教你搞懂冒泡排序和選擇排序

    手把手教你搞懂冒泡排序和選擇排序

    這篇文章主要介紹了java數(shù)組算法例題代碼詳解(冒泡排序,選擇排序),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-07-07
  • Kibana的安裝和配置全過程

    Kibana的安裝和配置全過程

    Kibana是一個(gè)開源的數(shù)據(jù)分析和可視化平臺(tái),它與Elasticsearch緊密集成,提供了一個(gè)直觀的Web界面,使您可以快速地搜索、分析和可視化數(shù)據(jù),在本文中,我們將介紹如何安裝和配置Kibana
    2024-12-12
  • Java之Scanner.nextLine()讀取回車的問題及解決

    Java之Scanner.nextLine()讀取回車的問題及解決

    這篇文章主要介紹了Java之Scanner.nextLine()讀取回車的問題及解決,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • spring項(xiàng)目實(shí)現(xiàn)單元測試過程解析

    spring項(xiàng)目實(shí)現(xiàn)單元測試過程解析

    這篇文章主要介紹了spring項(xiàng)目實(shí)現(xiàn)單元測試過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • Java WebService 簡單實(shí)例(附實(shí)例代碼)

    Java WebService 簡單實(shí)例(附實(shí)例代碼)

    本篇文章主要介紹了Java WebService 簡單實(shí)例(附實(shí)例代碼), Web Service 是一種新的web應(yīng)用程序分支,他們是自包含、自描述、模塊化的應(yīng)用,可以發(fā)布、定位、通過web調(diào)用。有興趣的可以了解一下
    2017-01-01
  • SpringSecurity表單配置之登錄成功及頁面跳轉(zhuǎn)原理解析

    SpringSecurity表單配置之登錄成功及頁面跳轉(zhuǎn)原理解析

    這篇文章主要介紹了SpringSecurity表單配置之登錄成功及頁面跳轉(zhuǎn)原理解析,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2023-12-12
  • MyBatis中的limit分頁設(shè)置

    MyBatis中的limit分頁設(shè)置

    這篇文章主要介紹了MyBatis中的limit分頁設(shè)置方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11

最新評論