栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring boot Aop 统一打印接口参数

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring boot Aop 统一打印接口参数

1.Aop maven 仓库路径,这里使用的spring boot 是2.4.5所有aop对应的版本是也是2.4.5


   org.springframework.boot
   spring-boot-starter-aop     

2.编写Aop切入类指向接口所在的类。

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.poi.util.IOUtils;
import org.aspectj.lang.JoinPoint;
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.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

@Aspect
@Component
public class RequestAspect {

    private final Logger logger = LoggerFactory.getLogger(RequestAspect.class);

    //切入点描述 这个是controller包的切入点
    @Pointcut("execution(public * com.dh.test.controller..*.*(..))")
    public void controllerLog() {
    }


    //在切入点的方法run之前要干的
    @Before("controllerLog()")
    public void logBeforeController(JoinPoint joinPoint) throws IOException {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();

        logger.info("请求的URL : " + request.getRequestURL().toString());
        Enumeration headerNames = request.getHeaderNames();
        Map map = new HashMap<>();
        if (headerNames.hasMoreElements()) {
            String headName = headerNames.nextElement();
            map.put(headName, request.getHeader(headName));
        }

        logger.info("获取到头部信息为:" + map);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        IOUtils.copy(request.getInputStream(), outputStream);
        logger.info("请求的body参数为:" + new String(outputStream.toByteArray()));
    }
}

3.编写一个controller,UserVo创建一个接受参数

@RestController
public class TestController {

    @RequestMapping("test.get")
    public List getUser(@RequestBody UserVo userVo) {
        return new ArrayList<>();
    }
}
public class UserVo {
//测试 可以什么都不放
}

4.启动项目使用postman测试接口,但是报错了。java.io.IOException: Stream closed,这里报错是因为sevlert里面的body是流为inputStream读一次就结束了。ResponseBody是读一次,自定义的aop再通过sevlert去读的时候就已经关闭了无法读取。

5.解决不能重复读的问题,需要重写servlet方法的getInputStream和getReader方法因为在后面使用的时候不知道具体使用那个防止出错两个都重写。

import org.apache.poi.util.IOUtils;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;

public class RequestWarp extends HttpServletRequestWrapper {
    // 定义局部变量保存流,每次读取都没有问题
    private byte[] body;
    private final HttpServletRequest request;


    public RequestWarp(HttpServletRequest request) {
        super(request);
        this.request = request;
        // 创建的时候 就把值设置好
        this.getInputStream();
    }


    @Override
    public ServletInputStream getInputStream() {
        // 判断 防止重复执行
        if (null == this.body) {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            try {
                IOUtils.copy(request.getInputStream(), outputStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
            this.body = outputStream.toByteArray();
        }
        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body);
        return new ServletInputStream() {

            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {

            }

            @Override
            public int read() {
                return byteArrayInputStream.read();
            }
        };
    }

    
    @Override
    public BufferedReader getReader() {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }


}

6.重写之后就是使他生效,需要借助过滤取将重写之后的方法生效。

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@WebFilter(urlPatterns = "/*")
public class RequestFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        RequestWarp requestWarp = new RequestWarp(request);
        // 这里一定是要用 修改后request 不然还是使用原始的request 无法获取两次
        filterChain.doFilter(requestWarp, servletResponse);
    }
}

7.最后不要忘记了Spring boot启动类加上过滤器的扫描,不然不会生效。

@ServletComponentScan(basePackages = "com.dh.test")

8.再次用postman请求,请求正常,然后看到后台日志也是正常打印了。

 

9.到此已经能aop能正常切入controller里面了,可能在想用过滤器为啥用这个,只是针对当前的使用是用过滤器就足够了。但是深入获取当前方法名,参数什么的在这个基础上只需要通过aop JoinPoint就可以快速的扩展了

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/581870.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号