亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

SpringBoot ThreadLocal實現(xiàn)公共字段自動填充案例講解

 更新時間:2022年10月12日 11:39:39   作者:懶羊羊.java  
每一次在Controller層中封裝改動數(shù)據(jù)的方法時都要重新設(shè)置一些共性字段,顯得十分冗余。為了解決此問題也是在項目中第一次利用到線程,總的來說還是讓我眼前一亮,也開闊了視野,對以后的開發(fā)具有深遠(yuǎn)的意義

一.字段自動填充引入

先看一個現(xiàn)象,在之前寫好的表中,我們發(fā)現(xiàn)有很多字段重復(fù)出現(xiàn)

比如update_time、create_time、create_user…

這就導(dǎo)致需要在Controller層中每一次對表中數(shù)據(jù)進行修改后調(diào)用一次.setCreateTime(LocalDateTime.now());或者setUpdateTime(LocalDateTime.now());等等“硬編碼問題又出現(xiàn)了”顯得格外麻煩

這些共性字段如何統(tǒng)一拿出來處理呢?MyBatisPlus給了我們解決方案,為了實現(xiàn)這一功能:

首先

我們需要在公共字段對應(yīng)的實體屬性上加上@TableField注解與指定填充策略,就像這樣:

    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    @TableField(fill = FieldFill.INSERT)
    private Long createUser;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;

不難看出,fill的類型是一個枚舉類

若是不需要處理則選擇DEAFULT,若是增添后需要修改字段的值選擇INSERT,若是涉及修改數(shù)據(jù)時需要修改字段的值則選擇UPDATE,若是插入和修改都需要設(shè)置字段的值則選擇INSERT_UPDATE就像updateTime和updateUser,只要涉及對數(shù)據(jù)的操作就要修改字段的值

類似于全局異常處理器,為了實現(xiàn)字段填充也需要定義一個元數(shù)據(jù)對象處理器

二.元數(shù)據(jù)對象處理器

在定義的類中實現(xiàn)MetaObjecthandler接口,并重寫接口中策略對應(yīng)的方法,就像這樣:

@Component
@Slf4j
public class MyMetaObjecthandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("公共字段自動填充...");
        log.info(metaObject.toString());
    }
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("公共字段自動填充...");
        log.info(metaObject.toString());
    }
}

這里有點像繼承HttpServlet那個套路,重寫doGet()與doPost()方法,要實現(xiàn)什么功能就寫在對應(yīng)的方法里…

重寫完方法,不妨debug一下:

發(fā)現(xiàn)我實現(xiàn)接口后在方法里拿到了實體的數(shù)據(jù),并封裝到了形參里的metaObject對象中,接下來我就可以利用此對象來做公共字段的集中處理了!

所謂的自動填充也正是因為該類擁有@Component注解,在每一次的項目啟動后就會被掃描到,加載到,而類中的方法又實現(xiàn)了功能,所以才可以做到自動填充字段!

回到正題

我們要做的是把公共的字段做到統(tǒng)一填充,具體實現(xiàn)則是在重寫的方法里調(diào)用setValue()方法并傳進去字段與參數(shù),就像這樣:

    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("公共字段自動填充...");
        log.info(metaObject.toString());
        metaObject.setValue("createTime", LocalDateTime.now());
        metaObject.setValue("updateTime",LocalDateTime.now());
    }
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("公共字段自動填充...");
        log.info(metaObject.toString());
        metaObject.setValue("updateTime",LocalDateTime.now());
    }

相比之前controller層中的employee.setCreateTime(LocalDateTime.now());/employee.setUpdateTime(LocalDateTime.now());來看還是比較好理解,無非就是“茴“字的另一種寫法

(但卻實現(xiàn)了一勞永逸)…

可能有人會問,懶羊羊你的updateUser與createUser字段怎么不處理呢?

確實,還記得之前在controller層中我們是怎么處理的嗎?

為了確定User是誰,我們從Session里拿到了操作的對象id,并調(diào)用set方法修改了對象的字段值

按照上面的經(jīng)驗,為了能夠動態(tài)的拿到id,我們應(yīng)該這樣設(shè)置:

可是,在此方法中metaObject對象好像不能利用Session里的empID,那要如何獲得對象的標(biāo)識呢?

不就是一個標(biāo)識么,我用線程id可以嗎?

三.Threadlocal的使用

在這之前,需要明白一點,每當(dāng)客戶端發(fā)送一次HTTP請求,對應(yīng)在服務(wù)器端會分配一個新的線程來處理。項目設(shè)計到現(xiàn)在為止,以點擊一次保存按鈕作為一次請求,它會觸發(fā)過濾器、調(diào)用Controller層、MetaObjectHandler層的方法

我們通過Thread的內(nèi)部方法:long id = Thread.currentThread().getId();來獲得當(dāng)前線程的id,以日志的形式log.info("當(dāng)前線程id:{}",id);輸出到控制臺:

可見,三者的線程id相同,說明他們在同一個線程中,這就保證了一致性,也正是因為這個特性,所以可用來當(dāng)作表中的字段id使用來作為標(biāo)識

在此基礎(chǔ)上,大致方向已經(jīng)敲定是利用線程的特性,具體要如何實現(xiàn)呢?那就不得不需要了解一下ThreadLocal這個概念了:

1.ThreadLocal并不是一個Thread,而是Thread的局部變量。

2.當(dāng)使用ThreadLocal維護變量時,ThreadLocal為每個使用該變量的線程提供獨立的變量副本,所以每一個線程都可以獨立地改變自己的副本,而不會影響其它線程所對應(yīng)的副本。

3.ThreadLocal為每個線程提供單獨一份存儲空間,具有線程隔離的效果,只有在線程內(nèi)才能獲取到對應(yīng)的值,線程外則不能訪問

常用方法

public void set(T value)設(shè)置當(dāng)前線程局部變量的值
public T get()返回當(dāng)前線程所對應(yīng)的線程局部變量的值

了解到ThreadLocal特性,我們就可以結(jié)合“同一線程”這一特性來獲得那個對象唯一的SessionId。

?? 在前面的登錄功能中我們設(shè)置了一個filter,在filter中我們已經(jīng)拿到過了一次SessionId,寫到這里解決方案不就出來了嘛——把filter中的SessionId當(dāng)作參數(shù)傳給ThreadLocal的set方法,然后在MetaObjectHandler實現(xiàn)類(元數(shù)據(jù)對象處理器)中調(diào)用ThreadLocal的get()方法得到SessionId

就像這樣:

1.為了規(guī)范,我們封裝一個類,功能是調(diào)用ThreadLocal的方法

/**
 * 基于ThreadLocal封裝工具類,用于保護和獲取當(dāng)前登錄id
 */
public class BaseContext {
    private static ThreadLocal<Long> threadLocal=new ThreadLocal();
    public static void setCurrentId(Long currentId){
        threadLocal.set(currentId);
    }
    public static Long getCurrentId(){
        return threadLocal.get();
    }
}

2.在filter中做到SessionId的遷移

3.在MetaObjectHandler實現(xiàn)類中利用SessionId完成公共字段填充設(shè)置

    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("公共字段自動填充...");
        log.info(metaObject.toString());
        long id = Thread.currentThread().getId();
        log.info("當(dāng)前線程id:{}",id);
        metaObject.setValue("updateTime",LocalDateTime.now());
        metaObject.setValue("createUser",BaseContext.getCurrentId());
        metaObject.setValue("updateUser",BaseContext.getCurrentId());
    }

這樣,就可以一勞永逸咯~

又是一個小技巧??!

到此這篇關(guān)于SpringBoot ThreadLocal實現(xiàn)公共字段自動填充案例講解的文章就介紹到這了,更多相關(guān)SpringBoot自動填充內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論