SpringAOP
.切面,是Spring得一大特性,使用目前是使用得面還很窄,用氣對Controller層做日志管理,其實還可以做參數(shù)校驗和RSA校驗等一系列前置操作。
在所有Controller得每一個方法里面做請求日志記錄,會讓代碼變得很臃腫和閱讀得低效。
沒有使用統(tǒng)一請求日志記錄得時候,我記錄Controller的日志十分痛苦:
@RestController @RequestMapping("gua") public class GuaController { private
Logger logger = LoggerFactory.getLogger(GuaController.class);
@GetMapping("str") public ResponseData str() { logger.info("Request 請求日志:
請求控制器,請求地址 ,請求方法,請求返回值。。。。。。還有很多需要記錄的細節(jié),為了追溯。。。"); return
ResponseDataUtil.buildSuccess("Result String"); } @GetMapping("data") public
ResponseData data() { logger.info("Request 請求日志: 請求控制器,請求地址
,請求方法,請求返回值。。。。。。還有很多需要記錄的細節(jié),為了追溯。。。"); return
ResponseDataUtil.buildSuccess(new User()); } @GetMapping("map") public
ResponseData map() { logger.info("Request 請求日志: 請求控制器,請求地址
,請求方法,請求返回值。。。。。。還有很多需要記錄的細節(jié),為了追溯。。。"); HashMap<String, Object> map = new
HashMap<>(1); map.put("Result", "Map"); return
ResponseDataUtil.buildSuccess(map); } }
現(xiàn)在只有三個映射,要是有更多呢?全都進行CV編程嗎?日志變得雜亂不堪,如果你說不需要記錄,那么業(yè)務出現(xiàn)細微差錯或者需要追溯源頭這種情況出現(xiàn),就會讓自己變得束手無策。日志得記錄,是為了輔助我們進行程序執(zhí)行追溯得。但是日志記錄得雜亂無章,讓程序越來亂。
我是用AOP做日志記錄,在執(zhí)行映射方法之前進行數(shù)據(jù)紀記錄,在執(zhí)行完成以后進行返回數(shù)據(jù)記錄,然后再統(tǒng)一輸出。
下面是我得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) { //記錄請求開始執(zhí)行時間: 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(); //獲取請求參數(shù):
MethodSignature ms = (MethodSignature) pjp.getSignature(); //獲取請求參數(shù)類型 String[]
parameterNames = ms.getParameterNames(); //獲取請求參數(shù)值 Object[] parameterValues =
pjp.getArgs(); StringBuilder sb = new StringBuilder(); //組合請求參數(shù),進行日志打印 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信息(???_??)?->:【{}】 請求映射控制類(???_??)?->:【{}】 " + "請求方法(???_??)?->:【{}】
請求參數(shù)列表(???_??)?->:【{}】", 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); } } //記錄請求完成執(zhí)行時間: long endTime =
System.currentTimeMillis(); long usedTime = endTime - beginTime; //記錄日志
logger.info("請求操作成功! 請求耗時:【{}】 " + "IP信息(?'?`?)??->: 【{}}】
URI信息(?'?`?)??->:【{}】 " + "請求映射控制類(?'?`?)??->:【{}】 請求方法(?'?`?)??->:【{}】 " +
"請求參數(shù)列表(?'?`?)??->:【{}】 返回值(?'?`?)??->:【{}】", 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】 請求參數(shù)列表(?'?`?)??->:【】
返回值(?'?`?)??->:【{"code":"0000","msg":"Result String"}】
感興趣的小伙伴,快去試試吧!
熱門工具 換一換