This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

preface

  • I don’t know if you remember the slogan we had when we were learning servlet: “ONE cup of tea, one cigarette, one parameter I pass for a day”.
  • Yes, servlet parameter passing is really complicated, we have to verify parameters, format and assign values before business starts. But since we use Spring, we have no worries any more. More specifically, since springboot we’ve been liberated.

HttpMessageConverter

  • In Web development, the browser is the client, and our Java program is the server in a container such as Tomcat. The client and server interact with each other through IO streams.
  • The client needs to save the data, submit it to the server, the server persists it to the database and then tells the client that it saved successfully! This process involves two interactions between the server and the client
  • The first time the client submits the saved data to the server through a byte stream. After saving successfully, the server will return the saved information to the byte stream to complete the interaction!!

doubt

  • Since we interact through the byte stream, we can rewrite the action of the byte stream in the SpringBoot project. Either directly returns a Java primitive type object or a wrapper object

  • Since we didn’t, SpringBoot certainly did it for us. That moves out of the main character of the day. For SpringMvc inHttpMessageConverterHelp us solve the data format conversion problem.
/** * Strategy interface that specifies a converter that can convert from and to HTTP requests and responses. * Interface for realizing data transfer between Request and Response */
public interface HttpMessageConverter<T> {}
Copy the code

Request the entry

  • RequestMappingHandlerAdapterIt’s for our controller layer@RequestMappingAnnotation method. We’ve also combed through springMVC’s execution flow before.RequestMappingHandlerAdapterIs in the MVCHandlerAdapterThe classic kind. It is how to locate methods by request and format conversion of method input and output parameters.
  • HandlerAdapterThere is a handle method in handle, which is translated as request entry function in source code.

  • And that’s the pointRequestMappingHandlerAdaptertheinvokeHandlerMethodOn.

  • We can also see that the controller is called from idea breakpoint debuggingRequestMappingHandlerAdaptertheinvokeHandlerMethodTo start the call.

  • Will end up inRequestResponseBodyMethodProcessorInterception of data return. This class intercepts both incoming and outgoing arguments. I’m breaking his return function here. Binding of incoming parameter data inreadWithMessageConvertersMethods. And in writing back data is its parent classAbstractMessageConverterMethodProcessor#writeWithMessageConvertersPlay a key role. Internally, the method finds the appropriate converter by matching the contentType in the request header with the registered Converter. And about the converter spring in requestMappingHandlerAdapter by default
public RequestMappingHandlerAdapter(a) {
   this.messageConverters = new ArrayList<>(4);
   this.messageConverters.add(new ByteArrayHttpMessageConverter());
   this.messageConverters.add(new StringHttpMessageConverter());
   try {
      this.messageConverters.add(new SourceHttpMessageConverter<>());
   }
   catch (Error err) {
      // Ignore when no TransformerFactory implementation is available
   }
   this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
}
Copy the code
  • This also corresponds to the extensions provided in our MVC chapter
/** * Customizes message converters to control object serialization format */
@Override
public void extendMessageConverters(List
       
        > converters)
       > {
    //converters.clear();
    converters.add(getFormHttpMessageConverter());
    converters.add(getJsonHttpMessageConverter());
}
Copy the code
  • So we added our converter to spring’s default converter. So messageConverters is what we’re going to focus on today.

role

public abstract class AbstractHttpMessageConverter<T> implements HttpMessageConverter<T>
Copy the code
  • It’s abstracted in Springboot. Most of our custom message converters inherit from this abstract class.
public interface HttpMessageConverter<T> {

   /** * specifies whether the class can use the converter */
   boolean canRead(Class<? > clazz,@Nullable MediaType mediaType);

   /** * Whether the converter supports writing the class to */
   boolean canWrite(Class<? > clazz,@Nullable MediaType mediaType);

   /** * The mediaType of the request header Settings supported by the converter */
   List<MediaType> getSupportedMediaTypes(a);

   /** * Reads the specified class */ from the input byte stream
   T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
         throws IOException, HttpMessageNotReadableException;

   /** * outputs the specified class to a byte stream */
   void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
         throws IOException, HttpMessageNotWritableException;

}
Copy the code

InvocableHandlerMethod

  • It says that the request will end up atRequestMappingHandlerAdaptertheinvokeHandlerMethodOn. This method is based on the parameter and the class object to decide which one to useHandlerMethodArgumentResolverTo perform data parsing.
@Nullable
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
   HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
   if (result == null) {
      for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
         if (resolver.supportsParameter(parameter)) {
            result = resolver;
            this.argumentResolverCache.put(parameter, result);
            break; }}}return result;
}
Copy the code
  • Getting the corresponding handler according to MethodParameter is also validated by the support methods built into each handler. For instanceRequestResponseBodyMethodProcessorHis support was simple and methodicalRequestBodyAnnotated support

extension

  • We can customize an HttpMessageconverter and register it directly as a bean that will be parsed by SpringMVC and added to the execution chain of the message converter. We can also add our custom converters to the extendMessageConverters method by implementing WebMvcConfigurer. I’m not implementing it here

  • There is also an addArgumentResolvers method in WebMvcConfigurer. Through this method name we can know that he is to support us the above mentioned HandlerMethodArgumentResolver. He was responsible for the whole process of parsing our parameters. Class methods such as analytical RequestParam RequestParamMethodArgumentResolver responsible for labeling request; RequestResponseBodyMethodProcessor is responsible for parsing RequestBody labeling request class methods. The first is parsed through addFormats, the second is parsed through HttpMessageconverter, and Jackson does the parsing internally.

  • We usually need to upload and download files in development. Whether we can be based on his custom only when a HandlerMethodArgumentResolver to download data need to be ready to flow with custom annotation can finish downloading functions?

Please feel free to discuss in the comments section. The nuggets will draw 100 nuggets in the comments section after the diggnation project. See the event article for details