Mybatis-Plus實(shí)現(xiàn)公共字段自動(dòng)填充的項(xiàng)目實(shí)踐
一、公共字段自動(dòng)填充
1.1 問題分析
比如說在新增用戶需要指定創(chuàng)建時(shí)間、創(chuàng)建人等字段,
修改用戶時(shí)需要指定修改時(shí)間、修改人等字段
這些字段屬于公共字段,也就是很多表中都有這些字段
這樣我們?cè)谝院髮懫饋矸浅5穆闊?每次做操作都需要自己手動(dòng)寫。但是對(duì)于Mybatis plus來說這些是小意思,它為我們提供了公共字段自動(dòng)填充功能
1.2 實(shí)現(xiàn)思路及代碼編寫
Mybatis plus 公共字段自動(dòng)填充,也就是在插入或者更新的時(shí)候?yàn)橹付ㄗ侄钨x予指定的值,使用它的好處就是統(tǒng)一對(duì)這些字段進(jìn)行處理,避免了代碼重復(fù)。
實(shí)現(xiàn)步驟:
1. 在實(shí)體類的屬性上加入@TableField注解,指定自動(dòng)填充的策略
@TableField(value ="create_time",fill = FieldFill.INSERT) //插入時(shí)填充字段 private LocalDateTime createTime; @TableField(value ="update_time",fill = FieldFill.INSERT_UPDATE)//插入和更新時(shí)填充字段 private LocalDateTime updateTime; @TableField(value = "create_user",fill = FieldFill.INSERT)//插入時(shí)填充字段 private Long createUser; @TableField(value = "update_user",fill = FieldFill.INSERT_UPDATE)//插入和更新時(shí)填充字段 private Long updateUser;
其中FieldFill是一個(gè)枚舉類,如下所示:
2. 按照框架要求編寫元數(shù)據(jù)對(duì)象處理器,在此類中統(tǒng)一為公共字段賦值,此類需要實(shí)現(xiàn)MetaObjectHandler接口
package com.reggie_take_out.common; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.reflection.MetaObject; import org.springframework.stereotype.Component; import java.time.LocalDateTime; /** * 元數(shù)據(jù)對(duì)象處理器 */ @Component @Slf4j public class MyMetaObjectHandler implements MetaObjectHandler { /** * 執(zhí)行insert語句的時(shí)候執(zhí)行 * * @param metaObject */ @Override public void insertFill(MetaObject metaObject) { log.info("公共字段自動(dòng)填充——insertFill"); // 自動(dòng)填充 metaObject.setValue("createTime", LocalDateTime.now()); metaObject.setValue("updateTime", LocalDateTime.now()); // 獲取session對(duì)象 metaObject.setValue("createUser", BaseContext.getCurrentId()); metaObject.setValue("updateUser", BaseContext.getCurrentId()); } /** * 執(zhí)行update語句的時(shí)候執(zhí)行 * * @param metaObject */ @Override public void updateFill(MetaObject metaObject) { log.info("公共字段自動(dòng)填充——updateFill"); metaObject.setValue("updateTime", LocalDateTime.now()); metaObject.setValue("updateUser", BaseContext.getCurrentId()); } }
二、 知識(shí)補(bǔ)充: ThreadLocal
2.1 使用背景
為什么要使用這個(gè)類?
比如我們要給updateUser與createUser字段設(shè)置值的時(shí)候,我們是通過HttpServletRequest對(duì)象獲取
request.getSession().getAttribute("employee");
但是我們?cè)?strong>寫公共字段自動(dòng)填充的時(shí)候發(fā)現(xiàn)不能使用HttpServletRequest。
除此之外,將用戶id放入到HttpSession中也是獲取不到的,MyMetaObjectHandler類中是不能獲取HttpSession對(duì)象的,所以我們需要其他方式來進(jìn)行獲取。
客戶端發(fā)送的每次Http請(qǐng)求,對(duì)應(yīng)的服務(wù)端都會(huì)分配一個(gè)新的線程來處理,在處理過程中涉及到下面類中的方法都屬于同一個(gè)線程
1.LoginCheckFilter 的doFilter方法
2.EmployeeController的update方法
3.MyMetaObjectHandler的updateFill方法
解決思路:
我們可以在LoginCheckFilter的doFilter方法中獲取當(dāng)前登錄用戶id,并調(diào)用ThreadLocal的set方法來設(shè)置當(dāng)前線程的線程局部變量的值(用戶id),然后再M(fèi)yMetaObjectHandler的updateFill方法中調(diào)用ThreadLocal的get方法來獲取當(dāng)前線程所對(duì)應(yīng)的線程局部變量的值(用戶id)
2.2 ThreadLocal介紹
- ThreadLocal并不是一個(gè)Thread,而是Thread的局部變量。
- 當(dāng)使用ThreadLocal維護(hù)變量時(shí),ThreadLocal為每個(gè)使用該變量的線程提供獨(dú)立的變量副本,所以每一個(gè)線程都可以獨(dú)立地改變自己副本,而不會(huì)影響其他線程所對(duì)應(yīng)的副本。
- ThreadLocal為每個(gè)線程提供單獨(dú)一份存儲(chǔ)空間,具有線程隔離的效果,只有在線程內(nèi)才能獲取到對(duì)應(yīng)的值,線程外則不能訪問。
2.2.1 設(shè)置當(dāng)前線程的線程局部變量的值 public void set(T value)
具體代碼查看2.3.1
2.2.2 返回當(dāng)前線程所對(duì)應(yīng)的線程 局部變量的值 public T get()
具體代碼查看2.3.1
2.3 實(shí)現(xiàn)功能
2.3.1 基于ThreadLocal封裝BaseContext工具類
/** * 基于ThreadLocal封裝工具類,用戶保存和獲取當(dāng)前登錄用戶id */ public class BaseContext { private static ThreadLocal<Long> threadLocal = new ThreadLocal<>(); public static void setCurrentId(Long id){ threadLocal.set(id); } public static Long getCurrentId(){ return threadLocal.get(); } }
2.3.2 在過濾器方法中調(diào)用BaseContext工具類設(shè)置當(dāng)前登錄用戶id
/** * 檢查用戶是否已經(jīng)完成登錄 * 過濾器與攔截器的區(qū)別:Filter對(duì)所有訪問進(jìn)行增強(qiáng)(在Tomcat服務(wù)器進(jìn)行配置),Interceptor僅針對(duì)SpringMVC的訪問進(jìn)行增強(qiáng) */ @Slf4j @WebFilter(filterName = "loginCheckFilter", urlPatterns = "/*") //urlPatterns指定攔截哪些路徑 public class LoginCheckFilter implements Filter { // 此對(duì)象的作用:路徑匹配器, 匹配路徑時(shí)支持通配符 public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher(); @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { // servletRequest向下強(qiáng)制類型轉(zhuǎn)換 HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; //1. 獲取本次請(qǐng)求的URI( URI:請(qǐng)求的資源路徑) String requestURI = request.getRequestURI(); log.info("攔截到請(qǐng)求:{}", request.getRequestURI()); // 定義不用處理的請(qǐng)求路徑 String[] urls = new String[]{ "/employee/login", "/employee/logout", "/backend/**", "/front/**" }; //2. 判斷本次請(qǐng)求是否需要處理(因?yàn)橛行┱?qǐng)求并不需要用戶登錄) boolean check = check(requestURI, urls); //3.如果不需要處理,則直接放行 if (check) { log.info("本次請(qǐng)求{}不需要處理", request.getRequestURI()); filterChain.doFilter(request, response); return; } //4.判斷登錄狀態(tài),如果已登錄,則直接放行.從session中獲取用戶,如果獲取到說明已經(jīng)登錄 if (request.getSession().getAttribute("employee") != null) { log.info("用戶已登錄,用戶id為{}", request.getSession().getAttribute("employee")); Long empId = (Long) request.getSession().getAttribute("employee"); BaseContext.setCurrentId(empId); filterChain.doFilter(request, response); return; } //5.如果未登錄則返回未登錄結(jié)果 log.info("資源路徑路徑:{},用戶未登錄{}", request.getRequestURI(), request.getSession().getAttribute("employee")); // 通過輸出流的方式向客戶端響應(yīng)數(shù)據(jù) (為什么要返回這個(gè)NOTLOGIN? 因?yàn)榍岸诵枰@個(gè)來進(jìn)行判定是否登錄) response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN"))); // filterChain.doFilter(request, response); 加上這個(gè)就無法實(shí)現(xiàn) } /** * 檢查本次請(qǐng)求是否需要放行 * * @param requestURI 請(qǐng)求的資源路徑 * @param urls 放過的路徑 * @return true 放行 */ public boolean check(String requestURI, String[] urls) { for (String url : urls) { boolean match = PATH_MATCHER.match(url, requestURI); if (match) { // 放行 return true; } } return false; } }
2.3.3 在MyMetaObjectHandler的方法中調(diào)用BaseContext工具類獲取登錄用戶id
package com.reggie_take_out.common; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.reflection.MetaObject; import org.springframework.stereotype.Component; import java.time.LocalDateTime; /** * 元數(shù)據(jù)對(duì)象處理器 */ @Component @Slf4j public class MyMetaObjectHandler implements MetaObjectHandler { /** * 執(zhí)行insert語句的時(shí)候執(zhí)行 * * @param metaObject */ @Override public void insertFill(MetaObject metaObject) { log.info("公共字段自動(dòng)填充——insertFill"); // 自動(dòng)填充 metaObject.setValue("createTime", LocalDateTime.now()); metaObject.setValue("updateTime", LocalDateTime.now()); // 獲取session對(duì)象 metaObject.setValue("createUser", BaseContext.getCurrentId()); metaObject.setValue("updateUser", BaseContext.getCurrentId()); } /** * 執(zhí)行update語句的時(shí)候執(zhí)行 * * @param metaObject */ @Override public void updateFill(MetaObject metaObject) { log.info("公共字段自動(dòng)填充——updateFill"); metaObject.setValue("updateTime", LocalDateTime.now()); metaObject.setValue("updateUser", BaseContext.getCurrentId()); } }
到此這篇關(guān)于Mybatis-Plus實(shí)現(xiàn)公共字段自動(dòng)填充的項(xiàng)目實(shí)踐的文章就介紹到這了,更多相關(guān)Mybatis-Plus 公共字段自動(dòng)填充內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- MyBatisPlus實(shí)現(xiàn)自動(dòng)填充字段的實(shí)踐
- MyBatis-Plus自動(dòng)填充字段的詳細(xì)教程
- mybatis-plus調(diào)用update方法時(shí),自動(dòng)填充字段不生效問題及解決
- MyBatis-Puls插入或修改時(shí)某些字段自動(dòng)填充操作示例
- MyBatis-Plus邏輯刪除和字段自動(dòng)填充的實(shí)現(xiàn)
- MyBatis-Plus實(shí)現(xiàn)公共字段自動(dòng)填充功能詳解
- Mybatis-Plus自動(dòng)填充更新操作相關(guān)字段的實(shí)現(xiàn)
- MyBatis-Plus實(shí)現(xiàn)字段自動(dòng)填充功能的示例
- Mybatis plus通用字段自動(dòng)填充的示例
- Mybatis攔截器實(shí)現(xiàn)公共字段填充的示例代碼
相關(guān)文章
深入理解JavaWeb中過濾器與監(jiān)聽器的應(yīng)用
這篇文章主要介紹了JavaWeb中過濾器與監(jiān)聽器的應(yīng)用,過濾器能夠?qū)ζヅ涞恼?qǐng)求到達(dá)目標(biāo)之前或返回響應(yīng)之后增加一些處理代碼,監(jiān)聽器是一個(gè)接口內(nèi)容由我們實(shí)現(xiàn),會(huì)在特定時(shí)間被調(diào)用,感興趣想要詳細(xì)了解可以參考下文2023-05-05GraalVM?native-image編譯后quarkus的超音速啟動(dòng)
這篇文章主要介紹了經(jīng)過GraalVM?native-image編譯后的quarkus,來帶大家驗(yàn)證一下號(hào)稱超音速亞原子的quarkus是否名副其實(shí),有需要的朋友可以借鑒參考下,希望能夠有所包幫助2022-02-02Java實(shí)現(xiàn)AOP功能的封裝與配置的小框架實(shí)例代碼
這篇文章主要介紹了Java實(shí)現(xiàn)AOP功能的封裝與配置的小框架實(shí)例代碼,分享了相關(guān)代碼示例,小編覺得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-02-02DolphinScheduler容錯(cuò)源碼分析之Worker
這篇文章主要為大家介紹了DolphinScheduler容錯(cuò)源碼分析之Worker,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02解決mybatis三表連接查詢數(shù)據(jù)重復(fù)的問題
這篇文章主要介紹了解決mybatis三表連接查詢數(shù)據(jù)重復(fù)的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-01-01解決SpringCloud Gateway配置自定義路由404的坑
這篇文章主要介紹了解決SpringCloud Gateway配置自定義路由404的坑,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09