In SpringMVC, you can use the two annotations @RequestBody and @ResponseBody to complete the conversion of request packets to objects and object to response packets, respectively. This flexible message conversion mechanism is used. Use the HttpMessageConverter configured by the system to parse, and then bind the corresponding data to the object to be returned.
HttpInputMessage
This class is an abstraction of a Http request message within SpringMVC. In the read() method of HttpMessageConverter, there is a formal parameter of HttpInputMessage, which is the internal abstraction of the receptor "request message" played by SpringMVC's message converter. The message converter extracts messages from the "request message" according to the rules and converts them into objects declared in the method formal parameter.
package org.springframework.http;import java.io.IOException;import java.io.InputStream;public interface HttpInputMessage extends HttpMessage { InputStream getBody() throws IOException;}HttpOutputMessage
In the write() method of HttpMessageConverter, there is a formal parameter of HttpOutputMessage, which is the internal abstraction of the receptor "response message" used by SpringMVC's message converter. The message converter writes the "response message" into the response message according to certain rules.
package org.springframework.http;import java.io.IOException;import java.io.OutputStream;public interface HttpOutputMessage extends HttpMessage { OutputStream getBody() throws IOException;}HttpMessageConverter
/* * Copyright 2002-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.springframework.http.converter;import java.io.IOException;import java.util.List;import org.springframework.http.HttpInputMessage;import org.springframework.http.HttpOutputMessage;import org.springframework.http.MediaType;public interface HttpMessageConverter<T> { boolean canRead(Class<?> clazz, MediaType mediaType); boolean canWrite(Class<?> clazz, MediaType mediaType); List<MediaType> getSupportedMediaTypes(); T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException; void write(T t, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException;}The HttpMessageConverter interface provides 5 methods:
The parameters of the read and write methods include HttpInputMessage and HttpOutputMessage objects, respectively. These two objects represent the request and response parts in an Http communication respectively. The corresponding input stream and output stream can be obtained through the getBody method.
Currently, there are quite a lot of converters provided by default in Spring, including:
| name | effect | Reading support MediaType | Write support MediaType |
|---|---|---|---|
| ByteArrayHttpMessageConverter | Conversion of data and byte arrays | / | application/octet-stream |
| StringHttpMessageConverter | Conversion of data and String types | text/* | text/plain |
| FormHttpMessageConverter | Conversion of form and MultiValueMap<string, string=""> | application/x-www-form-urlencoded | application/x-www-form-urlencoded |
| SourceHttpMessageConverter | Transform.Source conversion of data and javax.xml.transform.Source | text/xml and application/xml | text/xml and application/xml |
| MarshallingHttpMessageConverter | Convert XML data using SpringMarshaller/Unmarshaller | text/xml and application/xml | text/xml and application/xml |
| MappingJackson2HttpMessageConverter | Convert Json data using Jackson's ObjectMapper | application/json | application/json |
| MappingJackson2XmlHttpMessageConverter | Convert XML data using Jackson's XmlMapper | application/xml | application/xml |
| BufferedImageHttpMessageConverter | Conversion of data and java.awt.image.BufferedImage | All types supported by Java I/O API | All types supported by Java I/O API |
HttpMessageConverter matching process:
@RequestBody annotation: According to the Content-Type type of the header part of the Request object, match the appropriate HttpMessageConverter one by one to read the data.
private Object readWithMessageConverters(MethodParameter methodParam, HttpInputMessage inputMessage, Class paramType) throws Exception { MediaType contentType = inputMessage.getHeaders().getContentType(); if (contentType == null) { StringBuilder builder = new StringBuilder(ClassUtils.getShortName(methodParam.getParameterType())); String paramName = methodParam.getParameterName(); if (paramName != null) { builder.append(' '); builder.append(paramName); } throw new HttpMediaTypeNotSupportedException("Cannot extract parameter (" + builder.toString() + "): no Content-Type found"); } List<MediaType> allSupportedMediaTypes = new ArrayList<MediaType>(); if (this.messageConverters != null) { for (HttpMessageConverter<?> messageConverter : this.messageConverters) { allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes()); if (messageConverter.canRead(paramType, contentType)) { if (logger.isDebugEnabled()) { logger.debug("Reading [" + paramType.getName() + "] as /"" + contentType + "/" using [" + messageConverter + "]"); } return messageConverter.read(paramType, inputMessage); } } } throw new HttpMediaTypeNotSupportedException(contentType, allSupportedMediaTypes); } @ResponseBody annotation: According to the Accept attribute (comma-separated) of the header part of the Request object, one by one, and traverse to find the HttpMessageConverter that can be processed.
private void writeWithMessageConverters(Object returnValue, HttpInputMessage inputMessage, HttpOutputMessage outputMessage) throws IOException, HttpMediaTypeNotAcceptableException { List<MediaType> acceptedMediaTypes = inputMessage.getHeaders().getAccept(); if (acceptedMediaTypes.isEmpty()) { acceptedMediaTypes = Collections.singletonList(MediaType.ALL); } MediaType.sortByQualityValue(acceptedMediaTypes); Class<?> returnValueType = returnValue.getClass(); List<MediaType> allSupportedMediaTypes = new ArrayList<MediaType>(); if (getMessageConverters() != null) { for (MediaType acceptedMediaType : acceptedMediaTypes) { for (HttpMessageConverter messageConverter: getMessageConverters()) { if (messageConverter.canWrite(returnValueType, acceptedMediaType)) { messageConverter.write(returnValue, acceptedMediaType, outputMessage); if (logger.isDebugEnabled()) { MediaType contentType = outputMessage.getHeaders().getContentType(); if (contentType == null) { contentType = acceptedMediaType; } logger.debug("Written [" + returnValue + "] as /"" + contentType + "/" using [" + messageConverter + "]"); } this.responseArgumentUsed = true; return; } } } for (HttpMessageConverter messageConverter : messageConverters) { allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes()); } } throw new HttpMediaTypeNotAcceptableException(allSupportedMediaTypes); }Customize a JSON converter
class CustomJsonHttpMessageConverter implements HttpMessageConverter { //Jackson's Json mapping class private ObjectMapper mapper = new ObjectMapper(); //The support type of this converter: application/json private List supportedMediaTypes = Arrays.asList(MediaType.APPLICATION_JSON); /** * Determine whether the converter can convert the input content into Java type* @param clazz Java type that needs to be converted* @param mediaType MediaType for this request * @return */ @Override public boolean canRead(Class clazz, MediaType mediaType) { if (mediaType == null) { return true; } for (MediaType supportedMediaType : getSupportedMediaTypes()) { if (supportedMediaType.includes(mediaType)) { return true; } } return false; } /** * Determine whether the converter can convert Java types to the specified output content* @param clazz The Java type that needs to be converted* @param mediaType MediaType for this request * @return */ @Override public boolean canWrite(Class clazz, MediaType mediaType) { if (mediaType == null || MediaType.ALL.equals(mediaType)) { return true; } for (MediaType supportedMediaType : getSupportedMediaTypes()) { if (supportedMediaType.includes(mediaType)) { return true; } } return false; } /** * Get MediaType supported by this converter * @return */ @Override public List getSupportedMediaTypes() { return supportedMediaTypes; } /** * Read the request content and convert the Json into a Java object* @param clazz The Java type that needs to be converted* @param inputMessage Request object* @return * @throws IOException * @throws HttpMessageNotReadableException */ @Override public Object read(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { return mapper.readValue(inputMessage.getBody(), clazz); } /** * Convert Java object to Json to return content* @param o Object that needs to be converted* @param contentType Return type* @param outputMessage Receipt object* @throws IOException * @throws HttpMessageNotWritableException */ @Override public void write(Object o, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { mapper.writeValue(outputMessage.getBody(), o); }}Customize MappingJackson2HttpMessage
It can be seen from the write method in the parent class AbstractHttpMessageConverter of MappingJackson2HttpMessageConverter that the method writes data to the output stream that returns the result through the writeInternal method, so you only need to override the method:
@Beanpublic MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() { return new MappingJackson2HttpMessageConverter() { //Rewrite the writeInternal method and encrypt it first before returning the content @Override protected void writeInternal(Object object, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { //Use Jackson's ObjectMapper to convert Java objects into Json String ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(object); LOGGER.error(json); //Encrypt String result = json + "Encrypted!"; LOGGER.error(result); //Output outputMessage.getBody().write(result.getBytes()); } };} After that, you need to configure this custom converter into Spring. Here you add a custom converter by rewriting the configureMessageConverters method in WebMvcConfigurer:
//Add a custom converter @Overridepublic void configureMessageConverters(List<httpmessageconverter<?>> converters) { converters.add(mappingJackson2HttpMessageConverter()); super.configureMessageConverters(converters);}The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.