Implementing other solutions would possibly lead you to the following exception
java.lang.IllegalStateException: getInputStream() has already been called for this request
To read HttpServletRequest, following needs to be implemented.
Background:
To get the request body from the request, HttpServletRequest is provided with and InputStream class. The getReader() is what is usually used to stream the request. This function internally calls getInputStream() function, which returns us the stream for us to read the request. Now, note that its a stream, and can be opened only once. Hence, while reading this (i.e. implementing the solutions given in this thread) it usually throws "stream is already closed." exception. Now this happens because, the tomcat server has already opened and read the request once. Hence, we need to implement a wrapper here, which helps us to re-open an already read stream by keeping an instance of it. This wrapper again, cannot be used directly, instead, needs to be added at spring filter level, while the tomcat server is reading it.
Code:
Servlet Request Wrapper Class:
import lombok.extern.slf4j.Slf4j;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
@Slf4j
public class MyHttpServletRequestWrapper extends HttpServletRequestWrapper {
private final String body;public MyHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
InputStream 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) {
log.error("Error reading the request body...");
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
log.error("Error closing bufferedReader...");
}
}
}
body = stringBuilder.toString();
}
@Override
public ServletInputStream getInputStream () {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
ServletInputStream inputStream = 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();
}
};
return inputStream;
}
@Override
public BufferedReader getReader(){
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
}
Now we need to use the wrapper my implementing it in a filter, as shown below.
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Objects;
@Component
@Order(1)
@Slf4j
public class ServletFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
ServletRequest requestWrapper = null;
if (servletRequest instanceof HttpServletRequest) {
requestWrapper = new MyHttpServletRequestWrapper((HttpServletRequest) servletRequest);
}
if (Objects.isNull(requestWrapper)){
filterChain.doFilter(servletRequest, servletResponse);
} else {
filterChain.doFilter(requestWrapper, servletResponse);
}
}
}
Then, the suggested implementations can be used as follows to get the request body as following:
private String getRequestBody(HttpServletRequest request) {
try {
return request.getReader().lines().collect(Collectors.joining());
}catch (Exception e){
e.printStackTrace();
return "{}";
}
}
getRequestURL()
,getRequestURI()
be used to get the URI in the question. – Pappas