1. Custom Annotation for Auto-Fill
Define a custom annotation to mark methods that require automatic field populatoin.
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
OperationType value();
}
The OperationType enum specifies the database operation type.
public enum OperationType {
UPDATE,
INSERT
}
2. Aspect for Automated Field Handling
Create an aspect to intercept methods annotated with @AutoFill and populate common fields via reflection.
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
@Aspect
@Component
@Slf4j
public class FieldAutoFillAspect {
@Pointcut("execution(* com.example.mapper.*.*(..)) && @annotation(com.example.annotation.AutoFill)")
public void autoFillPointcut() {}
@Before("autoFillPointcut()")
public void fillCommonFields(JoinPoint joinPoint) {
log.info("Auto-filling common fields...");
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);
OperationType operationType = autoFill.value();
Object[] args = joinPoint.getArgs();
if (args == null || args.length == 0) {
return;
}
Object entity = args[0];
LocalDateTime currentTime = LocalDateTime.now();
Long currentUserId = getCurrentUserId();
try {
if (operationType == OperationType.INSERT) {
Method setCreateTime = entity.getClass().getDeclaredMethod("setCreateTime", LocalDateTime.class);
Method setCreateUser = entity.getClass().getDeclaredMethod("setCreateUser", Long.class);
Method setUpdateTime = entity.getClass().getDeclaredMethod("setUpdateTime", LocalDateTime.class);
Method setUpdateUser = entity.getClass().getDeclaredMethod("setUpdateUser", Long.class);
setCreateTime.invoke(entity, currentTime);
setCreateUser.invoke(entity, currentUserId);
setUpdateTime.invoke(entity, currentTime);
setUpdateUser.invoke(entity, currentUserId);
} else if (operationType == OperationType.UPDATE) {
Method setUpdateTime = entity.getClass().getDeclaredMethod("setUpdateTime", LocalDateTime.class);
Method setUpdateUser = entity.getClass().getDeclaredMethod("setUpdateUser", Long.class);
setUpdateTime.invoke(entity, currentTime);
setUpdateUser.invoke(entity, currentUserId);
}
} catch (Exception e) {
throw new RuntimeException("Failed to auto-fill fields", e);
}
}
private Long getCurrentUserId() {
return UserContext.getCurrentUserId();
}
}
The aspect uses a pointcut targeting methods within the mapper package that are annotated with @AutoFill. The @Before advice executes before these methods, populating fields based on the operasion type. Ensure the entity parameter is the first argument in the intercepted method.
Add the Spring AOP dependency to your pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
3. Applying the Annotation to Mapper Methods
Annotate the appropriate mapper methods with @AutoFill and specify the operation type.
@AutoFill(OperationType.UPDATE)
void modifyEmployee(Employee employee);
@AutoFill(OperationType.INSERT)
void addEmployee(Employee employee);
4. Key Technologies
This implementation utilizes Java annotations, aspect-oriented programming (AOP), reflection, and enumerations to automate common field population, reducing boilerplate code and improving maintainability.