springboot~爲ES實體封裝審計Auditing功能

審記功能在Jpa框架裏出現的,主要針對實體的幾個字段進行自動化的賦值,讓業務人員能夠把關注點放在業務上,對於公用的,有規則的字段,由系統幫咱們去處理。spring

原理

經過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 {
}
相關文章
相關標籤/搜索