SpringBoot實(shí)現(xiàn)公共字段自動(dòng)填充的方法步驟
問(wèn)題引入
JavaEE開(kāi)發(fā)的時(shí)候,新增字段,修改字段大都會(huì)涉及到創(chuàng)建時(shí)間(createTime),更改時(shí)間(updateTime),創(chuàng)建人(craeteUser),更改人(updateUser),如果每次都要自己去setter(),會(huì)比較麻煩,可以使用Spring的AOP,對(duì)于任意Insert,Update操作進(jìn)行增強(qiáng)
解決步驟
主要依賴
如果使用了springboot,那就只需要導(dǎo)入這一個(gè),這個(gè)框架對(duì)spring自帶的aop框架進(jìn)行了優(yōu)化封裝,更好用
事實(shí)上,還需要兩個(gè)依賴,spring-context和spring-aop,不過(guò)springboot自帶的有
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency>
注釋代碼
給那些新增、修改功能中的設(shè)置時(shí)間、修改人的代碼部分注釋掉
自定義注解&使用
封裝數(shù)據(jù)庫(kù)操作類(lèi)型
/** * 數(shù)據(jù)庫(kù)操作類(lèi)型 */ public enum OperationType { /** * 更新操作 */ UPDATE, /** * 插入操作 */ INSERT }
自定義注解
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface AutoFill { // 數(shù)據(jù)庫(kù)操作類(lèi)型:UPDATE INSERT OperationType value(); }
給需要自動(dòng)填充的方法加上注解
/** * 新增員工 * @param employee */ @Insert("INSERT INTO employee" + "(name, username, password, phone, sex, id_number, create_time, update_time, create_user, update_user)" + "VALUES" + "(#{name}, #{username}, #{password}, #{phone}, #{sex}, #{idNumber}, #{createTime}, #{updateTime}, #{createUser}, #{updateUser})") @AutoFill(value = OperationType.INSERT) void insert(Employee employee); /** * 修改員工信息 * @param employee */ @AutoFill(value = OperationType.UPDATE) void update(Employee employee); /** * 根據(jù)ID查詢員工 * @param id * @return */ @Select("SELECT * FROM employee WHERE id = #{id}") Employee getById(Long id); /** * 密碼修改 * @param passwordEditDTO */ @AutoFill(value = OperationType.UPDATE) @Update("UPDATE employee SET `password` = #{newPassword} WHERE `id` = #{empId} AND `password` = #{oldPassword}") void updatePwd(PasswordEditDTO passwordEditDTO);
通知類(lèi)
@Slf4j @Component @Aspect public class AutoFillAspect { /** * 切面 && 指定切入點(diǎn) */ @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)") public void autoFillPointCut(){} /** * 切面 && 此方法(autoFill()) 在切入點(diǎn)之前執(zhí)行 * @param joinPoint */ @Before("autoFillPointCut()") public void autoFill(JoinPoint joinPoint) { log.info("開(kāi)始進(jìn)行公共字段自動(dòng)填充..."); // 拿到當(dāng)前被攔截的方法上的數(shù)據(jù)庫(kù)操作類(lèi)型 MethodSignature signature = (MethodSignature)joinPoint.getSignature();// 拿到實(shí)現(xiàn)類(lèi)的簽名信息,不過(guò)我們只需要方法的簽名信息,強(qiáng)轉(zhuǎn)成MethodSignature AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);// 獲得簽名對(duì)象的注解對(duì)象 OperationType operationType = autoFill.value(); // 拿到數(shù)據(jù)庫(kù)操作類(lèi)型 // 拿到當(dāng)前被攔截方法的方法參數(shù)(新增、更改方法的參數(shù)一般都是實(shí)體類(lèi)) Object[] args = joinPoint.getArgs(); if (args == null || args.length == 0){ // 防止null,防止空參 return; } Object entity = args[0]; // 這一行就要求,以后的新增、更改方法參數(shù),實(shí)體類(lèi)必須寫(xiě)在首形參位置 // 需填充的數(shù)據(jù) LocalDateTime now = LocalDateTime.now(); Long currentId = BaseContext.getCurrentId(); // 根據(jù)當(dāng)前不同的操作類(lèi)型,使用反射為對(duì)應(yīng)的屬性賦值 if (operationType == OperationType.INSERT) { // 為4個(gè)公共字段賦值 try { Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class); Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class); Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class); Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class); // 通過(guò)反射給對(duì)象屬性賦值 setCreateTime.invoke(entity, now); setUpdateTime.invoke(entity, now); setCreateUser.invoke(entity, currentId); setUpdateUser.invoke(entity, currentId); } catch (Exception e) { e.printStackTrace(); } } else if (operationType == OperationType.UPDATE) { // 為2個(gè)公共字段賦值 try { Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class); Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class); // 通過(guò)反射給對(duì)象屬性賦值 setUpdateTime.invoke(entity, now); setUpdateUser.invoke(entity, currentId); } catch (Exception e) { e.printStackTrace(); } } } }
依賴相關(guān)類(lèi)
公共字段自動(dòng)填充相關(guān)常量
/** * 公共字段自動(dòng)填充相關(guān)常量 */ public class AutoFillConstant { /** * 實(shí)體類(lèi)中的方法名稱 */ public static final String SET_CREATE_TIME = "setCreateTime"; public static final String SET_UPDATE_TIME = "setUpdateTime"; public static final String SET_CREATE_USER = "setCreateUser"; public static final String SET_UPDATE_USER = "setUpdateUser"; }
線程空間上下文
public class BaseContext { public static ThreadLocal<Long> threadLocal = new ThreadLocal<>(); public static void setCurrentId(Long id) { threadLocal.set(id); } public static Long getCurrentId() { return threadLocal.get(); } public static void removeCurrentId() { threadLocal.remove(); } }
啟動(dòng)類(lèi)加上注解@EnableAspectJAutoProxy
@SpringBootApplication @EnableTransactionManagement //開(kāi)啟注解方式的事務(wù)管理 @EnableAspectJAutoProxy // 開(kāi)啟注解方式的AOP @Slf4j public class SkyApplication { public static void main(String[] args) { SpringApplication.run(SkyApplication.class, args); log.info("server started"); } }
在這段代碼中,joinPoint 是 Spring AOP 中的一個(gè)概念,表示連接點(diǎn),即在程序執(zhí)行過(guò)程中切入的某個(gè)點(diǎn)。Signature 則是 Signature 接口的實(shí)現(xiàn)類(lèi)之一,用于表示連接點(diǎn)的簽名信息,包括方法名、參數(shù)列表等。
具體來(lái)說(shuō),這段代碼的含義是從 joinPoint 中獲取連接點(diǎn)的簽名信息,并將其強(qiáng)制轉(zhuǎn)換為 MethodSignature 類(lèi)型。然后可以通過(guò) signature 對(duì)象獲取連接點(diǎn)(被代理方法)的詳細(xì)信息,比如方法名、參數(shù)類(lèi)型等。
例如,可以通過(guò) signature.getMethod().getName() 獲取連接點(diǎn)方法的名稱,通過(guò) signature.getParameterTypes() 獲取連接點(diǎn)方法的參數(shù)類(lèi)型數(shù)組等。
需要注意的是,在實(shí)際應(yīng)用中,我們使用這段代碼時(shí)需要確保 joinPoint 真正代表了一個(gè)方法連接點(diǎn),否則在強(qiáng)制轉(zhuǎn)換為 MethodSignature 時(shí)可能會(huì)拋出類(lèi)型轉(zhuǎn)換異常。
到此這篇關(guān)于SpringBoot實(shí)現(xiàn)公共字段自動(dòng)填充的方法步驟的文章就介紹到這了,更多相關(guān)SpringBoot公共字段自動(dòng)填充內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot Mybatis Plus公共字段自動(dòng)填充功能
- Mybatis plus的自動(dòng)填充與樂(lè)觀鎖的實(shí)例詳解(springboot)
- SpringBoot實(shí)現(xiàn)字段自動(dòng)填充的兩種方式
- Springboot實(shí)現(xiàn)公共字段填充的示例詳解
- SpringBoot ThreadLocal實(shí)現(xiàn)公共字段自動(dòng)填充案例講解
- SpringBoot項(xiàng)目中公共字段填充的實(shí)現(xiàn)
- SpringBoot自定義注解如何解決公共字段填充問(wèn)題
- SpringBoot基于MyBatisPlus實(shí)現(xiàn)公共字段自動(dòng)填充
相關(guān)文章
Spring Boot整合mybatis使用注解實(shí)現(xiàn)動(dòng)態(tài)Sql、參數(shù)傳遞等常用操作(實(shí)現(xiàn)方法)
這篇文章主要介紹了Spring Boot整合mybatis使用注解實(shí)現(xiàn)動(dòng)態(tài)Sql、參數(shù)傳遞等常用操作(實(shí)現(xiàn)方法),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08Java服務(wù)限流算法的6種實(shí)現(xiàn)
服務(wù)限流是指通過(guò)控制請(qǐng)求的速率或次數(shù)來(lái)達(dá)到保護(hù)服務(wù)的目的,本文主要介紹了Java服務(wù)限流算法的6種實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2023-05-05SpringSecurity實(shí)現(xiàn)圖形驗(yàn)證碼功能的實(shí)例代碼
Spring Security 的前身是 Acegi Security ,是 Spring 項(xiàng)目組中用來(lái)提供安全認(rèn)證服務(wù)的框架。這篇文章主要介紹了SpringSecurity實(shí)現(xiàn)圖形驗(yàn)證碼功能,需要的朋友可以參考下2018-10-10SpringBoot一個(gè)接口多個(gè)實(shí)現(xiàn)類(lèi)的調(diào)用方式總結(jié)
這篇文章主要介紹了SpringBoot一個(gè)接口多個(gè)實(shí)現(xiàn)類(lèi)的調(diào)用方式,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2024-01-01簡(jiǎn)單了解mybatis攔截器實(shí)現(xiàn)原理及實(shí)例
這篇文章主要介紹了簡(jiǎn)單了解mybatis攔截器實(shí)現(xiàn)原理及實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-01-01