springboot~为ES实体封装审计Auditing功能

审记功能在Jpa框架里出现的,主要针对实体的几个字段进行自动化的赋值,让业务人员可以把关注点放在业务上,对于公用的,有规则的字段,由系统帮我们去处理。

原理

通过spring aop功能实现对es仓库接口方法的拦截,然后在方法处理之前,为实体的这些公用字段赋值即可,我们使用了jpa里的一些注解,如@CreateBy,@CreateDate,@LatestModifyDate等等。

EsBaseEntity实体


@Data
public class EsBaseEntity {

    public static final String dateTimeFormat = "yyyy/MM/dd||yyyy-MM-dd" +
            "||yyyy-MM-dd HH:mm:ss||yyyy/MM/dd HH:mm:ss" +
            "||yyyy-MM-dd HH:mm:ss.SSS||yyyy/MM/dd HH:mm:ss.SSS" +
            "||yyyy-MM-dd'T'HH:mm:ss.SSS";
    /**
     * 创建时间.
     */
    @Field(type = FieldType.Date, format = DateFormat.custom, pattern = dateTimeFormat)
    @CreatedDate
    protected String createTime;
    /**
     * 创建人.
     */
    @Field(type = FieldType.Keyword)
    @CreatedBy
    protected String creator;
    /**
     * 更新时间.
     */
    @Field(type = FieldType.Date, format = DateFormat.custom, pattern = dateTimeFormat)
    @LastModifiedDate
    protected String updateTime;
    /**
     * 更新人.
     */
    @Field(type = FieldType.Keyword)
    @LastModifiedBy
    protected String updateUser;
    /**
     * 删除标记.
     */
    @Field(type = FieldType.Keyword)
    protected boolean delFlag;
    /**
     * 主键.
     */
    @Id
    private String id = String.valueOf(SnowFlakeUtil.getFlowIdInstance().nextId());

}

审记拦截器

@Component
@Aspect
public class AuditAspect {
    DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * 添加ES实体-切入点
     */
    @Pointcut("execution(* org.springframework.data.repository.CrudRepository.save(..))")
    public void save() {
    }

    /**
     * 更新ES实体-切入点
     */
    @Pointcut("execution(* org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate.update(..))")
    public void update() {
    }

    /**
     * 插入实体拦截器.
     *
     * @param joinPoint
     * @throws IllegalAccessException
     */
    @Before("save()")
    public void beforeSave(JoinPoint joinPoint) throws IllegalAccessException {
        System.out.println("插入拦截");

        if (joinPoint.getArgs().length > 0) {
            Object esBaseEntity = joinPoint.getArgs()[0];
            Field[] fields = ClassHelper.getAllFields(esBaseEntity.getClass());
            List<Field> fieldList = Arrays.stream(fields)
                    .filter(o -> o.getAnnotation(CreatedDate.class) != null
                            || o.getAnnotation(LastModifiedDate.class) != null)
                    .collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(fieldList)) {
                for (Field field : fieldList) {
                    field.setAccessible(true);//取消私有字段限制
                    if (field.get(esBaseEntity) == null) {
                        field.set(esBaseEntity, df.format(new Date()));
                    }
                }
            }
            List<Field> auditFieldList = Arrays.stream(fields)
                    .filter(o -> o.getAnnotation(CreatedBy.class) != null
                            || o.getAnnotation(LastModifiedBy.class) != null)
                    .collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(auditFieldList)) {
                for (Field field : auditFieldList) {
                    field.setAccessible(true);//取消私有字段限制
                    if (field.get(esBaseEntity) == null) {
                        EsAuditorAware esAuditorAware = SpringContextConfig.getBean(EsAuditorAware.class);
                        if (esAuditorAware != null) {
                            field.set(esBaseEntity, esAuditorAware.getCurrentAuditor().orElse(null));
                        }
                    }
                }
            }
        }

    }

    /**
     * 更新实体拦截器.
     *
     * @param joinPoint
     */
    @Before("update()")
    public void beforeUpdate(JoinPoint joinPoint) {
        System.out.println("更新拦截");
        if (joinPoint.getArgs().length == 1 && joinPoint.getArgs()[0] instanceof UpdateQuery) {
            UpdateQuery updateQuery = (UpdateQuery) joinPoint.getArgs()[0];
            Map source = updateQuery.getUpdateRequest().doc().sourceAsMap();
            Field[] fields = ClassHelper.getAllFields(updateQuery.getClazz());
            List<Field> fieldList = Arrays.stream(fields)
                    .filter(o -> o.getAnnotation(LastModifiedDate.class) != null)
                    .collect(Collectors.toList());
            for (Field field : fieldList) {
                if (!source.containsKey(field.getName())) {
                    source.put(field.getName(), df.format(new Date()));
                }
            }
            List<Field> auditFieldList = Arrays.stream(fields)
                    .filter(o -> o.getAnnotation(LastModifiedBy.class) != null)
                    .collect(Collectors.toList());
            for (Field field : auditFieldList) {
                if (!source.containsKey(field.getName())) {
                    EsAuditorAware esAuditorAware = SpringContextConfig.getBean(EsAuditorAware.class);
                    if (esAuditorAware != null) {
                        source.put(field.getName(), esAuditorAware.getCurrentAuditor().orElse(null));
                    }
                }
            }
            updateQuery.getUpdateRequest().doc().source(source);
        }
    }
}

对审记人使用Aware方式实现

/**
 * Es获取审核当前对象.
 *
 * @param <T>
 */
public interface EsAuditorAware<T> {
    Optional<T> getCurrentAuditor();
}
/**
 * 得到当前操作人信息.
 */
@Component
public class UserAuditorAware implements EsAuditorAware<String> {
    @Override
    public Optional<String> getCurrentAuditor() {
        return Optional.of("1");
    }
}

第三方组件开启审计功能

/**
 * 开启ES审计功能.
 * 主要对建立人、建立时间、更新人、更新时间赋值.
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AuditAspect.class, SpringContextConfig.class})
public @interface EnableEsAuditing {
}

posted @ 2020-08-05 21:36  张占岭  阅读(835)  评论(0编辑  收藏  举报