SpringBoot Controller 包打印日志:请求参数,返回值

v1

2021-04-16 11:10:22

pom依赖

1
2
3
4
5
6
7
8
9
10
11
<!--开启 AOP-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package com.decathlon.easypromo.config;

import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
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.springframework.stereotype.Component;

/**
* Controller 日志请求拦截。响应拦截。
*
* @author 陶攀峰
* @version 1.0
* @date 2021/4/13 下午2:27
*/
@Component
@Aspect
@Slf4j
public class ControllerLogAspect {

/**
* 切入点
*
* @author 陶攀峰
* @date 2021/4/13 下午2:59
*/
@Pointcut("execution(* com.decathlon.easypromo.controller.*.*(..))")
public void controllerLog() {
}

/**
* 环绕通知。进入日志打印。
*
* @param point 切入口信息
* @return 切入方法的返回结果
* @author 陶攀峰
* @date 2021/4/13 下午2:59
*/
@Around("controllerLog()")
public Object aroundAdvice(ProceedingJoinPoint point) throws Throwable {
Object[] args = point.getArgs();
String className = point.getTarget().getClass().getSimpleName();
String methodName = ((MethodSignature) point.getSignature()).getMethod().getName();

System.out.println("\n\n\n");
log.info("-----------------------------------------------------------------------");
log.info("-----------------------------------------------------------------------");
log.info("-----------------------------------------------------------------------");
log.info(">>>>>>>>>>>>>> Controller 前置拦截:请求方法:{}.{},请求参数:{}", className, methodName, JSONUtil.toJsonStr(args));
try {
Object returnValue = point.proceed(args);
log.info(">>>>>>>>>>>>>> Controller 后置拦截:请求方法:{}.{},返回结果:{}", className, methodName, JSONUtil.toJsonStr(returnValue));
return returnValue;
} catch (Exception e) {
//ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
//e.printStackTrace(new PrintStream(outputStream));
//log.info(">>>>>>>>>>>>>> Controller 异常拦截:请求方法:{}.{},异常信息:{}", className, methodName, outputStream.toString());
// 交给 GlobalExceptionHandler 处理。
throw e;
}
}
}

在这里插入图片描述

v2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package com.amoros.pumpkin.firebolt.main.config;

import com.alibaba.fastjson.JSON;
import com.amoros.firebolt.cloud.main.platform.ComReq;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.Callable;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* Controller 请求日志打印
* 2021-11-01 18:34:20
*/
@Aspect
@Component
@Slf4j
public class ControllerAspect {
public ControllerAspect() {
}

@Pointcut("@within(org.springframework.stereotype.Controller) && execution(public * *(..))")
private void controllerPointcut() {
}

@Pointcut("@within(org.springframework.web.bind.annotation.RestController) && execution(public * *(..))")
private void restControllerPointcut() {
}

@Before("restControllerPointcut() || controllerPointcut()")
public void callBeforexxx(JoinPoint joinPoint) {
}

@Around("restControllerPointcut() || controllerPointcut()")
public Object restControllerPointcut(ProceedingJoinPoint point) throws Throwable {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
long beginTime = System.currentTimeMillis();
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
ApiOperation annotation = method.getAnnotation(ApiOperation.class);
String description;
if (annotation != null) {
description = annotation.value();
} else {
description = "未定义 ApiOperation 接口";
}

String methodName = method.getName();
Object[] args = point.getArgs();
Parameter[] parameters = method.getParameters();

String logContent = this.writeLogInfo(parameters, args, request);

log.info("《《===== RequestURI:'{}',方法:'{}',方法 ApiOperation 描述:'{}' =====》》", request.getRequestURI(), methodName, description);
log.info("请求参数:{}", logContent);

Object object = point.proceed(args);
if (!method.getReturnType().equals(Callable.class)) {
long costMs = System.currentTimeMillis() - beginTime;
String resultLogs = JSON.toJSONString(object);

log.info("响应信息:{}", resultLogs);
log.info("》》===== 方法'{}'请求结束,耗时:{}ms =====《《", methodName, costMs);
} else {
request.setAttribute("startTime", beginTime);
request.setAttribute("isLogs", true);
}

return object;
}

@AfterThrowing(pointcut = "controllerPointcut()", throwing = "e")
public void controllerHandle(JoinPoint point, Exception e) {
log.info("cut exception:{}", e.getMessage());
}

private String writeLogInfo(Parameter[] paramsArgsName, Object[] paramsArgsValue, HttpServletRequest request) {
if (!ArrayUtils.isEmpty(paramsArgsName) && !ArrayUtils.isEmpty(paramsArgsValue)) {
StringBuffer buffer = new StringBuffer();

for (int i = 0; i < paramsArgsName.length; ++i) {
String name = paramsArgsName[i].getName();
Object value = paramsArgsValue[i];
if (!Objects.isNull(value)) {
if (this.isPrimite(value.getClass())) {
buffer.append(name).append(" = ");
}

if (!(value instanceof HttpServletRequest) && !(value instanceof HttpServletResponse) && !(value instanceof MultipartFile)) {
buffer.append(JSON.toJSON(value)).append(",");
if (value.getClass().equals(ComReq.class)) {
request.setAttribute("comReq", value);
}
}
}
}

return buffer.toString();
} else {
return "该方法没有参数";
}
}

private boolean isPrimite(Class<?> clazz) {
return clazz.equals(String.class) || clazz.equals(Integer.class) || clazz.equals(Byte.class) || clazz.equals(Long.class) || clazz.equals(Double.class) || clazz.equals(Float.class) || clazz.equals(Character.class) || clazz.equals(Short.class) || clazz.equals(BigDecimal.class) || clazz.equals(BigInteger.class) || clazz.equals(Boolean.class) || clazz.equals(Date.class) || clazz.isPrimitive();
}
}