刘光辉
7 小时以前 06f314545ac3514d7ce28939920866ae8188d31c
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
package jnpf;
 
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import jnpf.annotation.HandleLog;
import jnpf.base.LogSortEnum;
import jnpf.base.UserInfo;
import jnpf.base.entity.LogEntity;
import jnpf.config.ConfigValueUtil;
import jnpf.provider.system.LogProvider;
import jnpf.util.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
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 jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.multipart.MultipartFile;
 
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
 
/**
 * 日志记录
 *
 * @author JNPF开发平台组
 * @version V3.1.0
 * @copyright 引迈信息技术有限公司
 * @date 2021年3月13日 上午9:18
 */
 
@Slf4j
@Aspect
@Component
@Order(2)
public class RequestLogAspect {
 
    @Autowired
    private ConfigValueUtil configValueUtil;
    @DubboReference(injvm = false, async = true, url = "${jnpf.log-provider.url:dubbo://cx-system:20880}")
    private LogProvider logProvider;
 
 
    @Pointcut("within(jnpf.*.controller..*) || within(jnpf.controller..*) "
            + "|| within(jnpf.tmsController..*) || within(jnpf.limsController..*) "
            + "|| within(jnpf.dmsController..*) || within(jnpf.elnController..*)")
    public void requestLog() {
    }
 
    @Around("requestLog()")
    public Object doAroundService(ProceedingJoinPoint pjp) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object obj = pjp.proceed();
        if(ServletUtil.getRequest() == null){
            return obj;
        }
        long costTime = System.currentTimeMillis() - startTime;
        UserInfo userInfo = UserProvider.getUser();
        if(userInfo.getUserId() != null && (!configValueUtil.isMultiTenancy() || TenantHolder.getLocalTenantCache() != null)) {
            // 得到请求参数
            Object[] args = pjp.getArgs();
            Signature signature = pjp.getSignature();
            try {
                printLog(userInfo, costTime, obj, args, signature);
            } catch (Exception e) {
                log.error("记录请求日志发生错误:" + e.getMessage());
            }
            try {
                // 判断是否需要操作日志
                MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
                // 得到请求方法
                Method method = methodSignature.getMethod();
                HandleLog methodAnnotation = method.getAnnotation(HandleLog.class);
                if (methodAnnotation != null) {
                    String moduleName = methodAnnotation.moduleName();
                    String requestMethod = methodAnnotation.requestMethod();
                    handleLog(userInfo, costTime, obj, moduleName, requestMethod, args, signature);
                }
            } catch (Exception e) {
                log.error("记录操作日志发生错误:" + e.getMessage());
            }
        }
        return obj;
    }
 
    /**
     * 请求日志
     *
     * @param userInfo
     * @param costTime
     */
    private void printLog(UserInfo userInfo, long costTime, Object obj, Object[] args, Signature signature) {
        LogEntity entity = new LogEntity();
        entity.setId(RandomUtil.uuId());
        entity.setType(LogSortEnum.REQUEST.getCode());
        entity.setUserId(userInfo.getUserId());
        entity.setUserName(userInfo.getUserName() + "/" + userInfo.getUserAccount());
        //请求耗时
        entity.setRequestDuration((int) costTime);
        entity.setRequestUrl(ServletUtil.getRequest().getServletPath());
        entity.setRequestMethod(ServletUtil.getRequest().getMethod());
        String ipAddr = IpUtil.getIpAddr();
        entity.setIpAddress(ipAddr);
        entity.setIpAddressName(IpUtil.getIpCity(ipAddr));
        entity.setCreatorTime(new Date());
        UserAgent userAgent = UserAgentUtil.parse(ServletUtil.getUserAgent());
        if (userAgent != null) {
            entity.setPlatForm(userAgent.getPlatform().getName() + " " + userAgent.getOsVersion());
            entity.setBrowser(userAgent.getBrowser().getName() + " " + userAgent.getVersion());
        }
        String declaringTypeName = signature.getDeclaringTypeName();
        String name = signature.getName();
        entity.setRequestTarget(declaringTypeName + "." + name);
        entity.setJsons(safeResultText(obj));
        entity.setRequestParam(buildRequestParam(args));
        logProvider.writeLogRequest(entity);
    }
 
    /**
     * 添加操作日志
     *
     * @param userInfo      用户信息
     * @param costTime      操作耗时
     * @param obj           请求结果
     * @param moduleName    模块名称
     * @param requestMethod 请求方法
     * @param arg           请求参数
     */
    private void handleLog(UserInfo userInfo, long costTime, Object obj, String moduleName, String requestMethod, Object[] args, Signature signature) {
        LogEntity entity = new LogEntity();
        entity.setId(RandomUtil.uuId());
        entity.setType(LogSortEnum.OPERATE.getCode());
        entity.setUserId(userInfo.getUserId());
        entity.setUserName(userInfo.getUserName() + "/" + userInfo.getUserAccount());
        //请求耗时
        entity.setRequestDuration((int) costTime);
        entity.setRequestMethod(ServletUtil.getRequest().getMethod());
        entity.setRequestUrl(ServletUtil.getRequest().getServletPath());
        String ipAddr = IpUtil.getIpAddr();
        entity.setIpAddress(ipAddr);
        entity.setIpAddressName(IpUtil.getIpCity(ipAddr));
        entity.setCreatorTime(new Date());
        // 请求设备
        UserAgent userAgent = UserAgentUtil.parse(ServletUtil.getUserAgent());
        if (userAgent != null) {
            entity.setPlatForm(userAgent.getPlatform().getName() + " " + userAgent.getOsVersion());
            entity.setBrowser(userAgent.getBrowser().getName() + " " + userAgent.getVersion());
        }
        // 操作模块
        entity.setModuleName(moduleName);
        String declaringTypeName = signature.getDeclaringTypeName();
        String name = signature.getName();
        entity.setRequestTarget(declaringTypeName + "." + name);
        entity.setRequestParam(buildRequestParam(args));
        entity.setJsons(safeResultText(obj));
        logProvider.writeLogRequest(entity);
    }
 
    /**
     * 导出等接口已占用 response 输出流,不可再对 Request/Response 做 FastJSON 序列化。
     */
    private static String buildRequestParam(Object[] args) {
        if (args == null || args.length == 0) {
            return "";
        }
        StringBuilder multipart = new StringBuilder();
        List<Object> serializable = new ArrayList<>(args.length);
        for (Object o : args) {
            if (o == null) {
                continue;
            }
            if (o instanceof MultipartFile) {
                MultipartFile file = (MultipartFile) o;
                multipart.append("{\"originalFilename\":\"").append(file.getOriginalFilename()).append("\",");
                multipart.append("\"contentType\":\"").append(file.getContentType()).append("\",");
                multipart.append("\"name\":\"").append(file.getName()).append("\",");
                multipart.append("\"resource\":\"").append(file.getResource()).append("\",");
                multipart.append("\"size\":\"").append(file.getSize()).append("\"}");
                continue;
            }
            if (skipLogArg(o)) {
                continue;
            }
            serializable.add(o);
        }
        if (multipart.length() > 0) {
            return multipart.toString();
        }
        if (serializable.isEmpty()) {
            return "";
        }
        return JsonUtil.getObjectToString(serializable.toArray());
    }
 
    private static boolean skipLogArg(Object o) {
        return o instanceof ServletRequest
                || o instanceof ServletResponse
                || o instanceof BindingResult
                || o instanceof InputStream
                || o instanceof OutputStream;
    }
 
    /** void 导出等无返回体时避免把 response 之类写进日志 */
    private static String safeResultText(Object obj) {
        if (obj == null) {
            return "";
        }
        if (skipLogArg(obj)) {
            return "";
        }
        return String.valueOf(obj);
    }
}