IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring boot Aop 统一打印接口参数 -> 正文阅读

[Java知识库]Spring boot Aop 统一打印接口参数

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

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-aop</artifactId>     
</dependency>

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<String> headerNames = request.getHeaderNames();
        Map<String, String> 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<User> 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就可以快速的扩展了

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-11-22 12:12:16  更:2021-11-22 12:13:37 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:50:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码