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);
|
}
|
}
|