ServletInputStream在拦截器或过滤器应用后重写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
ServletInputStream inputStream = super .getInputStream();
StringBuilder sb = new StringBuilder();
BufferedReader reader = null ;
try {
reader = new BufferedReader( new InputStreamReader(servletInputStream, Charset.forName( "UTF-8" )));
String line = "" ;
while ((line = reader.readLine()) != null ) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (servletInputStream != null ) {
try {
servletInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (reader != null ) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//使用ServletInputStream中数据的代码
byte [] bytes = sb.getBytes( "UTF-8" );
final ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
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() throws IOException {
return bais.read();
}
};
|
在拦截器种使用了request.getInputStream()或者getReader()
导致在controller中无法获取请求参数
问题描述
在拦截器种使用了request.getInputStream()或者getReader(),然后在controller接口种使用了@requestbody ,导致controller中无法获取入参,报错:HttpMessageNotReadableException: Required request body is missing:
原因分析
ServletRequest中getReader()和getInputStream()只能调用一次。而又由于@RequestBody注解获取输出参数的方式也是根据流的方式获取的。所以我们前面使用流获取后,后面的@RequestBody就获取不到对应的输入流了。
为什么取不到输入流了???因为流对应的是数据,数据放在内存中,有的是部分放在内存中。
read 一次标记一次当前位置(mark position),第二次read就从标记位置继续读(从内存中copy)数据。
所以这就是为什么读了一次第二次是空了。 怎么让它不为空呢?只要inputstream 中的pos 变成0就可以重写读取当前内存中的数据。
javaAPI中有一个方法public void reset() 这个方法就是可以重置pos为起始位置,但是不是所有的IO读取流都可以调用该方法!ServletInputStream是不能调用reset方法,这就导致了只能调用一次getInputStream()。
如何处理
重写HttpServletRequestWrapper把request保存下来,然后通过过滤器把保存下来的request再填充进去,这样就可以多次读取request了。
第一步:定义过滤器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@WebFilter (urlPatterns = "/*" , filterName = "channelFilter" )
public class ChannelFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
ServletRequest requestWrapper = null ;
if (servletRequest instanceof HttpServletRequest) {
requestWrapper = new RequestWrapper((HttpServletRequest) servletRequest);
}
if (requestWrapper == null ) {
filterChain.doFilter(servletRequest, servletResponse);
} else {
System.out.println( "进入了过滤器。。。。。" );
filterChain.doFilter(requestWrapper, servletResponse);
}
}
@Override
public void destroy() {
}
}
|
第二步:重写RequestWrapper类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
public class RequestWrapper extends HttpServletRequestWrapper {
private final String body;
public RequestWrapper(HttpServletRequest request) {
super (request);
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null ;
InputStream inputStream = null ;
try {
inputStream = request.getInputStream();
if (inputStream != null ) {
bufferedReader = new BufferedReader( new InputStreamReader(inputStream));
char [] charBuffer = new char [ 128 ];
int bytesRead = - 1 ;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0 ) {
stringBuilder.append(charBuffer, 0 , bytesRead);
}
} else {
stringBuilder.append( "" );
}
} catch (IOException ex) {
} finally {
if (inputStream != null ) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bufferedReader != null ) {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
body = stringBuilder.toString();
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
ServletInputStream servletInputStream = new ServletInputStream() {
@Override
public boolean isFinished() {
return false ;
}
@Override
public boolean isReady() {
return false ;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() throws IOException {
return byteArrayInputStream.read();
}
};
return servletInputStream;
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader( new InputStreamReader( this .getInputStream()));
}
public String getBody() {
return this .body;
}
}
|
第三步:在启动类中注册过滤器
以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/u011110968/article/details/80228567