SpringAOP .切面,是Spring得一大特性,使用目前是使用得面还很窄,用气对Controller层做日志管理,其实还可以做参数校验和RSA校验等一系列前置操作。
在所有Controller得每一个方法里面做请求日志记录,会让代码变得很臃肿和阅读得低效。
没有使用统一请求日志记录得时候,我记录Controller的日志十分痛苦:
@RestController
@RequestMapping("gua")
public class GuaController {
private Logger logger = LoggerFactory.getLogger(GuaController.class);
@GetMapping("str")
public ResponseData str() {
logger.info("Request 请求日志: 请求控制器,请求地址 ,请求方法,请求返回值。。。。。。还有很多需要记录的细节,为了追溯。。。");
return ResponseDataUtil.buildSuccess("Result String");
}
@GetMapping("data")
public ResponseData data() {
logger.info("Request 请求日志: 请求控制器,请求地址 ,请求方法,请求返回值。。。。。。还有很多需要记录的细节,为了追溯。。。");
return ResponseDataUtil.buildSuccess(new User());
}
@GetMapping("map")
public ResponseData map() {
logger.info("Request 请求日志: 请求控制器,请求地址 ,请求方法,请求返回值。。。。。。还有很多需要记录的细节,为了追溯。。。");
HashMap<String, Object> map = new HashMap<>(1);
map.put("Result", "Map");
return ResponseDataUtil.buildSuccess(map);
}
}
现在只有三个映射,要是有更多呢?全都进行CV编程吗?日志变得杂乱不堪,如果你说不需要记录,那么业务出现细微差错或者需要追溯源头这种情况出现,就会让自己变得束手无策。日志得记录,是为了辅助我们进行程序执行追溯得。但是日志记录得杂乱无章,让程序越来乱。
我是用AOP做日志记录,在执行映射方法之前进行数据纪记录,在执行完成以后进行返回数据记录,然后再统一输出。
下面是我得AOP代码,非常简单:
@Component
@Aspect
public class RequestLogAspect {
private final Logger logger = LoggerFactory.getLogger(RequestLogAspect.class);
/**
* 定义切点
*/
@Pointcut("execution(* com.dong.gua.web.controller..*(..))")
public void requestServer() {
}
@Around("requestServer()")
public Object doAround(ProceedingJoinPoint pjp) {
//记录请求开始执行时间:
long beginTime = System.currentTimeMillis();
//获取请求信息
ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = sra.getRequest();
//获取代理地址、请求地址、请求类名、方法名
String remoteAddress = IPUtils.getProxyIP(request);
String requestURI = request.getRequestURI();
String methodName = pjp.getSignature().getName();
String clazzName = pjp.getTarget().getClass().getSimpleName();
//获取请求参数:
MethodSignature ms = (MethodSignature) pjp.getSignature();
//获取请求参数类型
String[] parameterNames = ms.getParameterNames();
//获取请求参数值
Object[] parameterValues = pjp.getArgs();
StringBuilder sb = new StringBuilder();
//组合请求参数,进行日志打印
if (parameterNames != null && parameterNames.length > 0) {
for (int i = 0; i < parameterNames.length; i++) {
if (parameterNames[i].equals("bindingResult")) {
break;
}
if ((parameterValues[i] instanceof HttpServletRequest) || (parameterValues[i] instanceof HttpServletResponse)) {
sb.
append("[").
append(parameterNames[i]).append("=").append(parameterValues[i])
.append("]");
} else {
sb.
append("[").
append(parameterNames[i]).append("=")
.append(JSON.toJSONString(parameterValues[i], SerializerFeature.WriteDateUseDateFormat))
.append("]");
}
}
}
Object result = null;
try {
result = pjp.proceed();
} catch (Throwable throwable) {
//请求操纵失败
//记录错误日志
logger.error("(ง•̀_•́)ง (っ•̀ω•́)っ 切面处理请求错误! IP信息(ง•̀_•́)ง->: 【{}}】 " +
"URI信息(ง•̀_•́)ง->:【{}】 请求映射控制类(ง•̀_•́)ง->:【{}】 " +
"请求方法(ง•̀_•́)ง->:【{}】 请求参数列表(ง•̀_•́)ง->:【{}】", remoteAddress, requestURI, clazzName, methodName,
sb.toString());
throw throwable;
}
//请求操作成功
String resultJosnString = "";
if (result != null) {
if (result instanceof ResponseData) {
resultJosnString = JSON.toJSONString(result, SerializerFeature.WriteDateUseDateFormat);
} else {
resultJosnString = String.valueOf(result);
}
}
//记录请求完成执行时间:
long endTime = System.currentTimeMillis();
long usedTime = endTime - beginTime;
//记录日志
logger.info("请求操作成功! 请求耗时:【{}】 " +
"IP信息(◍'౪`◍)ノ゙->: 【{}}】 URI信息(◍'౪`◍)ノ゙->:【{}】 " +
"请求映射控制类(◍'౪`◍)ノ゙->:【{}】 请求方法(◍'౪`◍)ノ゙->:【{}】 " +
"请求参数列表(◍'౪`◍)ノ゙->:【{}】 返回值(◍'౪`◍)ノ゙->:【{}】", usedTime, remoteAddress, requestURI, clazzName,
methodName, sb.toString(), resultJosnString);
return result;
}
编写了AOP以后,Controller的代码是这样的:
@RestController
@RequestMapping("gua")
public class GuaController {
private Logger logger = LoggerFactory.getLogger(GuaController.class);
@GetMapping("str")
public ResponseData str() {
return ResponseDataUtil.buildSuccess("Result String");
}
@GetMapping("data")
public ResponseData data() {
return ResponseDataUtil.buildSuccess(new User());
}
@GetMapping("map")
public ResponseData map() {
HashMap<String, Object> map = new HashMap<>(1);
map.put("Result", "Map");
return ResponseDataUtil.buildSuccess(map);
}
}
干净、整洁、易读。
其请求日志是这样的:
请求操作成功! 请求耗时:【137】 IP信息(◍'౪`◍)ノ゙->: 【Client IP: 0:0:0:0:0:0:0:1, fromSource: request.getRemoteAddr}】 URI信息(◍'౪`◍)ノ゙->:【/gua/str】 请求映射控制类(◍'౪`◍)ノ゙->:【GuaController】 请求方法(◍'౪`◍)ノ゙->:【str】 请求参数列表(◍'౪`◍)ノ゙->:【】 返回值(◍'౪`◍)ノ゙->:【{"code":"0000","msg":"Result String"}】
感兴趣的小伙伴,快去试试吧!