运维页面

This commit is contained in:
2026-08-21 00:49:38 +08:00
parent 0d82bd4c76
commit ec306f0a98
11 changed files with 464 additions and 190 deletions
@@ -6,6 +6,7 @@ import com.yunhai.bschclassmanage.entity.SyncLog;
import com.yunhai.bschclassmanage.model.vo.PageVO;
import com.yunhai.bschclassmanage.service.ISyncLogService;
import com.yunhai.bschclassmanage.utils.ReflectRetryUtil;
import com.yunhai.bschclassmanage.utils.SyncLogRetryContext;
import com.yunhai.platform.utils.exception.DException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
@@ -23,6 +24,7 @@ import javax.persistence.criteria.Predicate;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
@@ -104,6 +106,10 @@ public class SyncLogServiceImpl implements ISyncLogService {
if (StringUtils.isBlank(e.getClassMethod())) throw new DException("该日志缺少调用信息(classMethod),无法重试");
if (StringUtils.isBlank(e.getJsonData())) throw new DException("该日志缺少入参(jsonData),无法重试");
// 记录本次重试元数据(重试次数 +1、重试时间)
e.setRetryCount((e.getRetryCount() == null ? 0 : e.getRetryCount()) + 1);
e.setLastRetryTime(LocalDateTime.now());
try {
@SuppressWarnings("unchecked")
Map<String, Object> argMap = JSON.parseObject(e.getJsonData(), LinkedHashMap.class);
@@ -133,11 +139,26 @@ public class SyncLogServiceImpl implements ISyncLogService {
}
Method invokeMethod = ReflectRetryUtil.getInvokeMethod(resolved.bean, target);
return invokeMethod.invoke(resolved.bean, args);
SyncLogRetryContext.mark(); // 标记为重试,切面生成新日志时在同步类型名追加"(重试)"
Object result = invokeMethod.invoke(resolved.bean, args);
e.setLastRetryStatus(1); // 本次重试成功
return result;
} catch (DException de) {
e.setLastRetryStatus(0); // 本次重试失败
throw de;
} catch (InvocationTargetException | IllegalAccessException ex) {
e.setLastRetryStatus(0); // 本次重试失败
throw ReflectRetryUtil.rethrow(ex);
} catch (RuntimeException re) {
e.setLastRetryStatus(0); // 本次重试失败(入参转换 / 定位等)
throw re;
} finally {
SyncLogRetryContext.clear(); // 清除重试标记,避免线程池复用泄漏
try {
repository.save(e); // 同步落库重试元数据(次数 / 上次状态 / 时间)
} catch (Exception saveEx) {
log.error("重试元数据落库失败, id={}", e.getId(), saveEx);
}
}
}
}
@@ -7,6 +7,7 @@ import com.yunhai.bschclassmanage.model.vo.PageVO;
import com.yunhai.bschclassmanage.service.ISysOperationLogService;
import com.yunhai.bschclassmanage.utils.GzipUtil;
import com.yunhai.bschclassmanage.utils.ReflectRetryUtil;
import com.yunhai.bschclassmanage.utils.SyncLogRetryContext;
import com.yunhai.bschclassmanage.utils.UserContext;
import com.yunhai.platform.utils.exception.DException;
import lombok.extern.slf4j.Slf4j;
@@ -139,43 +140,63 @@ public class SysOperationLogServiceImpl implements ISysOperationLogService {
throw new DException("非 JSON 数组入参(如 GET query)无法可靠重放,请手动重试");
}
JSONArray arr;
try {
arr = JSONArray.parseArray(e.getRequestParams());
} catch (Exception ex) {
throw new DException("入参解析失败(requestParams),无法重试");
}
if (arr == null) throw new DException("入参解析失败(requestParams),无法重试");
ReflectRetryUtil.Resolved resolved = ReflectRetryUtil.resolveBeanAndMethod(
applicationContext, e.getClassMethod(), arr.size());
Method target = resolved.method;
Parameter[] params = target.getParameters();
Object[] args = new Object[params.length];
int jsonIdx = 0;
for (int i = 0; i < params.length; i++) {
if (ReflectRetryUtil.isSkippable(params[i].getType())) {
args[i] = null; // 容器注入参数,无法重建
} else {
Object raw = (jsonIdx < arr.size()) ? arr.get(jsonIdx++) : null;
args[i] = ReflectRetryUtil.convert(raw, params[i]);
}
}
// 记录本次重试元数据(重试次数 +1、重试时间)
e.setRetryCount((e.getRetryCount() == null ? 0 : e.getRetryCount()) + 1);
e.setLastRetryTime(LocalDateTime.now());
// 还原原操作人上下文,使重放触发的审计切面记录正确操作人;结束后恢复本次请求上下文
UserContext.UserInfo snapshot = UserContext.getCurrentUser();
try {
JSONArray arr;
try {
arr = JSONArray.parseArray(e.getRequestParams());
} catch (Exception ex) {
throw new DException("入参解析失败(requestParams),无法重试");
}
if (arr == null) throw new DException("入参解析失败(requestParams),无法重试");
ReflectRetryUtil.Resolved resolved = ReflectRetryUtil.resolveBeanAndMethod(
applicationContext, e.getClassMethod(), arr.size());
Method target = resolved.method;
Parameter[] params = target.getParameters();
Object[] args = new Object[params.length];
int jsonIdx = 0;
for (int i = 0; i < params.length; i++) {
if (ReflectRetryUtil.isSkippable(params[i].getType())) {
args[i] = null; // 容器注入参数,无法重建
} else {
Object raw = (jsonIdx < arr.size()) ? arr.get(jsonIdx++) : null;
args[i] = ReflectRetryUtil.convert(raw, params[i]);
}
}
UserContext.setUserId(e.getUserId());
UserContext.setUserName(e.getUserName());
UserContext.setSchId(e.getSchId());
UserContext.setIp(e.getRequestIp());
Method invokeMethod = ReflectRetryUtil.getInvokeMethod(resolved.bean, target);
return invokeMethod.invoke(resolved.bean, args);
SyncLogRetryContext.mark(); // 标记为重试,审计切面生成新日志时在操作类型追加"(重试)"
Object result = invokeMethod.invoke(resolved.bean, args);
e.setLastRetryStatus(1); // 本次重试成功
return result;
} catch (DException de) {
e.setLastRetryStatus(0); // 本次重试失败
throw de;
} catch (InvocationTargetException | IllegalAccessException ex) {
e.setLastRetryStatus(0); // 本次重试失败
throw ReflectRetryUtil.rethrow(ex);
} catch (RuntimeException re) {
e.setLastRetryStatus(0); // 本次重试失败(入参转换 / 定位等)
throw re;
} finally {
UserContext.setUserInfo(snapshot);
SyncLogRetryContext.clear(); // 清除重试标记,避免线程池复用泄漏
try {
repository.save(e); // 同步落库重试元数据(次数 / 上次状态 / 时间)
} catch (Exception saveEx) {
log.error("审计日志重试元数据落库失败, id={}", e.getId(), saveEx);
}
}
}
}