服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - SpringBoot过滤器如何获取POST请求的JSON参数

SpringBoot过滤器如何获取POST请求的JSON参数

2021-12-08 11:54Lpepsi Java教程

这篇文章主要介绍了SpringBoot过滤器如何获取POST请求的JSON参数操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

 

SpringBoot过滤器获取POST请求的JSON参数

项目中需要将每个请求的路径和请求参数以及响应结果,都记录在日志中,这样在出现问题时可以快速定位是哪里出现了问题。

 

想到了使用过滤器来实现这个功能

当请求来到过滤器时,会有一个Request参数,通过该参数就能获取到请求路径和请求参数,以及相关内容

parameterMap = httpRequest.getParameterMap();
String requestMethod = httpRequest.getMethod();
String remoteAddr = httpRequest.getRemoteAddr();
int remotePort = httpRequest.getRemotePort();

上面的getParameterMap(),只能够获取到GET请求的参数,如果是POST方法传的JSON那就没法获取到,那如何获取呢,POST的请求是在请求体body中,而POST请求中的body参数是已流形式存在的

 

所以我们可以通过获取到输入流来获取body

ServletInputStream inputStream = httpRequest.getInputStream();
InputStreamReader reader = new InputStreamReader(inputStream,StandardCharsets.UTF_8);
BufferedReader bfReader = new BufferedReader(reader);
StringBuilder sb = new StringBuilder();
String line;
while ((line = bfReader.readLine()) != null){
sb.append(line);
}
System.out.println(sb.toString());

通过上面的方法,我们确实能在过滤器中获取到POST的JSON参数了,但是按照上面的方法实现的过滤器,我们会发现,当请求经过过滤器来到Controller的时候,请求参数不见了

SpringBoot过滤器如何获取POST请求的JSON参数

可以看到,过滤器确实拿到JSON参数,但是接着报了一个request body missing的异常,也就是请求来到Controller时,参数没有了,这是为啥呢?我们先去源码看看,Controller平时是怎么拿到请求参数的吧

SpringBoot过滤器如何获取POST请求的JSON参数

根据DeBug,可以看到SpringBoot处理请求的最主要的两个方法是上图红框的doServicedoDisparch方法,上面就是通过反射去获取参数名去匹配等

SpringBoot过滤器如何获取POST请求的JSON参数

来到invokeForRequest方法,这里面的getMethodArgumentValues,就是SpringBoot获取请求参数的入口,进入入口后

SpringBoot过滤器如何获取POST请求的JSON参数

再经过上面的红框,就能看到SpringBoot获取POST请求JSON的参数的真面目了

SpringBoot过滤器如何获取POST请求的JSON参数

 

从源码我们可以看到

SpringBoot也是通过获取request的输入流来获取参数,这样上面的疑问就能解开了,为什么经过过滤器来到Controller请求参数就没了,这是因为 InputStream read方法内部有一个,postion,标志当前流读取到的位置,每读取一次,位置就会移动一次,如果读到最后,InputStream.read方法会返回-1,标志已经读取完了,如果想再次读取,可以调用inputstream.reset方法,position就会移动到上次调用mark的位置,mark默认是0,所以就能从头再读了。但是呢 是否能reset又是由markSupported决定的,为true能reset,为false就不能reset,从源码可以看到,markSupported是为false的,而且一调用reset就是直接异常

SpringBoot过滤器如何获取POST请求的JSON参数

所以这也就代表,InputStream只能被读取一次,后面就读取不到了。因此我们在过滤器的时候,已经将InputStream读取过了一次,当来到Controller,SpringBoot读取InputStream的时候自然是什么都读取不到了

SpringBoot过滤器如何获取POST请求的JSON参数

既然InputStream只能读取一次,那我们可以把InputStream给保存下来,然后完整的传下去SpringBoot就可以读取到了,这里就需要用到HttpServletRequest的包装类HttpServletRequestWrapper了,该类可以自定义一些方法

 

我们创建一个类并继承这个包装类

public class RequestWrapper extends HttpServletRequestWrapper {
    private final byte[] body;
    public RequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        //保存一份InputStream,将其转换为字节数组
        body = StreamUtils.copyToByteArray(request.getInputStream());
    }
	//转换成String
    public String getBodyString(){
        return new String(body,StandardCharsets.UTF_8);
    }
    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }
	//把保存好的InputStream,传下去
    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream bais = new ByteArrayInputStream(body);
        return new ServletInputStream() {
            @Override
            public int read() throws IOException {
                return bais.read();
            }
            @Override
            public boolean isFinished() {
                return false;
            }
            @Override
            public boolean isReady() {
                return false;
            }
            @Override
            public void setReadListener(ReadListener readListener) {
            }
        };
    }
}

通过保存一份流,就可实现在过滤器中能拿到JSON参数,同时Controller也不会丢失参数

SpringBoot过滤器如何获取POST请求的JSON参数

 

有一点需要注意的

在过滤器放行的时候,放行的是包装类和而不是原来的Request

SpringBoot过滤器如何获取POST请求的JSON参数

以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/qq_40866897/article/details/111404480

延伸 · 阅读

精彩推荐
  • Java教程java数据结构-堆实现优先队列

    java数据结构-堆实现优先队列

    通常都把队列比喻成排队买东西,大家都很守秩序,先排队的人就先买东西。但是优先队列有所不同,它不遵循先进先出的规则,而是根据队列中元素的优...

    RAIN 73462021-11-23
  • Java教程java实现图书管理系统

    java实现图书管理系统

    这篇文章主要为大家详细介绍了java实现图书管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    颜问儿6442021-08-31
  • Java教程springboot websocket简单入门示例

    springboot websocket简单入门示例

    这篇文章主要介绍了springboot websocket简单入门示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    王强劲5992021-05-25
  • Java教程java中final关键字使用示例详解

    java中final关键字使用示例详解

    Java中的final关键字非常重要,它可以应用于类、方法以及变量。这篇文章中带你看看什么是final关键字?将变量,方法和类声明为final代表了什么?使用fi...

    java教程网3462019-10-30
  • Java教程java实现线性表及其算法

    java实现线性表及其算法

    线性表是最简单和最常用的一种数据结构,它是有n个体数据元素(节点)组成的有限序列,这篇文章主要介绍了java实现线性表及其算法,小编觉得挺不错...

    博弈5532021-05-06
  • Java教程Spring基础篇之初识DI和AOP

    Spring基础篇之初识DI和AOP

    这篇文章主要为大家详细介绍了Spring基础篇之初识DI和AOP,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    陈本布衣4872021-03-13
  • Java教程centos下GitLab+Jenkins持续集成环境搭建(安装jenkins)

    centos下GitLab+Jenkins持续集成环境搭建(安装jenkins)

    这篇文章主要为大家详细介绍了centos下搭建GitLab+Jenkins持续集成环境,安装jenkins的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    睡着的糖葫芦11832021-04-20
  • Java教程Java生成随机数的2种示例方法代码

    Java生成随机数的2种示例方法代码

    在Java中,生成随机数有两种方法。1是使用Random类。2是使用Math类中的random方法。看下面的例子使用吧 ...

    java代码网5202019-10-21