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