AOP实现日志管理
程序员文章站
2022-03-02 15:39:49
...
1 自定义日志注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* desc: 自定义日志注解,可用在类或者方法上
*
* @author gaorimao
* @since 2021-3-14
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogAnnotation {
String value() default "";
}
2 日志切面
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.grm.annotation.LogAnnotation;
import com.grm.pojo.Log;
import com.grm.response.LoginResponse;
import com.grm.service.LogService;
import com.grm.util.SnowFlake;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* desc: 日志切面类
*
* @author gaorimao
* @since 2021-3-14
*/
@Aspect
@Component
public class LogAspect {
private static Logger logger = LoggerFactory.getLogger(LogAspect.class);
@Autowired
private LogService logService;
@Autowired
private HttpServletRequest request;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private SnowFlake snowFlake;
@Pointcut("@annotation(com.grm.annotation.LogAnnotation)")
public void pointcut() {}
/**
* desc: 环绕
*
* @param joinPoint 切入点
*/
@After("pointcut()")
public void aroud(JoinPoint joinPoint) {
try {
handleLog(joinPoint);
} catch (Exception e) {
logger.error("[LogAspect] doBefore error = {}",e);
}
}
/**
* desc: 通过反射获取日志信息,存入数据库
*
* @param joinPoint 切点
* @throws Exception
*/
private void handleLog(final JoinPoint joinPoint) throws Exception{
// 获得注解
Method method = getMethod(joinPoint);
LogAnnotation logAnnotation = getAnnotationLog(method);
if (logAnnotation == null) {
return;
}
Log log = setLogInfo(joinPoint,method,logAnnotation);
logger.info("[log] log info : {}", JSON.toJSONString(log));
logService.insert(log);
}
/**
* desc: 初始化日志信息,存入数据库
*
* @return SysLog
*/
private Log setLogInfo(JoinPoint joinPoint, Method method, LogAnnotation logAnnotation) {
// 操作数据库日志表
Log log = new Log();
log.setId(snowFlake.nextId());
log.setAction(logAnnotation.value());
//触发人
LoginResponse loginUser = (LoginResponse)request.getSession().getAttribute("LOGIN_USER");
logger.info("[log] loginUserId : {}", loginUser.getUserId());
log.setUserId(loginUser.getUserId());
log.setRequestIp(request.getRemoteHost());
log.setRequestUrl(request.getRequestURI());
log.setRequestType(request.getMethod());
String classMethod = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
log.setRequestMethod(classMethod);
// 请求的方法参数值
Object[] args = joinPoint.getArgs();
// 请求的方法参数名称
LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
String[] paramNames = discoverer.getParameterNames(method);
if (args != null && paramNames != null) {
StringBuilder params = new StringBuilder();
try {
params = handleParams(params, args, Arrays.asList(paramNames));
} catch (JsonProcessingException e) {
logger.error("[LogAspect] setSysLogInfo handleParams error = {}",e);
}
log.setRequestParams(params.toString());
}
return log;
}
/**
*dsec: 是否存在注解,如果存在就获取
*/
private LogAnnotation getAnnotationLog(Method method) {
if (method != null) {
return method.getAnnotation(LogAnnotation.class);
}
return null;
}
/**
* desc: 通过反射或缺当前请求方法
*
* @param joinPoint 切点
* @return Method
*/
private Method getMethod(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method != null) {
return method;
}
return null;
}
/**
* desc: 处理请求参数
*
* @param params
* @param args
* @param paramNames
* @return
* @throws JsonProcessingException
*/
private StringBuilder handleParams(StringBuilder params, Object[] args, List paramNames) throws JsonProcessingException {
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof Map) {
Set set = ((Map) args[i]).keySet();
List list = new ArrayList();
List paramList = new ArrayList<>();
for (Object key : set) {
list.add(((Map) args[i]).get(key));
paramList.add(key);
}
return handleParams(params, list.toArray(), paramList);
} else {
if (args[i] instanceof Serializable) {
Class<?> aClass = args[i].getClass();
try {
aClass.getDeclaredMethod("toString", new Class[]{null});
// 如果不抛出NoSuchMethodException 异常则存在 toString 方法 ,安全的writeValueAsString ,否则 走 Object的 toString方法
params.append(" ").append(paramNames.get(i)).append(": ").append(objectMapper.writeValueAsString(args[i]));
} catch (NoSuchMethodException e) {
params.append(" ").append(paramNames.get(i)).append(": ").append(objectMapper.writeValueAsString(args[i].toString()));
}
} else if (args[i] instanceof MultipartFile) {
MultipartFile file = (MultipartFile) args[i];
params.append(" ").append(paramNames.get(i)).append(": ").append(file.getName());
} else {
params.append(" ").append(paramNames.get(i)).append(": ").append(args[i]);
}
}
}
return params;
}
}
3 Log实体类
import lombok.Data;
import lombok.ToString;
import java.util.Date;
@Data
@ToString
public class Log {
/**
* 主键id
*/
private Long id;
/**
* 动作
*/
private String action;
/**
* 触发人
*/
private Long userId;
/**
* 请求ip
*/
private String requestIp;
/**
* 请求URL
*/
private String requestUrl;
/**
* 请求方法
*/
private String requestMethod;
/**
* 请求类型
*/
private String requestType;
/**
* 请求参数
*/
private String requestParams;
/**
* 错误信息
*/
private String errorMessage;
/**
* 创建时间
*/
private Date createTime;
}
4 LogMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.grm.mapper.LogMapper">
<sql id="BASE_COLUMN_FEILD">
id,action,user_id,request_ip,request_url,request_method,request_type,request_params,error_message,create_time
</sql>
<!-- useGeneratedKeys="true" keyProperty="id" 这种写法可以在新增后回显id的值-->
<insert id="insert" parameterType="com.grm.pojo.Log" useGeneratedKeys="true" keyProperty="id">
insert into t_log
(id,action,user_id,request_ip,request_url,request_method,request_type,request_params,error_message,create_time)
values
(#{id},#{action},#{userId},#{requestIp},#{requestUrl},#{requestMethod},#{requestType},#{requestParams},#{errorMessage},now())
</insert>
</mapper>
5 登录接口加上@Log注解
@PostMapping("/login")
@LogAnnotation("登录成功!")
public Result login(@RequestBody LoginRequest loginRequest){
LoginResponse loginResponse = loginService.login(loginRequest);
return Result.success(loginResponse);
}
6 其余关于Log入库的mapper,service等代码太简单,省略
上一篇: Spring Boot AOP 日志管理
下一篇: AOP-实现日志管理