欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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等代码太简单,省略

相关标签: # 6 框架