Recently, many interactions have to deal with native HttpServletRequest and HttpServletResponse. Read the body data from HttpServletRequest and encapsulate it into a data structure; Write data to HttpServletResponse and respond. The traditional way of writing is not elegant. Today I'll introduce you a more elegant way.
HttpMessageConverter
HttpMessageConverter is a message converter model provided by the Spring framework, which is a policy interface for converting between HTTP requests and responses. It can read the input message HttpInputMessage; You can also write the output message HttpOutputMessage.
The message transformation of Spring MVC is completed through the implementation of this interface. There are many implementations of HttpMessageConverter:
Generally, the handling of Form submission, JSON, XML, string and even Protobuf in Spring MVC is completed by the implementation of HttpMessageConverter. The body parameters passed from the front end to the back end and the data returned from the back end to the front end are converted by this interface. In Spring IoC (Spring MVC environment), there is also a container for HttpMessageConverters. HttpMessageConverters:
@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, find out what HttpInputMessage and HttpOutputMessage are used for.
HttpInputMessage
HttpInputMessage represents an HTTP input message, which is composed of a request header and a readable request body. It is usually implemented by the server-side HTTP request handle or the client-side HTTP response handle.
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 related. As long as we find out the actual relationship between the two, we can let the HttpMessageConverter read and process the request information carried by HttpServletRequest.
ServletServerHttpRequest
To tell you the truth, I really found:
ServletServerHttpRequest is not only the implementation of HttpInputMessage, but also holds an HttpServletRequest instance property. All operations of ServletServerHttpRequest are based on HttpServletRequest. We can inject an HttpServletRequest instance into it by constructing, so that the HttpMessageConverter can indirectly process HttpServletRequest.
Actual combat of extracting request body
The focus here is to use HttpMessageConverter in Servlet filter. It is not recommended to operate HttpServletRequest in Spring MVC. I chose FormHttpMessageConverter, which is usually used to process application/x-www-form-urlencoded requests. We write a filter to intercept the request and extract the body:
/** * Processing 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 POST request with content type of 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
The console will print:
2021-12-30 6:43:56.409 INFO 12408 --- [nio-8080-exec-1] sfds: Print the read request body:{a=[b123], c=[d123], e=[f123]}
ServletServerHttpResponse
If there is a ServletServerHttpRequest, there is a ServletServerHttpResponse. The general principle is similar. It is just opposite to 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 as follows:
ServletServerHttpResponse servletServerHttpResponse = new ServletServerHttpResponse(response); // Using 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 deal with some request response problems gracefully. However, it should be noted that the request body can only be read once. Even if it is wrapped in ServletServerHttpRequest, pay attention to the difference between it and HttpServletRequestWrapper.
Pay attention to the official account: Felordcn for more information