feat: initial iShare project code
This commit is contained in:
38
pigx-common/pigx-common-audit/pom.xml
Normal file
38
pigx-common/pigx-common-audit/pom.xml
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pigx-common</artifactId>
|
||||
<version>5.2.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>pigx-common-audit</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<description>pigx 数据审计相关工具类</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- 数据对比实现 -->
|
||||
<dependency>
|
||||
<groupId>org.javers</groupId>
|
||||
<artifactId>javers-core</artifactId>
|
||||
</dependency>
|
||||
<!-- 切面依赖 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
<!-- 提供日志插入 API -->
|
||||
<dependency>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>as-upms-api</artifactId>
|
||||
</dependency>
|
||||
<!-- 获取上下文的操作用户 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.pig4cloud.pigx.common.audit;
|
||||
|
||||
import com.pig4cloud.pigx.admin.api.feign.RemoteAuditLogService;
|
||||
import com.pig4cloud.pigx.common.audit.aop.AuditAspect;
|
||||
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.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<IAuditLogHandle> auditNameHandleOptional) {
|
||||
return new JavesCompareHandle(auditNameHandleOptional);
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认的审计日志存储策略
|
||||
* @return DefaultAuditLogHandle
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public IAuditLogHandle auditLogHandle(RemoteAuditLogService logService, KeyStrResolver tenantKeyStrResolver) {
|
||||
return new DefaultAuditLogHandle(logService, tenantKeyStrResolver);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 "";
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
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<SysAuditLog> auditLogList = new ArrayList<>();
|
||||
for (Change change : changes) {
|
||||
ValueChange valueChange = (ValueChange) change;
|
||||
|
||||
SysAuditLog auditLog = new SysAuditLog();
|
||||
auditLog.setAuditName(audit.name());
|
||||
auditLog.setAuditField(valueChange.getPropertyName()); // 修改的字段名称
|
||||
|
||||
if (Objects.nonNull(valueChange.getLeft())) {
|
||||
auditLog.setBeforeVal(valueChange.getLeft().toString()); // 更改前的值
|
||||
}
|
||||
if (Objects.nonNull(valueChange.getRight())) {
|
||||
auditLog.setAfterVal(valueChange.getRight().toString()); // getRight
|
||||
}
|
||||
|
||||
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<SysAuditLog> auditLogList) {
|
||||
remoteLogService.saveLog(auditLogList, SecurityConstants.FROM_IN);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<SysAuditLog> auditLogList);
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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<IAuditLogHandle> 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
com.pig4cloud.pigx.common.audit.AuditAutoConfiguration
|
||||
Reference in New Issue
Block a user