字段自动填充功能( JPA )

字段自动填充功能( JPA )


0、前言

​  最近,项目需要实现一个字段自动填充功能,整体需求是这样子:在每次实体类进行插入、修改操作时,给公共字段自动赋值,公共字段有创建人Id、创建人名称、修改人Id、修改人名称、创建时间、修改时间,其中创建人Id、创建人名称、修改人Id、修改人名称从 Token 中解析获取。

​  最开始我的思路的是这样子的:写一个自定义注解,给需要自动注入的字段加上这个注解,再写一个 AOP 类,在每个实体即将进行插入、修改操作时切入,再利用反射完成字段的赋值。

​  由于项目的持久化框架是 JPA,我便去查阅相关资料,最终找到 JPA 进行持久化操作的生命周期注解(@PrePersist 保存前、@PreUpdate 修改前,相当于 JPA 为我们提供了一个 AOP 操作),再结合自定义注解和反射最终实现字段自动填充功能。

​  后面,由于项目不想在实体类上额外多使用一个注解,改成使用枚举类和反射实现字段自动填充功能。



1、自定义注解 + 反射

1.1、注解

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface LoadingField {

    boolean isTime() default false;

    boolean isModified() default false;
}

1.2、实体类

@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;
}

1.3、监听器

@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;
    }
}


2、枚举类 + 反射

2.1、枚举类

 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;
    }
}

2.2、实体类

@EntityListeners(FieldListener.class)
public class example {
    
    private Long creatorId;

    private String creatorName;
    
    private Timestamp createTime;
    
    private Long modifierId;
    
    private String modifierName; 
    
    private Timestamp modifyTime;
}

2.3、监听器

@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;
    }
}


3、效果

插入时:
在这里插入图片描述

修改时:
在这里插入图片描述

你可能感兴趣的:(工作经验,java,jpa,aop,自定义注解,反射)