# SpringBoot自定义实现日志记录
本文作者:程序员飞云
# 创建logs表
CREATE TABLE `logs` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键id',
`operateUserId` bigint NOT NULL COMMENT '操作者id',
`operateTime` varchar(255) DEFAULT NULL COMMENT '操作时间',
`className` varchar(255) DEFAULT NULL COMMENT '操作类名',
`methodName` varchar(255) DEFAULT NULL COMMENT '操作方法名',
`methodParams` varchar(255) DEFAULT NULL COMMENT '操作方法参数',
`returnValue` varchar(1024) DEFAULT NULL COMMENT '操作方法返回值',
`costTime` varchar(255) DEFAULT NULL COMMENT '操作耗时',
`ip` varchar(255) DEFAULT NULL COMMENT '用户ip',
`logType` varchar(255) DEFAULT NULL COMMENT '日志类型',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=35 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='操作日志'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 创建实体
package com.sky.pono.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import lombok.Data;
/**
* 操作日志
*
* @TableName logs
*/
@TableName(value = "logs")
@Data
public class Logs implements Serializable {
/**
* 主键id
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 操作者id
*/
private Long operateuserid;
/**
* 操作时间
*/
private String operatetime;
/**
* 操作类名
*/
private String classname;
/**
* 操作方法名
*/
private String methodname;
/**
* 操作方法参数
*/
private String methodparams;
/**
* 操作方法返回值
*/
private String returnvalue;
/**
* 操作耗时
*/
private String costtime;
private String ip;
private String logtype;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
}
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
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
# 注解Log
import com.sky.enumeration.OperationType;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定义注解
*/
@Retention(RetentionPolicy.RUNTIME)//运行时有效
@Target(ElementType.METHOD)//作用在方法上
public @interface Log {
//数据库操作类型
OperationType value();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 操作类型
package com.sky.enumeration;
/**
* 数据库操作类型
*/
public enum OperationType {
/**
* 更新操作
*/
UPDATE,
/**
* 插入操作
*/
INSERT,
SELECT,
DELETE,
UPLOAD,
LOGIN,
LOGOUT
}
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
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
# 获取Ip
package com.sky.utils;
import javax.servlet.http.HttpServletRequest;
/**
* IP工具类
*/
public class IpUtils {
public static String getIpAddr(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Forwarded-For");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Real-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
}
}
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
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
# 执行切面方法
package com.sky.utils;
import cn.hutool.core.thread.ThreadUtil;
import com.alibaba.fastjson.JSONObject;
import com.sky.annotation.Log;
import com.sky.constant.JwtClaimsConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import com.sky.pono.entity.Logs;
import com.sky.properties.JwtProperties;
import com.sky.service.impl.LogsServiceImpl;
import io.jsonwebtoken.Claims;
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.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Arrays;
@Aspect
@Component
@Slf4j
public class LogAsper {
@Autowired
private LogsServiceImpl logsService;
@Autowired
private HttpServletRequest request;
@Autowired
private JwtProperties jwtProperties;
@Around("@annotation(com.sky.annotation.Log)")//匹配加了Log注解的方法
public Object recordLog(ProceedingJoinPoint joinPoint) throws Throwable {
//方法开始前的操作
Logs logs = new Logs();
String token;
token = request.getHeader(jwtProperties.getAdminTokenName());
Object result = joinPoint.proceed();
try {
log.info("jwt校验:{}", token);
Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
Long userId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());
log.info("当前用户的id:{}", userId);
BaseContext.setCurrentId(userId);
// 1. 获取用户id
logs.setOperateuserid(userId);
// 2 设置操作时间
logs.setOperatetime(LocalDateTime.now().toString());
//获取操作类名
logs.setClassname(joinPoint.getTarget().getClass().getName());
//获取操作方法名
logs.setMethodname(joinPoint.getSignature().getName());
//获取操作方法参数
logs.setMethodparams(Arrays.toString(joinPoint.getArgs()));
//获取开始时间
long begin = System.currentTimeMillis();
//获取操作方法返回值
//String returnValue = JSONObject.toJSONString(result);
//logs.setReturnvalue(returnValue.toString());
//获取操作结束时间
long end = System.currentTimeMillis();
//获取操作耗时
logs.setCosttime(String.valueOf(end - begin));
logs.setIp(IpUtils.getIpAddr(request));
// 获取方法上的@Log注解
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
Log logAnnotation = method.getAnnotation(Log.class);
if (logAnnotation != null) {
OperationType operationType = logAnnotation.value();
// 设置操作类型到日志实体中
logs.setLogtype(operationType.toString());
}
// 异步保存
ThreadUtil.execAsync(() -> {
boolean save = logsService.save(logs);
if (!save) {
log.info("日志记录失败");
}
});
} catch (Exception ex) {
log.info("jwt校验失败:{}", token, ex);
}
return result;
}
}
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
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