111 lines
4.2 KiB
Java
111 lines
4.2 KiB
Java
package com.yunhai.bschclassmanage.aspect;
|
|
|
|
import com.alibaba.fastjson.JSON;
|
|
import com.yunhai.bschclassmanage.annotation.SyncOpLog;
|
|
import com.yunhai.bschclassmanage.entity.SyncLog;
|
|
import com.yunhai.bschclassmanage.enums.SyncDataType;
|
|
import com.yunhai.bschclassmanage.service.ISyncLogService;
|
|
import com.yunhai.bschclassmanage.utils.OtherUtil;
|
|
import com.yunhai.bschclassmanage.utils.SensitiveDataUtil;
|
|
import com.yunhai.bschclassmanage.utils.SyncLogRetryContext;
|
|
import com.yunhai.bschclassmanage.utils.UserContext;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import org.aspectj.lang.ProceedingJoinPoint;
|
|
import org.aspectj.lang.annotation.Around;
|
|
import org.aspectj.lang.annotation.Aspect;
|
|
import org.aspectj.lang.reflect.MethodSignature;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.core.annotation.Order;
|
|
import org.springframework.stereotype.Component;
|
|
import org.springframework.util.StringUtils;
|
|
|
|
import java.util.LinkedHashMap;
|
|
import java.util.Map;
|
|
|
|
/**
|
|
* 同步调用日志切面。
|
|
* 拦截所有标注 @SyncLog 的方法(当前仅 SyncUserBaseService),
|
|
* 统一采集:枚举类型 / 大类(Sync-Send) / 类名.方法名 / 操作人 / 学校 / IP / 脱敏入参 / 异常,
|
|
* 并在 finally 中异步落库(不影响主流程、异常照常抛出)。
|
|
*/
|
|
@Slf4j
|
|
@Aspect
|
|
@Component
|
|
@Order(10)
|
|
public class SyncLogAspect {
|
|
|
|
private static final int MAX_ERROR_MSG = 2000;
|
|
|
|
@Autowired
|
|
private ISyncLogService syncLogService;
|
|
|
|
@Around("@annotation(syncLog)")
|
|
public Object around(ProceedingJoinPoint pjp,SyncOpLog syncLog) throws Throwable {
|
|
SyncDataType dataType = syncLog.value();
|
|
String classMethod = pjp.getTarget().getClass().getName() + "." + pjp.getSignature().getName();
|
|
String jsonData = buildJsonData(pjp);
|
|
|
|
SyncLog entity = new SyncLog();
|
|
// 枚举类型 key/name
|
|
entity.setSyncDataTypeKey(dataType.getKey());
|
|
String typeName = dataType.getName();
|
|
if (SyncLogRetryContext.isRetry()) {
|
|
// 重试重放时,在同步类型名上追加"(重试)"标记,便于与首次调用区分
|
|
typeName = (typeName == null ? "" : typeName) + "(重试)";
|
|
}
|
|
entity.setSyncDataTypeName(typeName);
|
|
// 大类:Send / Sync(由 key 前缀推导)
|
|
boolean isSend = dataType.getKey() != null && dataType.getKey().startsWith("Send");
|
|
entity.setSyncType(isSend ? "Send" : "Sync");
|
|
entity.setSyncTypeName(isSend ? "推送" : "同步");
|
|
|
|
entity.setClassMethod(classMethod);
|
|
entity.setUserId(UserContext.getUserId());
|
|
entity.setUserName(UserContext.getUserName());
|
|
entity.setSchId(UserContext.getSchId());
|
|
entity.setRequestIp(StringUtils.hasText(UserContext.getIp())
|
|
? UserContext.getIp() : OtherUtil.getClientIp());
|
|
entity.setJsonData(jsonData);
|
|
|
|
Object result;
|
|
try {
|
|
result = pjp.proceed();
|
|
} catch (Throwable t) {
|
|
String msg = t.getMessage();
|
|
if (msg == null || msg.trim().isEmpty()) {
|
|
msg = t.getClass().getName();
|
|
}
|
|
entity.setErrorMsg(truncate(msg, MAX_ERROR_MSG));
|
|
entity.setStatus(0);
|
|
syncLogService.saveAsync(entity);
|
|
throw t;
|
|
}
|
|
entity.setStatus(1);
|
|
syncLogService.saveAsync(entity);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* 将方法参数按"参数名->值"序列化为 JSON,并用 SensitiveDataUtil 脱敏 pwd/idCard/phone 等。
|
|
*/
|
|
private String buildJsonData(ProceedingJoinPoint pjp) {
|
|
try {
|
|
MethodSignature ms = (MethodSignature) pjp.getSignature();
|
|
String[] names = ms.getParameterNames();
|
|
Object[] args = pjp.getArgs();
|
|
if (names == null || args == null) return "";
|
|
Map<String, Object> map = new LinkedHashMap<>();
|
|
for (int i = 0; i < args.length && i < names.length; i++) {
|
|
map.put(names[i], args[i]);
|
|
}
|
|
return SensitiveDataUtil.mask(JSON.toJSONString(map));
|
|
} catch (Exception e) {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
private String truncate(String s, int max) {
|
|
return s != null && s.length() > max ? s.substring(0, max) : s;
|
|
}
|
|
}
|