最近,项目需要实现一个字段自动填充功能,整体需求是这样子:在每次实体类进行插入、修改操作时,给公共字段自动赋值,公共字段有创建人Id、创建人名称、修改人Id、修改人名称、创建时间、修改时间,其中创建人Id、创建人名称、修改人Id、修改人名称从 Token 中解析获取。
最开始我的思路的是这样子的:写一个自定义注解,给需要自动注入的字段加上这个注解,再写一个 AOP 类,在每个实体即将进行插入、修改操作时切入,再利用反射完成字段的赋值。
由于项目的持久化框架是 JPA,我便去查阅相关资料,最终找到 JPA 进行持久化操作的生命周期注解(@PrePersist 保存前、@PreUpdate 修改前,相当于 JPA 为我们提供了一个 AOP 操作),再结合自定义注解和反射最终实现字段自动填充功能。
后面,由于项目不想在实体类上额外多使用一个注解,改成使用枚举类和反射实现字段自动填充功能。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface LoadingField {
boolean isTime() default false;
boolean isModified() default false;
}
@EntityListeners(FieldListener.class)
public class example {
@LoadingField
private Long creatorId;
@LoadingField
private String creatorName;
@LoadingField(isTime = true)
private Timestamp createTime;
@LoadingField(isModified = true)
private Long modifierId;
@LoadingField(isModified = true)
private String modifierName;
@LoadingField(isTime = true, isModified = true)
private Timestamp modifyTime;
}
@Slf4j
public class FieldListener extends BasicListener {
private static final String TOKEN_KEY = "access_token";
private static final Map<String, String> fieldMap = new HashMap<>();
private SysUserVO sysUserVo;
// 保存之前,为创建时间和创建人赋值
@PrePersist
public void prePersist(Object object) {
this.init();
if (sysUserVo == null) {
return;
}
if (object != null) {
Field[] fields = object.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(LoadingField.class)) {
boolean isTime = field.getAnnotation(LoadingField.class).isTime();
fieldFill(field, object, isTime);
}
}
}
}
// 修改之前,为创建时间和创建人赋值
@PreUpdate
public void preUpdate(Object object) {
this.init();
if (sysUserVo == null) {
return;
}
if (object != null) {
Field[] fields = object.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(LoadingField.class) && field.getAnnotation(LoadingField.class).isModified()) {
boolean isTime = field.getAnnotation(LoadingField.class).isTime();
fieldFill(field, object, isTime);
}
}
}
}
private void fieldFill(Field field, Object object, boolean isTime) {
try {
if (isTime) {
field.setAccessible(true);
field.set(object, new Timestamp(new Date().getTime()));
} else {
String fieldName = fieldMap.containsKey(field.getName()) ? fieldMap.get(field.getName()) : field.getName();
Field fieldSource = sysUserVo.getClass().getDeclaredField(fieldName);
fieldSource.setAccessible(true);
field.setAccessible(true);
field.set(object, fieldSource.get(sysUserVo));
}
} catch (NoSuchFieldException | IllegalAccessException e) {
log.debug(e.getMessage());
}
}
private void init() {
// SysUserVO sysUserVO = new SysUserVO();
// sysUserVO.setSysUserId(1L);
// sysUserVO.setUserName("admin");
// this.sysUserVo = sysUserVO;
this.sysUserVo = parseToken();
fieldMap.put("creatorId", "sysUserId");
fieldMap.put("creatorName", "userName");
fieldMap.put("modifierId", "sysUserId");
fieldMap.put("modifierName", "userName");
}
// 解析 Token
private SysUserVO parseToken() {
HttpServletRequest request = RequestAndResponseContextHolder.request();
if (request != null) {
Cookie tokenCookie = CookieUtils.getCookie(TOKEN_KEY);
if (tokenCookie != null) {
return JwtUtils.parserCredential(tokenCookie.getValue(), SysUserVO.class);
}
}
return null;
}
}
public class BasicListener implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
public enum PublicField {
CREATOR_ID("creatorId", "sysUserId", false, false),
CREATOR_NAME("creatorName", "userName", false, false),
CREATE_TIME("createTime", "createTime", true, false),
MODIFIER_ID("modifierId", "sysUserId", false, true),
MODIFIER_NAME("modifierName", "userName", false, true),
MODIFY_TIME("modifyTime", "modifyTime", true, true)
;
private final String fieldName;
private final String mappingName;
private final boolean isTime;
private final boolean isModified;
PublicField(String fieldName, String mappingName, boolean isTime, boolean isModified) {
this.fieldName = fieldName;
this.mappingName = mappingName;
this.isTime = isTime;
this.isModified = isModified;
}
public String getFieldName() {
return fieldName;
}
public String getMappingName() {
return mappingName;
}
public boolean isTime() {
return isTime;
}
public boolean isModified() {
return isModified;
}
}
public class BasicListener implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
@EntityListeners(FieldListener.class)
public class example {
private Long creatorId;
private String creatorName;
private Timestamp createTime;
private Long modifierId;
private String modifierName;
private Timestamp modifyTime;
}
@Slf4j
public class FieldListener extends BasicListener {
private static final String TOKEN_KEY = "access_token";
private SysUserVO sysUserVo;
// 保存之前,为创建时间和创建人赋值
@PrePersist
public void prePersist(Object object) throws NoSuchFieldException {
this.sysUserVo = parseToken();
if (this.sysUserVo == null) {
return;
}
if (object != null) {
for (PublicField publicField : PublicField.values()) {
Field field = object.getClass().getDeclaredField(publicField.getFieldName());
fieldFill(field, publicField.getMappingName(), object, publicField.isTime());
}
}
}
// 修改之前,为创建时间和创建人赋值
@PreUpdate
public void preUpdate(Object object) throws NoSuchFieldException {
this.sysUserVo = parseToken();
if (sysUserVo == null) {
return;
}
if (object != null) {
for (PublicField publicField : PublicField.values()) {
if (publicField.isModified()) {
Field field = object.getClass().getDeclaredField(publicField.getFieldName());
fieldFill(field, publicField.getMappingName(), object, publicField.isTime());
}
}
}
}
private void fieldFill(Field field, String mappingName, Object object, boolean isTime) {
try {
if (isTime) {
field.setAccessible(true);
field.set(object, new Timestamp(new Date().getTime()));
} else {
Field fieldSource = sysUserVo.getClass().getDeclaredField(mappingName);
fieldSource.setAccessible(true);
field.setAccessible(true);
field.set(object, fieldSource.get(sysUserVo));
}
} catch (NoSuchFieldException | IllegalAccessException e) {
log.debug(e.getMessage());
}
}
private SysUserVO parseToken() {
HttpServletRequest request = RequestAndResponseContextHolder.request();
if (request != null) {
Cookie tokenCookie = CookieUtils.getCookie(TOKEN_KEY);
if (tokenCookie != null) {
return JwtUtils.parserCredential(tokenCookie.getValue(), SysUserVO.class);
}
}
return null;
}
}