说明
最近有个项目需要增加日志记录功能,因为这个项目原来是基于spring开发的,在查阅了相关资料以后,我采用了spring aop的方式实现该需求,然后就有了本篇文章。
思路
我这边需求是这样的:要统计各个接口的调用次数,然后我想加上客户端ip、请求参数、返回结果等信息,而我的接口都是通过controller实现的,所以从原理上讲就是要通过aop拦截所有controller,实现日志记录。项目本身用到了swagger,每个接口都有ApiOperation注解,所以我的实现方式就变成了拦截ApiOperation注解,为什么要拦截ApiOperation,因为ApiOperation注解有对每个接口的描述信息,当然也是因为每个接口方法上都有ApiOperation注解,当然如果你愿意你也可以拦截RequestMapping,下面是我的aop实现:
package com.mytest.aop; import io.swagger.annotations.ApiOperation; import org.apache.shiro.SecurityUtils; import org.apache.shiro.subject.Subject; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method; import java.text.SimpleDateFormat; import java.util.Date; /** * @program: publicCoreServer * @description: aop 打印 接收参数日志 * @author: liu yan * @create: 2019-11-21 09:15 */ @Aspect @Component//定义一个切面 public class LogRecordAspect { private static final Logger logger = LoggerFactory.getLogger(LogRecordAspect.class); private static final String UTF_8 = "utf-8"; @Autowired private UpmsLogService upmsLogService; @Pointcut("@annotation(io.swagger.annotations.ApiOperation)") public void logPointCut() { } @Around("logPointCut()") public Object around(ProceedingJoinPoint point) throws Throwable { long beginTime = System.currentTimeMillis(); //执行方法 Object result = point.proceed(); //执行时长(毫秒) long time = System.currentTimeMillis() - beginTime; //保存日志 saveSysLog(point, beginTime, time, result); return result; } /** * 日志记录 * * @param joinPoint * @param beginTime 开始时间 * @param spendTime 用时 * @param result 返回结果 */ private void saveSysLog(ProceedingJoinPoint joinPoint,long beginTime, long spendTime, Object result) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); UpmsLog upmsLog = new UpmsLog(); upmsLog.setLogId(UUIDUtil.getUUID()); upmsLog.setAppId("wx"); ApiOperation annotation = method.getAnnotation(ApiOperation.class); if(annotation != null){ //注解上的描述 upmsLog.setDescription(annotation.value()); } //请求的参数 Object[] args = joinPoint.getArgs(); String params = JSON.toJSONString(args[0]); upmsLog.setParameter(params); // 返回结果 String resultJson = JSON.toJSONString(result); upmsLog.setResult(resultJson); //获取request HttpServletRequest request = HttpContextUtils.getHttpServletRequest(); //设置IP地址 upmsLog.setIp(IPUtils.getIpAddr(request)); // 请求路径 String requestUrl = request.getRequestURL().toString(); upmsLog.setUrl(requestUrl); String requestURI = request.getRequestURI(); upmsLog.setUri(requestURI); // 请求头 String agentString = request.getHeader("User-Agent"); upmsLog.setUserAgent(agentString); // 请求方式 String authType = request.getMethod(); upmsLog.setMethod(authType); //用户名 Subject subject = SecurityUtils.getSubject(); if (subject.isAuthenticated()) { Object userId = subject.getPrincipal(); upmsLog.setUsername(userId.toString()); upmsLog.setUserId(userId.toString()); } String path = request.getContextPath(); String baseURL = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; upmsLog.setBasePath(baseURL); // 开始时间 upmsLog.setStartTime(beginTime); // 用时 upmsLog.setSpendTime(spendTime); upmsLog.setCreatetime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); //保存系统日志 logger.info("日志信息:"+ upmsLog); upmsLogService.saveLog(upmsLog); } }
我的spring xml的配置如下:
<context:component-scan base-package="com.mytest.aop"> <context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect" /> </context:component-scan> <!-- 设置AOP为自动代理 --> <aop:aspectj-autoproxy proxy-target-class="true"/>
我的controller(部分)
@Api(value = "info", description = "相关控制器") @Controller @RequestMapping(value = "/test/getInfo") public class InfoController { @Autowired private InfoService infoService; @ApiOperation(value = "aop日志测试") @RequestMapping("/getInfo") @ResponseBody public AjaxJson getInfo(String datas) { JSONObject data = JSONObject.parseObject(datas); AjaxJson result = infoService.getInfo(data.toString()); return result; } }
其他的servic、entity等代码这里就不放了,有需求的小伙伴可以留言。