SpringBoot實(shí)現(xiàn)公共字段自動填充的方法步驟
問題引入
JavaEE開發(fā)的時(shí)候,新增字段,修改字段大都會涉及到創(chuàng)建時(shí)間(createTime),更改時(shí)間(updateTime),創(chuàng)建人(craeteUser),更改人(updateUser),如果每次都要自己去setter(),會比較麻煩,可以使用Spring的AOP,對于任意Insert,Update操作進(jìn)行增強(qiáng)
解決步驟
主要依賴
如果使用了springboot,那就只需要導(dǎo)入這一個(gè),這個(gè)框架對spring自帶的aop框架進(jìn)行了優(yōu)化封裝,更好用
事實(shí)上,還需要兩個(gè)依賴,spring-context和spring-aop,不過springboot自帶的有
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency>
注釋代碼
給那些新增、修改功能中的設(shè)置時(shí)間、修改人的代碼部分注釋掉
自定義注解&使用
封裝數(shù)據(jù)庫操作類型
/** * 數(shù)據(jù)庫操作類型 */ public enum OperationType { /** * 更新操作 */ UPDATE, /** * 插入操作 */ INSERT }
自定義注解
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface AutoFill { // 數(shù)據(jù)庫操作類型:UPDATE INSERT OperationType value(); }
給需要自動填充的方法加上注解
/** * 新增員工 * @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);
通知類
@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("開始進(jìn)行公共字段自動填充..."); // 拿到當(dāng)前被攔截的方法上的數(shù)據(jù)庫操作類型 MethodSignature signature = (MethodSignature)joinPoint.getSignature();// 拿到實(shí)現(xiàn)類的簽名信息,不過我們只需要方法的簽名信息,強(qiáng)轉(zhuǎn)成MethodSignature AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);// 獲得簽名對象的注解對象 OperationType operationType = autoFill.value(); // 拿到數(shù)據(jù)庫操作類型 // 拿到當(dāng)前被攔截方法的方法參數(shù)(新增、更改方法的參數(shù)一般都是實(shí)體類) Object[] args = joinPoint.getArgs(); if (args == null || args.length == 0){ // 防止null,防止空參 return; } Object entity = args[0]; // 這一行就要求,以后的新增、更改方法參數(shù),實(shí)體類必須寫在首形參位置 // 需填充的數(shù)據(jù) LocalDateTime now = LocalDateTime.now(); Long currentId = BaseContext.getCurrentId(); // 根據(jù)當(dāng)前不同的操作類型,使用反射為對應(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); // 通過反射給對象屬性賦值 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); // 通過反射給對象屬性賦值 setUpdateTime.invoke(entity, now); setUpdateUser.invoke(entity, currentId); } catch (Exception e) { e.printStackTrace(); } } } }
依賴相關(guān)類
公共字段自動填充相關(guān)常量
/** * 公共字段自動填充相關(guān)常量 */ public class AutoFillConstant { /** * 實(shí)體類中的方法名稱 */ 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(); } }
啟動類加上注解@EnableAspectJAutoProxy
@SpringBootApplication @EnableTransactionManagement //開啟注解方式的事務(wù)管理 @EnableAspectJAutoProxy // 開啟注解方式的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í)行過程中切入的某個(gè)點(diǎn)。Signature 則是 Signature 接口的實(shí)現(xiàn)類之一,用于表示連接點(diǎn)的簽名信息,包括方法名、參數(shù)列表等。
具體來說,這段代碼的含義是從 joinPoint 中獲取連接點(diǎn)的簽名信息,并將其強(qiáng)制轉(zhuǎn)換為 MethodSignature 類型。然后可以通過 signature 對象獲取連接點(diǎn)(被代理方法)的詳細(xì)信息,比如方法名、參數(shù)類型等。
例如,可以通過 signature.getMethod().getName() 獲取連接點(diǎn)方法的名稱,通過 signature.getParameterTypes() 獲取連接點(diǎn)方法的參數(shù)類型數(shù)組等。
需要注意的是,在實(shí)際應(yīng)用中,我們使用這段代碼時(shí)需要確保 joinPoint 真正代表了一個(gè)方法連接點(diǎn),否則在強(qiáng)制轉(zhuǎn)換為 MethodSignature 時(shí)可能會拋出類型轉(zhuǎn)換異常。
到此這篇關(guān)于SpringBoot實(shí)現(xiàn)公共字段自動填充的方法步驟的文章就介紹到這了,更多相關(guān)SpringBoot公共字段自動填充內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java實(shí)現(xiàn)后臺返回base64圖形編碼
這篇文章主要介紹了java實(shí)現(xiàn)后臺返回base64圖形編碼,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06Java將數(shù)組轉(zhuǎn)換成字符串的四種方法總結(jié)
這篇文章主要給大家介紹了關(guān)于Java將數(shù)組轉(zhuǎn)換成字符串的四種方法,每種方法都有其適用的場景和優(yōu)缺點(diǎn),文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-12-12Zookeeper中如何解決zookeeper.out文件輸出位置問題
這篇文章主要介紹了Zookeeper中如何解決zookeeper.out文件輸出位置問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04集成Spring Redis緩存的實(shí)現(xiàn)
今天小編就為大家分享一篇關(guān)于集成Spring Redis緩存的實(shí)現(xiàn),小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-12-12SpringBoot實(shí)現(xiàn)無感刷新Token的項(xiàng)目實(shí)踐
token刷新是前端安全中必要的一部分,本文就來介紹一下SpringBoot實(shí)現(xiàn)無感刷新Token的項(xiàng)目實(shí)踐,具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03Java+opencv3.2.0實(shí)現(xiàn)模板匹配
這篇文章主要為大家詳細(xì)介紹了Java+opencv3.2.0實(shí)現(xiàn)模板匹配的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-02-02Maven搭建springboot項(xiàng)目的方法步驟
這篇文章主要介紹了Maven搭建springboot項(xiàng)目的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04