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"}】
感兴趣的小伙伴,快去试试吧!
热门工具 换一换