<!-- markdown -->
SpringBoot项目,项目中早已整合了一套Spring AOP切面相关技术实现,该有的流程都有,常规操作就是给方法加上自定义注解就可以在被调用时,根据当前请求头获取到用户信息(token)、请求IP地址等信息,然后分两种情况写入数据库日志表:
- 1、正常请求日志,每次该方法被调用时都会被记录入库;
- 2、当抛出异常时,额外记录一条异常日志信息(与1同表);
上面文字提到的内容是系统架构中目前已经实现的一整套相关业务的具体实现。但是...
但是现在有个新的需求(当自定义的注解用在异步方法上时,如何在Spring AOP切面恰当的位置获取到请求头里token等信息),当我尝试将该现有的日志注解写在主线程中的“某个异步方法”时,切面日志类在写入数据库之前有个“获取请求头”信息的的操作理所当然的报错了。
这两天我没少查阅资料,为了存请求头信息,考虑过Redis、MQTT、MySQL在记录一条请求头的记录等等,都被我推翻了。目前我采用写死的方案:
- 1、我假设一个不存在的异步方法操作员的用户的信息,定义好这个用户信息Object的所有预设属性值。
- 2、请求方式既不是GET也不是POST,由于写入数据库日志表的时候这个字段是String,我直接预设“Async”。
- 3、还缺什么信息我全部都预设...
然后我将当前的日志切面类(LogAspect)抽离成父类(BaseLogAspect),再定义一个异常日志切面类(LogAsyncAspect),分别继承自父类(BaseLogAspect),其中LogAspect留空不写,完整继承父类;LogAsyncAspect则是部分继承,部分重写父类方法,这里我重写了获取用户请求头信息的那个方法,我不再通过String userStr = request.getHeader(AuthConstant.USER_TOKEN_HEADER); 获取,而是改成用我上面预设的用户信息,请求ip用localhost;(以上还在撸代码,执行结果暂时未知是否符合当前预期)
/**
* @apiNote 日志异步切面类<br>
* 部分继承 BaseLogAspect 抽象类,部分重写。
* @Since 2024年3月29日
* @AuThor TabKey9
* @version 0.0.1.240329
*/
@Slf4j
@Aspect
@Component
public class LogAsyncAspect extends BaseLogAspect {
@Override
protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) {
try {
// 虚拟一个异步线程专用账号信息
UserDto userDto = new UserDto();
userDto.setId(-1L);
userDto.setUsername("异步操作专员");
// MySQL 日志记录表实体对象
SysOperLogEntity operLog = new SysOperLogEntity();
// 操作状态
operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
// 请求的地址 【获取不到】
operLog.setOperIp("localhost");
// 请求url 【获取不到】
operLog.setOperUrl("/**");
// 操作人员
operLog.setOperName(userDto.getUsername());
if (e != null) {
operLog.setStatus(BusinessStatus.FAIL.ordinal());
operLog.setErrorMsg(e.getMessage());
}
// 设置方法名称
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
operLog.setMethod(className + "." + methodName + "()");
// 设置请求方式
operLog.setRequestMethod("Async");
// 处理设置注解上的参数 【调用父类方法】
getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult);
// 设置消耗时间 【TIME_THREADLOCAL在父类用protected修饰符定义】
operLog.setCostTime(System.currentTimeMillis() - TIME_THREADLOCAL.get());
operLog.setOperTime(new Date());
// 保存数据库 【sysOperLogService在父类用protected修饰符定义】
sysOperLogService.save(operLog);
} catch (Exception exp) {
// 记录本地异常日志
log.error("异常信息:{}", exp.getMessage());
exp.printStackTrace();
} finally {
//【TIME_THREADLOCAL在父类用protected修饰符定义】
TIME_THREADLOCAL.remove();
}
}
}
<u>请问:我的做法合理吗?或者有哪里考虑不周吗?以及还有其它解决方案嘛?</u>
|