mirror of
http://git.pig4cloud.com/pig/pigx.git
synced 2026-11-08 12:39:05 +08:00
feat(pigx-common-audit): 重构审计模块,支持通过主键自动获取对象进行比对
This commit is contained in:
1 parent
836fc04a26
commit
1d9bfd866f
5 files changed
+141
-10
No files matched your search
+18
-2
@@ -6,10 +6,12 @@ import com.pig4cloud.pigx.common.audit.handle.DefaultAuditLogHandle;
|
||||
import com.pig4cloud.pigx.common.audit.handle.IAuditLogHandle;
|
||||
import com.pig4cloud.pigx.common.audit.handle.ICompareHandle;
|
||||
import com.pig4cloud.pigx.common.audit.handle.JavesCompareHandle;
|
||||
import com.pig4cloud.pigx.common.audit.support.AuditValueResolver;
|
||||
import com.pig4cloud.pigx.common.audit.support.SpelParser;
|
||||
import com.pig4cloud.pigx.common.core.util.KeyStrResolver;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
@@ -34,8 +36,22 @@ public class AuditAutoConfiguration {
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ICompareHandle compareHandle(Optional<IAuditLogHandle> auditNameHandleOptional) {
|
||||
return new JavesCompareHandle(auditNameHandleOptional);
|
||||
public ICompareHandle compareHandle(Optional<IAuditLogHandle> auditNameHandleOptional,
|
||||
AuditValueResolver auditValueResolver) {
|
||||
return new JavesCompareHandle(auditNameHandleOptional, auditValueResolver);
|
||||
}
|
||||
|
||||
/**
|
||||
* 审计值解析器。
|
||||
*
|
||||
* @param applicationContext Spring 上下文
|
||||
* @return AuditValueResolver
|
||||
* @since 6.0
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public AuditValueResolver auditValueResolver(ApplicationContext applicationContext) {
|
||||
return new AuditValueResolver(applicationContext);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+18
@@ -44,4 +44,22 @@ public @interface Audit {
|
||||
*/
|
||||
String newVal() default "";
|
||||
|
||||
/**
|
||||
* 主键表达式(SpEL)。配置后会通过 MyBatis-Plus Mapper selectById 查询切面执行前后的实体快照,
|
||||
* 解析结果必须实现 {@link java.io.Serializable}。
|
||||
*
|
||||
* @return 主键 SpEL 表达式
|
||||
* @since 6.0
|
||||
*/
|
||||
String id() default "";
|
||||
|
||||
/**
|
||||
* 显式指定 MyBatis-Plus Mapper 类型,必须是被 Spring 管理的 BaseMapper Bean。
|
||||
* 默认 {@code Void.class} 表示从当前 Service 的 {@code getBaseMapper()} 自动获取。
|
||||
*
|
||||
* @return Mapper 类型
|
||||
* @since 6.0
|
||||
*/
|
||||
Class<?> mapper() default Void.class;
|
||||
|
||||
}
|
||||
+4
-4
@@ -2,12 +2,11 @@ package com.pig4cloud.pigx.common.audit.aop;
|
||||
|
||||
import com.pig4cloud.pigx.common.audit.annotation.Audit;
|
||||
import com.pig4cloud.pigx.common.audit.handle.ICompareHandle;
|
||||
import com.pig4cloud.pigx.common.audit.support.SpelParser;
|
||||
import com.pig4cloud.pigx.common.audit.support.AuditValueResolver;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
@@ -22,11 +21,12 @@ public class AuditAspect {
|
||||
|
||||
private final ICompareHandle compareHandle;
|
||||
|
||||
private final AuditValueResolver auditValueResolver;
|
||||
|
||||
@Around("@annotation(audit)")
|
||||
public Object auditLog(ProceedingJoinPoint joinPoint, Audit audit) throws Throwable {
|
||||
// 获取变更之前的结果
|
||||
Object oldVal = SpelParser.parser(joinPoint,
|
||||
StringUtils.hasText(audit.oldVal()) ? audit.oldVal() : audit.spel());
|
||||
Object oldVal = auditValueResolver.resolveOldVal(joinPoint, audit);
|
||||
Object result = joinPoint.proceed();
|
||||
|
||||
compareHandle.compare(oldVal, joinPoint, audit);
|
||||
|
||||
+4
-4
@@ -1,12 +1,11 @@
|
||||
package com.pig4cloud.pigx.common.audit.handle;
|
||||
|
||||
import com.pig4cloud.pigx.common.audit.annotation.Audit;
|
||||
import com.pig4cloud.pigx.common.audit.support.AuditValueResolver;
|
||||
import com.pig4cloud.pigx.common.audit.support.DataAuditor;
|
||||
import com.pig4cloud.pigx.common.audit.support.SpelParser;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.javers.core.Changes;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -21,14 +20,15 @@ public class JavesCompareHandle implements ICompareHandle {
|
||||
|
||||
private final Optional<IAuditLogHandle> auditLogHandleOptional;
|
||||
|
||||
private final AuditValueResolver auditValueResolver;
|
||||
|
||||
/**
|
||||
* 比较两个对象是否变更,及其变更后如何审计
|
||||
* @param oldVal 原有值
|
||||
*/
|
||||
@Override
|
||||
public Changes compare(Object oldVal, ProceedingJoinPoint joinPoint, Audit audit) {
|
||||
Object newVal = SpelParser.parser(joinPoint,
|
||||
StringUtils.hasText(audit.newVal()) ? audit.newVal() : audit.spel());
|
||||
Object newVal = auditValueResolver.resolveNewVal(joinPoint, audit);
|
||||
Changes compare = DataAuditor.compare(oldVal, newVal);
|
||||
auditLogHandleOptional.ifPresent(handle -> handle.handle(audit, compare));
|
||||
return compare;
|
||||
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
package com.pig4cloud.pigx.common.audit.support;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.pig4cloud.pigx.common.audit.annotation.Audit;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 审计快照解析器。
|
||||
*
|
||||
* @author lengleng
|
||||
* @since 6.0
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class AuditValueResolver {
|
||||
|
||||
private final ApplicationContext applicationContext;
|
||||
|
||||
/**
|
||||
* 解析修改前快照。
|
||||
*
|
||||
* @param joinPoint 连接点
|
||||
* @param audit 审计注解
|
||||
* @return 修改前快照
|
||||
*/
|
||||
public Object resolveOldVal(ProceedingJoinPoint joinPoint, Audit audit) {
|
||||
if (StringUtils.hasText(audit.id())) {
|
||||
return selectById(joinPoint, audit);
|
||||
}
|
||||
return SpelParser.parser(joinPoint, StringUtils.hasText(audit.oldVal()) ? audit.oldVal() : audit.spel());
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析修改后快照。
|
||||
*
|
||||
* @param joinPoint 连接点
|
||||
* @param audit 审计注解
|
||||
* @return 修改后快照
|
||||
*/
|
||||
public Object resolveNewVal(ProceedingJoinPoint joinPoint, Audit audit) {
|
||||
if (StringUtils.hasText(audit.id())) {
|
||||
return selectById(joinPoint, audit);
|
||||
}
|
||||
return SpelParser.parser(joinPoint, StringUtils.hasText(audit.newVal()) ? audit.newVal() : audit.spel());
|
||||
}
|
||||
|
||||
private Object selectById(ProceedingJoinPoint joinPoint, Audit audit) {
|
||||
Object id = SpelParser.parser(joinPoint, audit.id());
|
||||
if (Objects.isNull(id)) {
|
||||
return null;
|
||||
}
|
||||
if (!(id instanceof Serializable serializableId)) {
|
||||
throw new IllegalArgumentException("@Audit id 表达式解析结果必须实现 Serializable");
|
||||
}
|
||||
return resolveMapper(joinPoint, audit).selectById(serializableId);
|
||||
}
|
||||
|
||||
private BaseMapper<?> resolveMapper(ProceedingJoinPoint joinPoint, Audit audit) {
|
||||
Object mapper;
|
||||
if (audit.mapper() == Void.class) {
|
||||
mapper = getBaseMapper(joinPoint);
|
||||
} else {
|
||||
try {
|
||||
mapper = applicationContext.getBean(audit.mapper());
|
||||
} catch (NoSuchBeanDefinitionException ex) {
|
||||
throw new IllegalStateException(
|
||||
"未找到 @Audit mapper Bean: " + audit.mapper().getName() + ",请确认其已注册到 MyBatis-Plus", ex);
|
||||
}
|
||||
}
|
||||
if (mapper instanceof BaseMapper<?> baseMapper) {
|
||||
return baseMapper;
|
||||
}
|
||||
throw new IllegalStateException("@Audit mapper 必须是 MyBatis-Plus BaseMapper 类型");
|
||||
}
|
||||
|
||||
private Object getBaseMapper(ProceedingJoinPoint joinPoint) {
|
||||
Object target = Objects.nonNull(joinPoint.getTarget()) ? joinPoint.getTarget() : joinPoint.getThis();
|
||||
if (Objects.isNull(target)) {
|
||||
throw new IllegalStateException("@Audit 未指定 mapper,且无法获取当前 Service 实例");
|
||||
}
|
||||
Method getBaseMapper = ReflectionUtils.findMethod(target.getClass(), "getBaseMapper");
|
||||
if (Objects.isNull(getBaseMapper)) {
|
||||
throw new IllegalStateException("@Audit 未指定 mapper,当前 Service 未提供 getBaseMapper()");
|
||||
}
|
||||
ReflectionUtils.makeAccessible(getBaseMapper);
|
||||
return ReflectionUtils.invokeMethod(getBaseMapper, target);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user