好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

使用ServletInputStream在拦截器或过滤器中应用后重写

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

查看更多关于使用ServletInputStream在拦截器或过滤器中应用后重写的详细内容...

  阅读:16次