背景
資料庫設計過程中,我們往往會給資料庫表添加一些通用字段,比如建立人、建立時間、修改人、修改時間,在一些公司的設計過程中有時會強制要求每個表都要包含這些基礎資訊,以便記錄資料操作時的一些基本日志記錄。
按照平常的操作來說,通用做法是輸寫sql時,将這些資訊和對象的基本屬性資訊一起寫入資料庫,當然,這也是大家習以為常的操作,這種寫法無可厚非,但是對于一個進階開發人員來說,如果所有的表都進行如此操作,未免顯得有點啰嗦,而且資料表多的話,這樣寫就有點得不償失了。
其實還有一種更簡便的做法,spring架構大家應該是比較熟悉的,幾乎每個公司都會用到,其中aop思想(切面程式設計)的經典應用場景之一就是日志記錄,本文結合aop思想,着重介紹下springboot架構下如何利用切面程式設計思想實作将建立人、建立時間、更新人、更新時間等基礎資訊寫入資料庫。
核心代碼
@Aspect
@Component
@Configuration
public class CommonDaoAspect {
private static final String creater = "creater";
private static final String createTime = "createTime";
private static final String updater = "updater";
private static final String updateTime = "updateTime";
@Pointcut("execution(* com.xx.xxxx.*.dao.*.update*(..))")
public void daoUpdate() {
}
@Pointcut("execution(* com.xx.xxxx.*.dao.*.insert*(..))")
public void daoCreate() {
}
@Around("daoUpdate()")
public Object doDaoUpdate(ProceedingJoinPoint pjp) throws Throwable {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes == null) {
return pjp.proceed();
}
HttpServletRequest request = attributes.getRequest();
String token = request.getHeader("token");
String username = getUserName();
if (token != null && username != null) {
Object[] objects = pjp.getArgs();
if (objects != null && objects.length > 0) {
for (Object arg : objects) {
BeanUtils.setProperty(arg, updater, username);
BeanUtils.setProperty(arg, updateTime, new Date());
}
}
}
Object object = pjp.proceed();
return object;
}
@Around("daoCreate()")
public Object doDaoCreate(ProceedingJoinPoint pjp) throws Throwable {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes == null) {
return pjp.proceed();
}
Object[] objects = pjp.getArgs();
if (objects != null && objects.length > 0) {
for (Object arg : objects) {
String username = getUserName();
if (username != null) {
if (StringUtils.isBlank(BeanUtils.getProperty(arg, creater))) {
BeanUtils.setProperty(arg, creater, username);
}
if (StringUtils.isBlank(BeanUtils.getProperty(arg, createTime))) {
BeanUtils.setProperty(arg, createTime, new Date());
}
}
}
}
Object object = pjp.proceed();
return object;
}
private String getUserName() {
return UserUtils.getUsername();
}
}
複制代碼
代碼介紹及注解說明
1.代碼介紹
核心代碼聲明了一個CommonDaoAspect切面類,實體類中聲明了4個核心方法和一個擷取使用者名資訊的方法,UserUtils是項目中聲明的工具類,包含擷取使用者id、姓名等一些基礎資訊,大家可以根據自己的實際情況去定義,不要照部就搬。
4個核心方法中,daoUpdate和daoCreate上添加了@Pointcut注解,該注解通過聲明正規表達式來确定項目包中dao目錄下哪些方法執行該切面方法。doDaoUpdate和doDaoCreate方法上添加了@Around注解,注解中引入了上述兩個方法,表示環繞通知,在我們自己dao目錄下的對應檔案目标方法完成前後做增強處理。
2.注解說明
@Aspect:聲明切面類,裡面可以定義切入點和通知
@Component:表明該類是spring管理的一個對象
@Pointcut:切入點,通過正規表達式聲明切入的時機,本文中是在目标方法(即項目中dao目錄下實體類中包含insert或update字元串的方法)執行時加入切入資訊,即執行新增或更新時加入建立人和更新人等資訊。
@Around:環繞通知,在目标方法完成前後做增強處理,本案例中表示在doCreate和doUpdate方法執行時添加參數資訊
注:execution(* com.xx.xxxx..dao..update*(..)) 表示在dao目錄下的任何檔案中的以update開頭的方法
execution(* com.xx.xxxx..dao..insert*(..)) 表示在dao目錄下的任何檔案中的以insert開頭的方法