我想从请求和响应中获取XML数据,并将其用于Rest控制器。我尝试了这个:
@RestController() public class HomeController { @PostMapping(value = "/v1") public Response handleMessage(@RequestBody Transaction transaction, HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest request, HttpServletResponse response System.out.println("!!!!!!! InputStream"); System.out.println(request.getInputStream()); System.out.println(response.getOutputStream()); InputStream in = request.getInputStream(); String readLine; BufferedReader br = new BufferedReader(new InputStreamReader(in)); while (((readLine = br.readLine()) != null)) { System.out.println(readLine); } } }
但是我明白了 java.io.IOException: UT010029: Stream is closed
java.io.IOException: UT010029: Stream is closed
将内容放入String变量的正确方法是什么?
编辑 :我也尝试使用筛选器的解决方案,但我不知道如何使用请求有效载荷到其余控制器:
读取请求有效负载:
@Component public class HttpLoggingFilter implements Filter { private static final Logger logger = LoggerFactory.getLogger(HttpLoggingFilter.class); @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { ResettableStreamHttpServletRequest wrappedRequest = new ResettableStreamHttpServletRequest((HttpServletRequest) request); wrappedRequest.getInputStream().read(); String body = IOUtils.toString(wrappedRequest.getReader()); System.out.println("!!!!!!!!!!!!!!!!!! " + body); wrappedRequest.resetInputStream(); chain.doFilter(request, response); } public class ResettableStreamHttpServletRequest extends HttpServletRequestWrapper { private byte[] rawData; private HttpServletRequest request; private ResettableServletInputStream servletStream; ResettableStreamHttpServletRequest(HttpServletRequest request) { super(request); this.request = request; this.servletStream = new ResettableServletInputStream(); } void resetInputStream() { servletStream.stream = new ByteArrayInputStream(rawData); } @Override public ServletInputStream getInputStream() throws IOException { if (rawData == null) { rawData = IOUtils.toByteArray(this.request.getInputStream()); servletStream.stream = new ByteArrayInputStream(rawData); } return servletStream; } @Override public BufferedReader getReader() throws IOException { if (rawData == null) { rawData = IOUtils.toByteArray(this.request.getInputStream()); servletStream.stream = new ByteArrayInputStream(rawData); } String encoding = getCharacterEncoding(); if (encoding != null) { return new BufferedReader(new InputStreamReader(servletStream, encoding)); } else { return new BufferedReader(new InputStreamReader(servletStream)); } } private class ResettableServletInputStream extends ServletInputStream { private InputStream stream; @Override public int read() throws IOException { return stream.read(); } @Override public boolean isFinished() { // TODO Auto-generated method stub return false; } @Override public boolean isReady() { // TODO Auto-generated method stub return false; } @Override public void setReadListener(ReadListener readListener) { // TODO Auto-generated method stub } } } }
其余端点:
@RestController() public class HomeController { @PostMapping(value = "/v1") public Response handleMessage(@RequestBody Transaction transaction, HttpServletRequest request, org.zalando.logbook.HttpRequest requestv, HttpServletResponse response) throws Exception { // Get here request and response and log it into DB } }
如何调用HttpLoggingFilterJava方法handleMessage并将请求作为正文String获取?也许我可以提供服务并注入它?您可以给我一些建议,以评估代码吗?
HttpLoggingFilter
这里有很多课程。这是一次OncePerRequestFilter实现,请在此处查看https://docs.spring.io/spring- framework/docs/current/javadoc- api/org/springframework/web/filter/OncePerRequestFilter.html。基本上,问题是在链式过滤器中,请求流和响应流只能读取一次。因此,需要将这两个流包装在可以多次读取的内容中。
在前两行中,我将请求和响应包装在requestToUse和responseToUse内。ResettableStreamHttpServletRequest和ResettableStreamHttpServletResponse是包装器类,它们将原始字符串主体保留在其中,并且每次需要该流时,它们都将返回一个新流。然后,您就无需再请求和响应了,而是开始使用requestToUse和responseToUse。
我是从我做的一个旧项目中摘下来的。其实还有更多的分类,但是我为您提取了主要部分。这可能不会立即编译。尝试一下,让我知道,我会帮助您使其工作。
public class RequestResponseLoggingFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { //here you wrap the request and response into some resetable istream class HttpServletRequest requestToUse = new ResettableStreamHttpServletRequest(request); HttpServletResponse responseToUse = new ResettableStreamHttpServletResponse(response); //you read the request to log it byte[] payload = IOUtils.toByteArray(requestToUse.getReader(), requestToUse.getCharacterEncoding()); String body = new String(payload, requestToUse.getCharacterEncoding()); //here you log the body request log.(body); //let the chain continue filterChain.doFilter(requestToUse, responseToUse); // Here we log the response String response = new String(responseToUse.toString().getBytes(), responseToUse.getCharacterEncoding()); //since you can read the stream just once, you will need it again for chain to be able to continue, so you reset it ResettableStreamHttpServletResponse responseWrapper = WebUtils.getNativeResponse(responseToUse, ResettableStreamHttpServletResponse.class); if (responseWrapper != null) { responseWrapper.copyBodyToResponse(true); } } } public class ResettableStreamHttpServletRequest extends HttpServletRequestWrapper { private byte[] rawData; private ResettableServletInputStream servletStream; public ResettableStreamHttpServletRequest(HttpServletRequest request) throws IOException { super(request); rawData = IOUtils.toByteArray(request.getInputStream()); servletStream = new ResettableServletInputStream(); servletStream.setStream(new ByteArrayInputStream(rawData)); } @Override public ServletInputStream getInputStream() throws IOException { servletStream.setStream(new ByteArrayInputStream(rawData)); return servletStream; } @Override public BufferedReader getReader() throws IOException { servletStream.setStream(new ByteArrayInputStream(rawData)); return new BufferedReader(new InputStreamReader(servletStream)); } } public class ResettableStreamHttpServletResponse extends HttpServletResponseWrapper { private ByteArrayServletOutputStream byteArrayServletOutputStream = new ByteArrayServletOutputStream(); public ResettableStreamHttpServletResponse(HttpServletResponse response) throws IOException { super(response); } /** * Copy the cached body content to the response. * * @param complete whether to set a corresponding content length for the complete cached body content * @since 4.2 */ public void copyBodyToResponse(boolean complete) throws IOException { byte[] array = byteArrayServletOutputStream.toByteArray(); if (array.length > 0) { HttpServletResponse rawResponse = (HttpServletResponse) getResponse(); if (complete && !rawResponse.isCommitted()) { rawResponse.setContentLength(array.length); } rawResponse.getOutputStream().write(byteArrayServletOutputStream.toByteArray()); if (complete) { super.flushBuffer(); } } } /** * The default behavior of this method is to return getOutputStream() on the wrapped response object. */ @Override public ServletOutputStream getOutputStream() throws IOException { return byteArrayServletOutputStream; } /** * The default behavior of this method is to return getOutputStream() on the wrapped response object. */ @Override public String toString() { String response = new String(byteArrayServletOutputStream.toByteArray()); return response; } }