Spring MVC - Get Httpservletresponse Body

Spring MVC - Get HttpServletResponse body

It's been hard on searching deeply into it but found that ResponseBodyAdvice could be suitable for my purposes. So looking for some example on StackOverflow found this guy which had quite same issue having to manipulate the Object body.

That's my final working solution in order to implement what I wrote here

@ControllerAdvice
public class CSRFHandler implements ResponseBodyAdvice<Object> {

@Value("${security.csrf.enabled}")
private String csrfEnabled;

@Value("${security.csrf.headerName}")
private String csrfHeaderName;

@Value("${security.csrf.salt}")
private String salt;

@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}

@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
ServerHttpResponse response) {

if (new Boolean(csrfEnabled).booleanValue()) {
String csrfValue = SecureUtil.buildCsrfValue(salt, StringUtil.toJson(body));
response.getHeaders().add(csrfHeaderName, csrfValue);
}

return body;
}

}

Logging response body (HTML) from HttpServletResponse using Spring MVC HandlerInterceptorAdapter

This would be better done using a Servlet Filter rather than a Spring HandlerInterceptor, for the reason that a Filter is allowed to substitute the request and/or response objects, and you could use this mechanism to substitute the response with a wrapper which logs the response output.

This would involve writing a subclass of HttpServletResponseWrapper, overriding getOutputStream (and possibly also getWriter()). These methods would return OutputStream/PrintWriter implementations that siphon off the response stream into a log, in addition to sending to its original destination. An easy way to do this is using TeeOutputStream from Apache Commons IO, but it's not hard to implement yourself.

Here's an example of the sort of thing you could do, making use of Spring's GenericFilterBean and DelegatingServletResponseStream, as well as TeeOutputStream, to make things easier:

public class ResponseLoggingFilter extends GenericFilterBean {

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse responseWrapper = loggingResponseWrapper((HttpServletResponse) response);
filterChain.doFilter(request, responseWrapper);
}

private HttpServletResponse loggingResponseWrapper(HttpServletResponse response) {
return new HttpServletResponseWrapper(response) {
@Override
public ServletOutputStream getOutputStream() throws IOException {
return new DelegatingServletOutputStream(
new TeeOutputStream(super.getOutputStream(), loggingOutputStream())
);
}
};
}

private OutputStream loggingOutputStream() {
return System.out;
}
}

This logs everything to STDOUT. If you want to log to a file, it'll get a big more complex, what with making sure the streams get closed and so on, but the principle remains the same.

Using HttpServletResponse object in spring MVC handler method

out.println() is used in jsp file. So you can edit your home.jsp as follows

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
<link href="<c:url value='/resources/css/style.css' />"
rel="stylesheet">
<script src="<c:url value='/resources/js/sample.css' /> "></script>


</head>
<body>
This is home view
<%
out.println("<h1> this is my response block</h1>");
%>
</body>
</html>

If you want to add something for home.jsp via the controller class, you can change your controller class as follows.

package springmvcsearch;


import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class SearchController {
@RequestMapping("/home")
public String home(HttpServletRequest req,HttpServletResponse res) throws IOException {

res.setContentType("text/html");
PrintWriter out = res.getWriter();
String message = "this is my response block";
req.setAttribute("message", message);

return "home";
}

}

Then change your jsp file as follows.

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
<link href="<c:url value='/resources/css/style.css' />"
rel="stylesheet">
<script src="<c:url value='/resources/js/sample.css' /> "></script>


</head>
<body>
This is home view
<h1>${message}</h1>
</body>
</html>

For further explanation, go through this link how to message from servlet and display in jsp

Why does HttpServletResponse not have a simple String of the response body?

HttpServletRequest/Response classes are designed to stream the data directly from/to the browser. They are there to handle the I/O communication over the network, but they do not need to store the whole request/response body.

This allows servlets to directly stream data, and by the time you would want to log the response, the data has already been sent over the network (well, except with async processing but that makes things even more complicated for your purposes). A default implementation wouldn’t know that it had to keep a copy of the data for logging purposes.

This is why you need to implement a Filter that would wrap the request/response in order to keep and log the body, as you have pointed in your link. In general you will probably want to customize this behavior in order to select only specific requests, limit the size, define how to log it etc. so a default implementation is not provided, but you have a lot of solutions.

Get responseBody from HttpServletResponse Java

package com.biclinical.rmm.controller;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import org.springframework.web.util.WebUtils;

import com.biclinical.rmm.utility.ServiceUtils;

@Component
@Order(1)
@WebFilter(urlPatterns = { "/*" })
public class DownloadFileFilter implements Filter {

private static final Logger logger = Logger.getLogger(DownloadFileFilter.class);

@Override
public void init(FilterConfig filterConfig) throws ServletException {
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {

HttpServletRequest requestToCache = new ContentCachingRequestWrapper((HttpServletRequest) request);
HttpServletResponse responseToCache = new ContentCachingResponseWrapper((HttpServletResponse) response);

try {
if (requestToCache.getRequestURL().toString().contains("/download")) {
chain.doFilter(request, responseToCache);
getResponseData(responseToCache);

} else {
chain.doFilter(request, response);
}
} catch (Exception e) {
logger.error("Exception in CustomFilter.doFilter(): ", e);
}

}

private static void getResponseData(HttpServletResponse response) throws Exception {
ContentCachingResponseWrapper wrapper = WebUtils.getNativeResponse(response,
ContentCachingResponseWrapper.class);
if (wrapper != null) {
byte[] buf = wrapper.getContentAsByteArray();
if (buf.length > 0) {
String payload = new String(buf, 0, buf.length, wrapper.getCharacterEncoding());
logger.debug("Response Richa :" + payload);
wrapper.copyBodyToResponse();
}
}
}

@Override
public void destroy() {
}

}


Related Topics



Leave a reply



Submit