package com.msxf.demo.aspect;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.msxf.demo.annotation.Log;
import lombok.Data;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
/**
* 日志记录
*
* @author: hzq
* @date: 2022/6/2
*/
@Slf4j
@Aspect
@Component
public class LogAspect {
@SneakyThrows
@Around("@annotation(aLog)")
public Object around(ProceedingJoinPoint joinPoint, Log aLog) {
// todo 获取操作人信息 客户端id
long start = System.currentTimeMillis();
HttpServletRequest request = getRequest();
SysLog sysLog = new SysLog();
sysLog.setTitle(aLog.value());
sysLog.setLogType("0");
sysLog.setRemoteAddress(ServletUtil.getClientIP(request));
sysLog.setRequestUri(URLUtil.getPath(request.getRequestURI()));
sysLog.setMethod(request.getMethod());
sysLog.setUserAgent(request.getHeader("user-agent"));
sysLog.setParams(extractParams(joinPoint, request));
Object proceed;
try {
proceed = joinPoint.proceed();
} catch (Exception e) {
sysLog.setLogType("9");
sysLog.setException(e.getMessage());
throw e;
} finally {
sysLog.setTime(System.currentTimeMillis() - start);
// todo 保存日志信息
log.info(sysLog.toString());
}
return proceed;
}
/**
* @return 请求
*/
private HttpServletRequest getRequest() {
return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
}
/**
* @param point 切入点
* @return 当前请求的参数
*/
private String extractParams(ProceedingJoinPoint point, HttpServletRequest request) {
JSONObject jsonObject = new JSONObject();
jsonObject.set("bodyParams", extractBodyParams(point));
jsonObject.set("urlParams", extractUrlParams(request));
return jsonObject.toString();
}
/**
* @return 请求url中的参数
*/
private String extractUrlParams(HttpServletRequest request) {
Map<String, String> params = new HashMap<>();
for (Map.Entry<String, String[]> entry : request.getParameterMap().entrySet()) {
params.put(entry.getKey(), entry.getValue()[0]);
}
if (MapUtil.isNotEmpty(params)) {
return (new JSONObject(params)).toString();
}
return null;
}
/**
* @param point 切入点
* @return 请求body中的参数
*/
private String extractBodyParams(ProceedingJoinPoint point) {
Object[] args;
if (null != (args = point.getArgs()) && args.length > 0) {
List<Object> params = Arrays.stream(args).filter(o -> !isFilterObject(o)).collect(Collectors.toList());
if (CollUtil.isNotEmpty(params)) {
return (new JSONArray(params)).toString();
}
}
return null;
}
/**
* @param o 参数
* @return true 需要过滤 false 不需要过滤
*/
@SuppressWarnings("rawtypes")
private boolean isFilterObject(final Object o) {
// 只针对泛型不是Object类型的处理
Class<?> clazz;
if ((clazz = o.getClass()).isArray()) {
return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
} else if (Collection.class.isAssignableFrom(clazz)) {
for (Object value : ((Collection) o)) {
return value instanceof MultipartFile;
}
} else if (Map.class.isAssignableFrom(clazz)) {
for (Object value : ((Map) o).entrySet()) {
return ((Map.Entry) value).getValue() instanceof MultipartFile;
}
}
return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse || o instanceof BindingResult;
}
@Data
public static class SysLog {
/**
* 日志类型
* (0-正常 9-错误)
*/
private String logType;
/**
* 日志标题
*/
private String title;
/**
* 创建者
*/
private String createBy;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 操作IP地址
*/
private String remoteAddress;
/**
* 用户代理
*/
private String userAgent;
/**
* 请求URI
*/
private String requestUri;
/**
* 操作方式
*/
private String method;
/**
* 操作提交的数据
*/
private String params;
/**
* 执行时间
*/
private Long time;
/**
* 异常信息
*/
private String exception;
/**
* 服务ID
*/
private String serviceId;
}
}
package com.msxf.demo.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 日志注解
*
* @author: hzq
* @date: 2022/6/2
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
/**
* @return 操作描述
*/
String value();
}