Many interactions recently have to deal with native HttpServletRequest
and HttpServletResponse
. Read body data from HttpServletRequest
and encapsulate it into a certain data structure; write data to HttpServletResponse
and respond. The traditional way of writing is very inelegant. Today I will introduce a more elegant way for you.
HttpMessageConverter
HttpMessageConverter
is a message converter model provided by the Spring framework, a strategy interface for converting between HTTP requests and responses. It can read the input message HttpInputMessage
; it can also write the output message HttpOutputMessage
.
HttpMessageConverter
The message conversion of Spring MVC is done through the implementation of this interface. HttpMessageConverter
has many implementations:
Common implementations of HttpMessageConverter
Typically Spring MVC handles Form form submissions, JSON, XML, strings, and even Protobuf< /strong> are all completed by the implementation of HttpMessageConverter
, the body parameter passed from the front end to the back end, and the data returned from the back end to the front end are all converted by this interface. In Spring IoC (Spring MVC environment) there is also a container HttpMessageConverters
that stores HttpMessageConverter
:
@Bean @ConditionalOnMissingBean public HttpMessageConverters messageConverters(ObjectProvider<HttpMessageConverter<?>> converters) { return new HttpMessageConverters((Collection)converters.orderedStream().collect(Collectors.toList())); }
We can use it directly. So how to use it? First of all, we must figure out what HttpInputMessage
and HttpOutputMessage
are for.
HttpInputMessage
HttpInputMessage
represents an HTTP input message, which consists of request header headers and a readable request body body, usually Implemented by a HTTP request handler on the server side or an HTTP response handler on the client side.
HttpInputMessage
And HttpServletRequest
is the extension interface of ServletRequest
, which provides the request information of HTTP Servlet, and also includes the request header and request body, so the two are have connection. As long as we find out the actual relationship between the two, we can let HttpMessageConverter
read and process the request information carried by HttpServletRequest
.
ServletServerHttpRequest
To be honest, I found:
ServletServerHttpRequest
ServletServerHttpRequest
is not only the implementation of HttpInputMessage
, it also holds a HttpServletRequest
instance attribute, all operations of ServletServerHttpRequest
They are all based on HttpServletRequest
. We can inject HttpServletRequest
instance into it through construction, so that HttpMessageConverter
can process HttpServletRequest
indirectly.
Actual extraction of request body
The focused scenario here is to use HttpMessageConverter
in the Servlet filter. It is not recommended to operate HttpServletRequest
in Spring MVC. I chose FormHttpMessageConverter
, which is usually used to handle application/x-www-form-urlencoded
requests. We write a filter to intercept requests to extract body:
/** * Handle application/x-www-form-urlencoded requests * * @author felord.cn */ @Component public class FormUrlencodedFilter implements Filter { private final FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter(); private static final Logger log = LoggerFactory.getLogger(FormUrlencodedFilter.class); @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException { String contentType = request. getContentType(); MediaType type= StringUtils.hasText(contentType)? MediaType.valueOf(contentType):null; ServletServerHttpRequest serverHttpRequest = new ServletServerHttpRequest((HttpServletRequest) request); if (formHttpMessageConverter. canRead(MultiValueMap. class, type)) { MultiValueMap<String, String> read = formHttpMessageConverter.read(null, serverHttpRequest); log.info("Print the read request body: {}", read); } } }
Then execute a request of POST
type, Content-Type
is application/x-www-form-urlencoded
:
POST /ind HTTP/1.1 Host: localhost:8080 Content-Type: application/x-www-form-urlencoded Content-Length: 20 a=b123 &c=d123&e=f123
Console prints:
Print the read request body: {a=[b123], c=[d123], e=[f123]}
ServletServerHttpResponse
There is ServletServerHttpRequest
and there is ServletServerHttpResponse
, the general principle is similar. It is exactly the opposite of ServletServerHttpRequest
. If we need to deal with the response problem, for example, if we want to write a JSON response through HttpServletResponse
, we can probably write it like this:
ServletServerHttpResponse servletServerHttpResponse = new ServletServerHttpResponse(response); // use json converter MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter(); // authentication refers to the object instance that needs to be written mappingJackson2HttpMessageConverter.write(authentication, MediaType.APPLICATION_JSON,servletServerHttpResponse);
Summary
HttpMessageConverter
abstracts the strategy of HTTP message conversion, which can help us handle some request response problems gracefully. But one thing to note is that the request body body can only be read once, even if it is wrapped in ServletServerHttpRequest
, pay attention to the difference from HttpServletRequestWrapper.