干货文:SpringBoot 配置 AOP 打印请求参数和返回参数

**应用场景:**当我们想要查看前端传的数据是否正确,后端的返回值是否符合前端要求时,就可以打印请求参数和响应参数出来看,这样就有利于前后端对接;

**重点说明:**结合使用 fastjson2 对请求对象和返回对象实现序列化打印,再配置相关过滤器,用来过滤敏感信息和无效的过长信息;

**实际原理:**在前端请求后端的是后,AOP 会最先起作用。你可以使用 AOP 的 @Before 注解来打印请求参数,@Around 注解打印返回参数,@Pointcut 注解来定义切点。

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.filter.SimplePropertyPreFilter;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
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.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

@Aspect
@Component
public class LogAspect {

    private final static Logger LOG = LoggerFactory.getLogger(LogAspect.class);

    // 定义一个切点
    @Pointcut("execution(public * com.example.*.controller..*Controller.*(..))")
    public void controllerPointcut() {}

    @Before("controllerPointcut()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {

        // 开始打印请求日志
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        Signature signature = joinPoint.getSignature();
        String name = signature.getName();

        // 打印前端请求信息
        LOG.info("=== 开始 ===");
        LOG.info("请求地址: {} {}", request.getRequestURL().toString(), request.getMethod());
        LOG.info("类名方法: {}.{}", signature.getDeclaringTypeName(), name);
        LOG.info("远程地址: {}", request.getRemoteAddr());

        // 打印请求参数
        Object[] args = joinPoint.getArgs();

        Object[] arguments  = new Object[args.length];
        for (int i = 0; i < args.length; i++) {
            if (args[i] instanceof ServletRequest
                    || args[i] instanceof ServletResponse
                    || args[i] instanceof MultipartFile) {
                continue;
            }
            arguments[i] = args[i];
        }

        // 当某些字段太敏感,或者是太长时,就不显示
        String[] excludeProperties = {"password", "file"};
        SimplePropertyPreFilter filters = new SimplePropertyPreFilter();
        for (String str : excludeProperties){
            filters.getExcludes().add(str);
        }
        LOG.info("请求的参数: {}", JSON.toJSONString(arguments, filters));
    }

    @Around("controllerPointcut()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = proceedingJoinPoint.proceed();

        // 当某些字段太敏感,或者是太长时,就不显示
        String[] excludeProperties = {"password", "file"};
        SimplePropertyPreFilter filters = new SimplePropertyPreFilter();
        for (String str : excludeProperties){
            filters.getExcludes().add(str);
        }
        LOG.info("返回的结果: {}", JSON.toJSONString(result, filters));
        LOG.info("=== 结束时,总耗时:{} ms ===", System.currentTimeMillis() - startTime);
        return result;
    }

    /**
     * 使用 Nginx 进行反向代理,这个方法主要是用来获取远程 IP
     * @param request
     * @return
     */
    public String getRemoteIp(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}

你可能感兴趣的:(spring,boot,java,aop,fastjson2,filter,aspect,spring)