准备工作
引入pom.xml依赖:
<!--引入Web模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--引入AOP依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
在完成了引入AOP依赖包后,一般来说并不需要去做其他配置。
实现一个简单请求处理:通过传入name参数和token参数,返回“hello xxx”的功能。
@ApiImplicitParams({
@ApiImplicitParam(name = "token", value = "token", required = true, dataType = "header"),
@ApiImplicitParam(name = "name", value = "名称", required = true, paramType = "query", dataType = "String")
})
@RequestMapping(value = "/hello", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
public String hello(HttpServletRequest request, @RequestParam(required = false) String name) {
return "Hello " + name;
}
实现Web层的日志切面
- 使用
@Aspect
注解将一个java类定义为切面类 - 使用
@Pointcut
定义一个切入点,可以是一个规则表达式,比如下例中某个package下的所有函数,也可以是一个注解等。 - 根据需要在切入点不同位置的切入内容
- 使用
@Before
在切入点开始处切入内容 - 使用
@After
在切入点结尾处切入内容 - 使用
@AfterReturning
在切入点return内容之后切入内容(可以用来对处理返回值做一些加工处理) - 使用
@Around
在切入点前后切入内容,并自己控制何时执行切入点自身的内容 - 使用
@AfterThrowing
用来处理当切入内容部分抛出异常之后的处理逻辑
- 使用
@Component // 将对象交由spring进行管理
@Aspect // 代表此类为一个切面类
public class ControllerAopInterceptor {
/**
* 初始化日志打印
*/
public static final Logger log = LoggerFactory.getLogger("visitLog");
@Pointcut("execution(public * com.xhchen.www.*.controller.*.*.*(..))")
public void privilege() {
}
@Around("privilege()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
String className = pjp.getTarget().getClass().getName(); // 获取类名
String methodName = pjp.getSignature().getName(); // 获取执行的方法名称
String[] parameterNamesArgs = ((MethodSignature) pjp.getSignature()).getParameterNames(); // 获取参数名称
Object result = null; // 定义返回参数
Object[] args = pjp.getArgs(); // 获取方法参数
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
// 请求的URL
String requestURL = request.getRequestURL().toString();
String ip = getIpAddr(request);
StringBuffer paramsBuf = new StringBuffer();
// 获取请求参数集合并进行遍历拼接
for (int i = 0; i < args.length; i++) {
if (paramsBuf.length() > 0) {
paramsBuf.append("|");
}
paramsBuf.append(parameterNamesArgs[i]).append(" = ").append(args[i]);
}
StringBuffer headerBuf = new StringBuffer();
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String key = (String) headerNames.nextElement();
String value = request.getHeader(key);
if (headerBuf.length() > 0) {
headerBuf.append("|");
}
headerBuf.append(key).append("=").append(value);
}
// 打印请求参数参数
long start = System.currentTimeMillis();// 记录开始时间
log.info("请求| ip:{} | 请求接口:{} | 请求类:{} | 方法 :{} | 参数:{} | 请求header:{}|请求时间 :{}", ip, requestURL, className, methodName, paramsBuf.toString(), headerBuf.toString(), start);
result = pjp.proceed();// 执行目标方法
// 获取执行完的时间 打印返回报文
log.info("返回| 请求接口:{}| 方法 :{} | 请求时间:{} | 处理时间:{} 毫秒 | 返回结果 :{}", requestURL, methodName, start, (System.currentTimeMillis() - start), result);
return result;
}
/**
* @Description: 获取ip
*/
public String getIpAddr(HttpServletRequest request) {
String ipAddress = null;
ipAddress = request.getHeader("x-forwarded-for");
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("WL-Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getRemoteAddr();
}
// 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length()
// = 15
if (ipAddress.indexOf(",") > 0) {
ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
}
}
// 或者这样也行,对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
return ipAddress;
}
}
通过运行程序并访问:http://localhost:8080/swagger-ui.html
,通过swagger访问接口可以获得下面的日志输出:
: 请求| ip:0:0:0:0:0:0:0:1 | 请求接口:http://localhost:8080/hello | 请求类:com.xhchen.www.log.controller.back.HelloController | 方法 :hello | 参数:request = org.apache.catalina.connector.RequestFacade@60de57ae|name = log | 请求header:host=localhost:8080|connection=keep-alive|content-length=20|accept=application/json;charset=UTF-8|origin=http://localhost:8080|x-requested-with=XMLHttpRequest|request-origion=SwaggerBootstrapUi|user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36|content-type=application/x-www-form-urlencoded;charset=UTF-8|referer=http://localhost:8080/swagger-ui.html|accept-encoding=gzip, deflate, br|accept-language=zh-CN,zh;q=0.9|请求时间 :1563272621249
: 返回| 请求接口:http://localhost:8080/hello| 方法 :hello | 请求时间:1563272621249 | 处理时间:12 毫秒 | 返回结果 :Hello log