为热门项目 若依(ruoyi) 添加请求日志输出

效果大概如下:
在这里插入图片描述把每个请求的请求信息以及返回值信息输出控制台或者是日志文件中,在开发或者是测试环境中,方便定位错误。

首先,在ruoyi-admin 这个module的application.yml配置文件中添加下面的内容,方便控制输出哪些内容。

aspect:
  logger:
    spring-application-name: true
    request-url: true
    request-uri: true
    class-method: true
    request-method: true
    request-param: true
    request-desc: true
    request-ip: true
    request-user-agent: true
    content-type: true
    session: true
    cookie: true
  do-before: true
  do-after: true
  do-returning: true
  do-throwing: true

然后在com.ruoyi.core.config目录下新建AppLogConfig.java文件,内容如下。

@Component
@Aspect
public class AppLogConfig {
    
    

    @Autowired
    private Environment env;

    private Logger LOGGER = LoggerFactory.getLogger(AppLogConfig.class);
    private static boolean isDoBefore = false;
    private static boolean isDoAfter = false;
    private static boolean isDoReturning = false;
    private static boolean isDoThrowing = false;
    
    /**
     * 保证每个线程都有一个单独的实例
     */
    private ThreadLocal<Long> threadLocal = new ThreadLocal<>();

    private static String[] params;

    static {
    
    
        params = new String[]{
    
    "aspect.logger.spring-application-name", "aspect.logger.request-url", "aspect.logger.request-uri",
                "aspect.logger.request-desc", "aspect.logger.session", "aspect.logger.cookie",
                "aspect.logger.content-type", "aspect.logger.request-method", "aspect.logger.request-ip",
                "aspect.logger.request-user-agent", "aspect.logger.class-method", "aspect.logger.request-param"};
    }

    @PostConstruct
    public void init() {
    
    
        isDoBefore = env.getProperty("aspect.do-before") == null ? false : env.getProperty("aspect.do-before", Boolean.class);
        isDoAfter = env.getProperty("aspect.do-after") == null ? false : env.getProperty("aspect.do-after", Boolean.class);
        isDoReturning = env.getProperty("aspect.do-returning") == null ? false : env.getProperty("aspect.do-returning", Boolean.class);
        isDoThrowing = env.getProperty("aspect.do-throwing") == null ? false : env.getProperty("aspect.do-throwing", Boolean.class);
    }

    @Pointcut("execution(* com.ruoyi.web.controller..*(..))")
    public void pointcut() {
    
    
    }

    @Before("pointcut()")
    public void doBefore(JoinPoint joinPoint) throws Exception {
    
    
        if (!isDoBefore) {
    
    
            return;
        }
        threadLocal.set(System.currentTimeMillis());
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        StringBuilder stringBuilder = new StringBuilder()
                .append("\n=== doBefore ===\n");

        // 记录请求的内容
        this.logHandle(joinPoint, params, request, stringBuilder);
        LOGGER.info(stringBuilder.toString());

    }

    @After("pointcut()")
    public void doAfter(JoinPoint joinPoint) {
    
    
        if (!isDoAfter) {
    
    
            return;
        }
        LOGGER.info("\n==== doAfter ===\n" + joinPoint.toString());
    }

    /**
     * 返回值信息
     *
     * @param ret
     */
    @AfterReturning(returning = "ret", pointcut = "pointcut()")
    public void doAfterReturning(Object ret) {
    
    
        if (!isDoReturning) {
    
    
            return;
        }
        LOGGER.info("\n=== afterReturning ===\n" + ret);
        LOGGER.info("\n==== time cost" + ((System.currentTimeMillis() - threadLocal.get())) + "ms" + " ====\n");
    }

    @AfterThrowing(throwing = "ex",pointcut = "pointcut()")
    public void doThrowing(Throwable ex){
    
    
        if (!isDoThrowing) {
    
    
            return;
        }
        LOGGER.error("\n=== doThrowing ===\n" + ex);
    }

    /**
     * 获取注解中对方法的描述信息 用于Controller层注解
     *
     * @param joinPoint 切点
     * @return 方法描述
     * @throws Exception
     */
    private String getControllerMethodDescription(JoinPoint joinPoint) throws Exception {
    
    
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        String description = "";
        for (Method method : methods) {
    
    
            if (method.getName().equals(methodName)) {
    
    
                Class[] clazzs = method.getParameterTypes();
                if (clazzs.length == arguments.length) {
    
    
                    Object temp = method.getAnnotation(ApiOperation.class);
                    if (temp != null) {
    
    
                        description = method.getAnnotation(ApiOperation.class).value();
                    }
                    break;
                }
            }
        }
        return description;
    }

    /**
     * 处理请求参数输出
     *
     * @param joinPoint
     * @param requestParams
     * @param request
     * @param stringBuilder
     * @throws Exception
     */
    public void logHandle(JoinPoint joinPoint, String[] requestParams, HttpServletRequest request, StringBuilder stringBuilder) throws Exception {
    
    
        Map<String, Object> paramMap = new HashMap<>(16);
        String contentType = request.getContentType();
        paramMap.put("session", request.getSession());
        paramMap.put("cookie", request.getCookies());
        paramMap.put("spring-application-name", env.getProperty("spring.application.name"));
        paramMap.put("request-url", request.getRequestURL());
        paramMap.put("request-uri", request.getRequestURI());
        paramMap.put("request-desc", getControllerMethodDescription(joinPoint));
        paramMap.put("request-method", request.getMethod());
        paramMap.put("content-type", contentType);
        paramMap.put("class-method", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        paramMap.put("request-ip", request.getRemoteAddr());
        paramMap.put("request-user-agent", request.getHeader("User-Agent"));

        String reqParam = null;
        Object[] o = joinPoint.getArgs();
        if (contentType != null && contentType.contains("multipart/form-data")) {
    
    
            MultipartFile file = (MultipartFile) o[0];
            reqParam = file.getOriginalFilename();
        } else {
    
    
            if (o != null && o.length > 0) {
    
    
                reqParam = o[0].toString();
            }
        }
        paramMap.put("aspect.logger.request-param", reqParam);

        // 按配置输出
        for (String param : requestParams) {
    
    
            Boolean property = env.getProperty(param, Boolean.class);
            String p = param.replace("aspect.logger.", "");
            if (property != null && property && paramMap.containsKey(p)) {
    
    
                stringBuilder.append(p + ":" + paramMap.get(p) + "\n");
            }
        }
    }
}

主要使用到的是aop的相关知识,也比较简单,不做过多赘述。这里如果有多个profile的话,其实也可以根据多个环境做不同的配置,输出的参数也可以根据自己的需求做相关的取舍。

一般的,根据我自己的需求,配置一下几个参数做输出就行了
在这里插入图片描述
ruoyi-vue登陆也需要验证码,所以刷新登陆页有一个请求
在这里插入图片描述这些信息如果做测试的话,在swagger里面也可以看到,如果是运行时异常的话,在日志信息中查找方便很多。

猜你喜欢

转载自blog.csdn.net/qq_41885819/article/details/115007412