SpringBoot过滤器如何获取POST请求的JSON参数
⽬录
SpringBoot过滤器获取POST请求的JSON参数
想到了使⽤过滤器来实现这个功能
所以我们可以通过获取到输⼊流来获取body
从源码我们可以看到
我们创建⼀个类并继承这个包装类
有⼀点需要注意的
SpringBoot过滤器获取POST请求的JSON参数
项⽬中需要将每个请求的路径和请求参数以及响应结果,都记录在⽇志中,这样在出现问题时可以快速定位是哪⾥出现了问题。
想到了使⽤过滤器来实现这个功能
当请求来到过滤器时,会有⼀个Request参数,通过该参数就能获取到请求路径和请求参数,以及相关内容
parameterMap = ParameterMap();
String requestMethod = Method();
String remoteAddr = RemoteAddr();
int remotePort = RemotePort();
上⾯的getParameterMap(),只能够获取到GET请求的参数,如果是POST⽅法传的JSON那就没法获取到,那如何获取呢,POST的请求是在请求体body中,⽽POST请求中的body参数是已流形式存在的
所以我们可以通过获取到输⼊流来获取body
ServletInputStream inputStream = InputStream();
InputStreamReader reader = new InputStreamReader(inputStream,StandardCharsets.UTF_8);
BufferedReader bfReader = new BufferedReader(reader);
StringBuilder sb = new StringBuilder();
springboot和过滤器String line;
while ((line = adLine()) != null){
sb.append(line);
}
System.out.String());
通过上⾯的⽅法,我们确实能在过滤器中获取到POST的JSON参数了,但是按照上⾯的⽅法实现的过滤器,我们会发现,当请求经过过滤器来到Controller的时候,请求参数不见了
可以看到,过滤器确实拿到JSON参数,但是接着报了⼀个request body missing的异常,也就是请求来到Controller时,参数没有了,这是为啥呢?我们先去源码看看,Controller平时是怎么拿到请求参数的吧
根据DeBug,可以看到SpringBoot处理请求的最主要的两个⽅法是上图红框的doService和doDisparch⽅法,上⾯就是通过反射去获取参数名去匹配等
来到invokeForRequest⽅法,这⾥⾯的getMethodArgumentValues,就是SpringBoot获取请求参数的⼊
⼝,进⼊⼊⼝后
再经过上⾯的红框,就能看到SpringBoot获取POST请求JSON的参数的真⾯⽬了
从源码我们可以看到
SpringBoot也是通过获取request的输⼊流来获取参数,这样上⾯的疑问就能解开了,为什么经过过滤器来到Controller请求参数就没了,这是因为 InputStream read⽅法内部有⼀个,postion,标志当前流读取到的位置,每读取⼀次,位置就会移动⼀次,如果读到最后,ad⽅法会返回-1,标志已经读取完了,如果想再次读取,可以调⽤set⽅法,position就会移动到上次调⽤mark的
位置,mark默认是0,所以就能从头再读了。但是呢是否能reset⼜是由markSupported决定的,为true能reset,为false就不能reset,从源码可以看到,markSupported是为false的,⽽且⼀调⽤reset就是直接异常
所以这也就代表,InputStream只能被读取⼀次,后⾯就读取不到了。因此我们在过滤器的时候,已经将InputStream读取过了⼀次,当来到Controller,SpringBoot读取InputStream的时候⾃然是什么都读取不到了
既然InputStream只能读取⼀次,那我们可以把InputStream给保存下来,然后完整的传下去SpringBoot就可以读取到了,这⾥就需要⽤到HttpServletRequest的包装类HttpServletRequestWrapper了,该类可以⾃定义⼀些⽅法
我们创建⼀个类并继承这个包装类
public class RequestWrapper extends HttpServletRequestWrapper {
private final byte[] body;
public RequestWrapper(HttpServletRequest request) throws IOException {
super(request);
//保存⼀份InputStream,将其转换为字节数组
body = InputStream());
}
//转换成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 {
ad();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
}
}
通过保存⼀份流,就可实现在过滤器中能拿到JSON参数,同时Controller也不会丢失参数
有⼀点需要注意的
在过滤器放⾏的时候,放⾏的是包装类和⽽不是原来的Request
以上为个⼈经验,希望能给⼤家⼀个参考,也希望⼤家多多⽀持。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论