Auto‑populate Audit Fields in Spring Boot with AOP: A Step‑by‑Step Guide
Learn how to use Spring Boot’s AOP features to automatically fill creator, creation time, updater, and update time fields for any DAO insert or update operation, eliminating repetitive code and ensuring consistent audit logging across all database tables.
Background
In database design it is common to add generic fields such as creator, createTime, updater, updateTime to every table for basic audit logging. Manually setting these fields in every SQL statement becomes verbose, especially with many tables. Spring’s AOP can automate this process.
Core Code
@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();
}
}Code Introduction
The aspect defines four constant field names and two pointcuts that match any DAO method whose name starts with insert or update. The @Around advice populates the audit fields before the original DAO method executes.
Annotation Explanation
@Aspect: declares the class as an aspect containing pointcuts and advice.
@Component: registers the class as a Spring bean.
@Pointcut: defines where the aspect applies, here matching DAO methods with insert or update in their names.
@Around: surrounds the matched method, allowing us to add or modify parameters before and after execution.
Note: execution(* com.xx.xxxx..dao..update*(..)) matches any method under the dao package that starts with update, and similarly for insert.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
ITFLY8 Architecture Home
ITFLY8 Architecture Home - focused on architecture knowledge sharing and exchange, covering project management and product design. Includes large-scale distributed website architecture (high performance, high availability, caching, message queues...), design patterns, architecture patterns, big data, project management (SCRUM, PMP, Prince2), product design, and more.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
