diff --git a/pigx-common/pigx-common-audit/pom.xml b/pigx-common/pigx-common-audit/pom.xml
new file mode 100644
index 000000000..27f258374
--- /dev/null
+++ b/pigx-common/pigx-common-audit/pom.xml
@@ -0,0 +1,38 @@
+
+
+ 4.0.0
+
+ com.pig4cloud
+ pigx-common
+ 5.0.0-SNAPSHOT
+
+
+ pigx-common-audit
+ jar
+
+ pigx 数据审计相关工具类
+
+
+
+
+ org.javers
+ javers-core
+
+
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
+
+
+ com.pig4cloud
+ pigx-upms-api
+
+
+
+ org.springframework.security
+ spring-security-core
+
+
+
diff --git a/pigx-common/pigx-common-audit/src/main/java/com/pig4cloud/pigx/common/audit/AuditAutoConfiguration.java b/pigx-common/pigx-common-audit/src/main/java/com/pig4cloud/pigx/common/audit/AuditAutoConfiguration.java
new file mode 100644
index 000000000..8d1e4f5db
--- /dev/null
+++ b/pigx-common/pigx-common-audit/src/main/java/com/pig4cloud/pigx/common/audit/AuditAutoConfiguration.java
@@ -0,0 +1,52 @@
+package com.pig4cloud.pigx.common.audit;
+
+import com.pig4cloud.pigx.admin.api.feign.RemoteAuditLogService;
+import com.pig4cloud.pigx.admin.api.feign.RemoteLogService;
+import com.pig4cloud.pigx.common.audit.aop.AuditAspect;
+import com.pig4cloud.pigx.common.audit.handle.DefaultAuditLogHandle;
+import com.pig4cloud.pigx.common.audit.handle.ICompareHandle;
+import com.pig4cloud.pigx.common.audit.handle.IAuditLogHandle;
+import com.pig4cloud.pigx.common.audit.handle.JavesCompareHandle;
+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.annotation.Bean;
+import org.springframework.context.annotation.Import;
+import org.springframework.scheduling.annotation.EnableAsync;
+
+import java.util.Optional;
+
+/**
+ * 审计自动配置类
+ *
+ * @author lengleng
+ * @date 2023/2/26
+ */
+@EnableAsync
+@AutoConfiguration
+@Import({ AuditAspect.class, SpelParser.class })
+public class AuditAutoConfiguration {
+
+ /**
+ * 默认注入 javers 的比较器实现
+ * @param auditNameHandleOptional 注入审计用户来源
+ * @return ICompareHandle
+ */
+ @Bean
+ @ConditionalOnMissingBean
+ public ICompareHandle compareHandle(Optional auditNameHandleOptional) {
+ return new JavesCompareHandle(auditNameHandleOptional);
+ }
+
+ /**
+ * 默认的审计日志存储策略
+ * @return DefaultAuditLogHandle
+ */
+ @Bean
+ @ConditionalOnMissingBean
+ public IAuditLogHandle auditLogHandle(RemoteAuditLogService logService, KeyStrResolver tenantKeyStrResolver) {
+ return new DefaultAuditLogHandle(logService, tenantKeyStrResolver);
+ }
+
+}
diff --git a/pigx-common/pigx-common-audit/src/main/java/com/pig4cloud/pigx/common/audit/annotation/Audit.java b/pigx-common/pigx-common-audit/src/main/java/com/pig4cloud/pigx/common/audit/annotation/Audit.java
new file mode 100644
index 000000000..be09a2c7b
--- /dev/null
+++ b/pigx-common/pigx-common-audit/src/main/java/com/pig4cloud/pigx/common/audit/annotation/Audit.java
@@ -0,0 +1,47 @@
+package com.pig4cloud.pigx.common.audit.annotation;
+
+import org.springframework.core.annotation.AliasFor;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author lengleng
+ *
+ * 记需要进行审计的方法
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Audit {
+
+ /**
+ * 此审计的名称
+ * @return 审计名称
+ */
+ String name();
+
+ @AliasFor("spel")
+ String value() default "";
+
+ /**
+ * 默认查询的表达式
+ * @return string
+ */
+ @AliasFor("value")
+ String spel() default "";
+
+ /**
+ * 查询原有结果的表达式,如果为空取 spel()
+ * @return string
+ */
+ String oldVal() default "";
+
+ /**
+ * 查询编辑后的表达式,如果为空取 spel()
+ * @return string
+ */
+ String newVal() default "";
+
+}
diff --git a/pigx-common/pigx-common-audit/src/main/java/com/pig4cloud/pigx/common/audit/aop/AuditAspect.java b/pigx-common/pigx-common-audit/src/main/java/com/pig4cloud/pigx/common/audit/aop/AuditAspect.java
new file mode 100644
index 000000000..e47b1f447
--- /dev/null
+++ b/pigx-common/pigx-common-audit/src/main/java/com/pig4cloud/pigx/common/audit/aop/AuditAspect.java
@@ -0,0 +1,36 @@
+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 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
+ * @date 2023/2/26
+ *
+ * 拦截被@Audit注解标记的方法,并记录前后变化值
+ */
+
+@Aspect
+@RequiredArgsConstructor
+public class AuditAspect {
+
+ private final ICompareHandle compareHandle;
+
+ @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 result = joinPoint.proceed();
+
+ compareHandle.compare(oldVal, joinPoint, audit);
+ return result;
+ }
+
+}
diff --git a/pigx-common/pigx-common-audit/src/main/java/com/pig4cloud/pigx/common/audit/handle/DefaultAuditLogHandle.java b/pigx-common/pigx-common-audit/src/main/java/com/pig4cloud/pigx/common/audit/handle/DefaultAuditLogHandle.java
new file mode 100644
index 000000000..730a9a311
--- /dev/null
+++ b/pigx-common/pigx-common-audit/src/main/java/com/pig4cloud/pigx/common/audit/handle/DefaultAuditLogHandle.java
@@ -0,0 +1,77 @@
+package com.pig4cloud.pigx.common.audit.handle;
+
+import com.pig4cloud.pigx.admin.api.entity.SysAuditLog;
+import com.pig4cloud.pigx.admin.api.feign.RemoteAuditLogService;
+import com.pig4cloud.pigx.common.audit.annotation.Audit;
+import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
+import com.pig4cloud.pigx.common.core.util.KeyStrResolver;
+import com.pig4cloud.pigx.common.core.util.SpringContextHolder;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.javers.core.Changes;
+import org.javers.core.diff.Change;
+import org.javers.core.diff.changetype.ValueChange;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * 默认的审计日志存储
+ *
+ * @author lengleng
+ * @date 2023/2/27
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class DefaultAuditLogHandle implements IAuditLogHandle {
+
+ private final RemoteAuditLogService remoteLogService;
+
+ private final KeyStrResolver tenantKeyStrResolver;
+
+ @Override
+ public void handle(Audit audit, Changes changes) {
+ // 如果变更项为空则不进行审计
+ if (changes.isEmpty()) {
+ return;
+ }
+
+ // 获取当前操作人
+ Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+ // 如果获取不到授权信息、或者没有身份信息的接口 直接跳过处理
+ if (Objects.isNull(authentication) || !authentication.isAuthenticated()) {
+ return;
+ }
+
+ List auditLogList = new ArrayList<>();
+ for (Change change : changes) {
+ ValueChange valueChange = (ValueChange) change;
+
+ SysAuditLog auditLog = new SysAuditLog();
+ auditLog.setAuditName(audit.name());
+ auditLog.setAuditField(valueChange.getPropertyName()); // 修改的字段名称
+ auditLog.setBeforeVal(valueChange.getLeft().toString()); // 更改前的值
+ auditLog.setAfterVal(valueChange.getRight().toString()); // 更改后的值
+ auditLog.setCreateBy(authentication.getName()); // 操作人
+ auditLog.setCreateTime(LocalDateTime.now()); // 操作时间
+ auditLog.setTenantId(Long.parseLong(tenantKeyStrResolver.key())); // 设置操作所属租户
+
+ auditLogList.add(auditLog);
+ }
+
+ // 异步保存日志,提升性能
+ IAuditLogHandle auditLogHandle = SpringContextHolder.getBean(IAuditLogHandle.class);
+ auditLogHandle.asyncSend(auditLogList);
+ }
+
+ @Async
+ public void asyncSend(List auditLogList) {
+ remoteLogService.saveLog(auditLogList, SecurityConstants.FROM_IN);
+ }
+
+}
diff --git a/pigx-common/pigx-common-audit/src/main/java/com/pig4cloud/pigx/common/audit/handle/IAuditLogHandle.java b/pigx-common/pigx-common-audit/src/main/java/com/pig4cloud/pigx/common/audit/handle/IAuditLogHandle.java
new file mode 100644
index 000000000..10790f474
--- /dev/null
+++ b/pigx-common/pigx-common-audit/src/main/java/com/pig4cloud/pigx/common/audit/handle/IAuditLogHandle.java
@@ -0,0 +1,21 @@
+package com.pig4cloud.pigx.common.audit.handle;
+
+import com.pig4cloud.pigx.admin.api.entity.SysAuditLog;
+import com.pig4cloud.pigx.common.audit.annotation.Audit;
+import org.javers.core.Changes;
+
+import java.util.List;
+
+/**
+ * @author lengleng
+ * @date 2023/2/26
+ *
+ * 审计日志处理器
+ */
+public interface IAuditLogHandle {
+
+ void handle(Audit audit, Changes changes);
+
+ void asyncSend(List auditLogList);
+
+}
diff --git a/pigx-common/pigx-common-audit/src/main/java/com/pig4cloud/pigx/common/audit/handle/ICompareHandle.java b/pigx-common/pigx-common-audit/src/main/java/com/pig4cloud/pigx/common/audit/handle/ICompareHandle.java
new file mode 100644
index 000000000..6d176841f
--- /dev/null
+++ b/pigx-common/pigx-common-audit/src/main/java/com/pig4cloud/pigx/common/audit/handle/ICompareHandle.java
@@ -0,0 +1,22 @@
+package com.pig4cloud.pigx.common.audit.handle;
+
+import com.pig4cloud.pigx.common.audit.annotation.Audit;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.javers.core.Changes;
+
+/**
+ * 比较器抽象类
+ *
+ * @author lengleng
+ * @date 2023/2/26
+ */
+public interface ICompareHandle {
+
+ /**
+ * 比较两个对象是否变更,及其变更后如何审计
+ * @param oldVal 原有值
+ * @param newVal 变更后值
+ */
+ Changes compare(Object oldVal, ProceedingJoinPoint joinPoint, Audit audit);
+
+}
diff --git a/pigx-common/pigx-common-audit/src/main/java/com/pig4cloud/pigx/common/audit/handle/JavesCompareHandle.java b/pigx-common/pigx-common-audit/src/main/java/com/pig4cloud/pigx/common/audit/handle/JavesCompareHandle.java
new file mode 100644
index 000000000..5b00280e1
--- /dev/null
+++ b/pigx-common/pigx-common-audit/src/main/java/com/pig4cloud/pigx/common/audit/handle/JavesCompareHandle.java
@@ -0,0 +1,37 @@
+package com.pig4cloud.pigx.common.audit.handle;
+
+import com.pig4cloud.pigx.common.audit.annotation.Audit;
+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;
+
+/**
+ * javers 比较实现
+ *
+ * @author lengleng
+ * @date 2023/2/26
+ */
+@RequiredArgsConstructor
+public class JavesCompareHandle implements ICompareHandle {
+
+ private final Optional auditLogHandleOptional;
+
+ /**
+ * 比较两个对象是否变更,及其变更后如何审计
+ * @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());
+ Changes compare = DataAuditor.compare(oldVal, newVal);
+ auditLogHandleOptional.ifPresent(handle -> handle.handle(audit, compare));
+ return compare;
+ }
+
+}
diff --git a/pigx-common/pigx-common-audit/src/main/java/com/pig4cloud/pigx/common/audit/support/DataAuditor.java b/pigx-common/pigx-common-audit/src/main/java/com/pig4cloud/pigx/common/audit/support/DataAuditor.java
new file mode 100644
index 000000000..294c99942
--- /dev/null
+++ b/pigx-common/pigx-common-audit/src/main/java/com/pig4cloud/pigx/common/audit/support/DataAuditor.java
@@ -0,0 +1,27 @@
+package com.pig4cloud.pigx.common.audit.support;
+
+import lombok.experimental.UtilityClass;
+import org.javers.core.Changes;
+import org.javers.core.Javers;
+import org.javers.core.JaversBuilder;
+import org.javers.core.diff.Diff;
+
+import static org.javers.core.diff.ListCompareAlgorithm.LEVENSHTEIN_DISTANCE;
+
+/**
+ * javers 审计工具
+ *
+ * @author lengleng
+ * @date 2023/2/26
+ */
+@UtilityClass
+public class DataAuditor {
+
+ private final Javers javers = JaversBuilder.javers().withListCompareAlgorithm(LEVENSHTEIN_DISTANCE).build();
+
+ public Changes compare(Object newObj, Object oldObj) {
+ Diff compare = javers.compare(newObj, oldObj);
+ return compare.getChanges();
+ }
+
+}
diff --git a/pigx-common/pigx-common-audit/src/main/java/com/pig4cloud/pigx/common/audit/support/SpelParser.java b/pigx-common/pigx-common-audit/src/main/java/com/pig4cloud/pigx/common/audit/support/SpelParser.java
new file mode 100644
index 000000000..88aaeb4a9
--- /dev/null
+++ b/pigx-common/pigx-common-audit/src/main/java/com/pig4cloud/pigx/common/audit/support/SpelParser.java
@@ -0,0 +1,39 @@
+package com.pig4cloud.pigx.common.audit.support;
+
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.expression.BeanFactoryResolver;
+import org.springframework.expression.spel.standard.SpelExpressionParser;
+import org.springframework.expression.spel.support.StandardEvaluationContext;
+
+/**
+ * 表达式处理器
+ *
+ * @author lengleng
+ * @date 2023/2/26
+ */
+public class SpelParser implements ApplicationContextAware {
+
+ private final static SpelExpressionParser parser = new SpelExpressionParser();
+
+ private static ApplicationContext applicationContext;
+
+ public static Object parser(ProceedingJoinPoint joinPoint, String spel) {
+ StandardEvaluationContext context = new StandardEvaluationContext();
+ context.setBeanResolver(new BeanFactoryResolver(applicationContext));
+ for (int i = 0; i < joinPoint.getArgs().length; i++) {
+ String paramName = ((MethodSignature) joinPoint.getSignature()).getParameterNames()[i];
+ context.setVariable(paramName, joinPoint.getArgs()[i]);
+ }
+ return parser.parseExpression(spel).getValue(context);
+ }
+
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ SpelParser.applicationContext = applicationContext;
+ }
+
+}
diff --git a/pigx-common/pigx-common-audit/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/pigx-common/pigx-common-audit/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 000000000..d295c990b
--- /dev/null
+++ b/pigx-common/pigx-common-audit/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+com.pig4cloud.pigx.common.audit.AuditAutoConfiguration