[Solved] Java.lang.IllegalStateException: getReader() has already been called for this request

For the project, it is necessary to obtain the data in the request body in the interceptor for data verification, because the @ requestbody annotation is used in the self-defined controller, resulting in an error in the project. The content of the error is: Java. Lang. IllegalStateException: getreader() has already been called for this request

After consulting the data, it is found that the getReader and getinputstream in the request are obtained by stream. After reading once, they can’t be used again. The solution is:

Step 1: define a filter in which a self-defined request is passed in. The self-defined request inherits the wrapper class httpservletrequestwrapper and rewrites the getinputstream and getReader methods
the filter code is as follows:

package com.chinastock.filter;

import com.chinastock.util.CustomHttpServletRequestWrapper;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * @author zhoule
 * @description: handle request
 */
public class IMTAFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        ServletRequest requestWrapper = null;
        if(servletRequest instanceof HttpServletRequest) {
            requestWrapper = new CustomHttpServletRequestWrapper((HttpServletRequest) servletRequest);
        }
        if(requestWrapper == null) {
            filterChain.doFilter(servletRequest, servletResponse);
        } else {
            filterChain.doFilter(requestWrapper, servletResponse);
        }
    }
}

The custom request code is as follows:

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.StandardCharsets;

/**
 * @author zhoule
 * @description: Custom request wrapper for processing messages in the request body
 */
public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper {
    private byte[] body;

    public CustomHttpServletRequestWrapper(HttpServletRequest request) throws IOException
    {
        super(request);

        BufferedReader reader = request.getReader();
        try (StringWriter writer = new StringWriter()) {
            int read;
            char[] buf = new char[1024 * 8];
            while ((read = reader.read(buf)) != -1) {
                writer.write(buf, 0, read);
            }
            this.body = writer.getBuffer().toString().getBytes();
        }
    }

    public String getBody(){
        return new String(body, StandardCharsets.UTF_8);
    }

    @Override
    public ServletInputStream getInputStream() throws IOException
    {
        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body);
        return new ServletInputStream()
        {
            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {

            }

            public int read() throws IOException
            {
                return byteArrayInputStream.read();
            }
        };
    }

    @Override
    public BufferedReader getReader() throws IOException
    {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }
}

The second step is to write the interceptor of the project. Some codes of the interceptor are as follows:

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        CustomHttpServletRequestWrapper wrapper = (CustomHttpServletRequestWrapper) request;
        String body = wrapper.getBody();
        System.out.println(body);
        return true;
    }

Read More: