案例总结
@Slf4j
@Aspect
@Component
public class ControllerAdvice {
// 对 controller 层的每个类的每个方法都进行增强
@Pointcut("execution(* com.qf.controller.*.*(..))")
public void appAccess() {
}
@Before("appAccess()")
public void doBefore(JoinPoint joinpoint) {
// 以下两行代码是为了获取当前请求的 HttpServletRequest 对象
ServletRequestAttributes requestAttributes =
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
// 获取被增强方法的参数
Object[] args = joinpoint.getArgs();
requestLog(request, args);
}
private void requestLog(HttpServletRequest request, Object[] args) {
//答应调用接口的 URL
log.info("REQ:request URL:=> {},time = {}", request.getRequestURL().toString(), DateUtil.now());
//打印请求方式
log.info("REQ:request METHOD:=> " + request.getMethod());
//打印被增强方法的参数
if (args != null && args.length > 0) {
log.info("REQ:requestId = {},args:=> {} ", AppRequestContextHolder.requestId(), JSON.toJSONString(args[args.length - 1]));
} else {
log.info("REQ:requestId = {},args:=> [] ", AppRequestContextHolder.requestId());
}
}
// 参数为被增强方法的返回值
@AfterReturning(returning = "ret", pointcut = "appAccess()")
public void doAfterReturning(Object ret) {
log.info("RSP_OK:requestId ={},time = {}", AppRequestContextHolder.requestId(), DateUtil.now());
}
@AfterThrowing(throwing = "ex", pointcut = "appAccess()")
public void doAfterThrowing(Throwable ex) {
if (ObjectUtils.isNotEmpty(ex)) {
log.info("RSP_THROWING:requestId = {},time= {},exception = {}", AppRequestContextHolder.requestId(), DateUtil.now(), ex.getMessage());
}
}
}
其中 AppRequestContextHolder 类是用来获取 requestId 的工具类。
public class AppRequestContextHolder {
/**
* 线程 全局 requestId
* 为每个线程分别创建并初始化一个变量,
* 从而保证每个线程看到的变量值都是独立且线程安全的。
*
* 当 tlRequestId 被调用时,就会进行初始化。
*/
private static ThreadLocal<String> tlRequestId=ThreadLocal.withInitial(()-> DateUtil.format(new Date(), DatePattern.PURE_DATETIME_MS_PATTERN)+ RandomUtil.randomNumbers(6));
public static String requestId(){
return tlRequestId.get();
}
public static void remove(){
tlRequestId.remove();
}
}
主要是对调用的接口的日志打印,方便排查问题,简化代码,不用再在 Controller 层的方法中进行
try catch 操作。