The role and replacement analysis of Spring HttpMessageConverter

The role and replacement analysis of Spring HttpMessageConverter

This article mainly introduces the function and replacement analysis of Spring HttpMessageConverter.

I believe that developers who have used Spring have used @RequestBody and @ResponseBody annotations, which can directly parse input into Json and output into Json. However, HTTP requests and responses are text-based, which means that the browser and server exchange the original Text is used to communicate, and here is where HttpMessageConverter actually plays a role.

HttpMessageConverter

Http request and response messages are actually strings. When the request message is sent to the Java program, it will be encapsulated into a ServletInputStream stream. The developer then reads the message, and the response message is output through the ServletOutputStream stream.

Only the original string message can be read from the stream, and the same is true for the output stream. Then when the message arrives at SpringMVC/SpringBoot and goes out from SpringMVC/SpringBoot, there is a conversion problem from string to java object. This process, in SpringMVC/SpringBoot, is solved through HttpMessageConverter. HttpMessageConverter interface source code:

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;
}

Here is an example to illustrate:

@RequestMapping("/test")
@ResponseBody
public String test(@RequestBody String param) {
    
    
  return "param '" + param + "'";
}

Before the request enters the test method, the corresponding HttpMessageConverter implementation class will be selected based on the @RequestBody annotation to parse the request parameters into the param variable. Because the parameters here are of type String, the StringHttpMessageConverter class is used here, and its canRead() The method returns true, and then the read() method reads the request parameters from the request and binds them to the param variable of the test() method.

Similarly, when the test method is executed, since the return value identifies @ResponseBody, SpringMVC/SpringBoot will use the write() method of StringHttpMessageConverter to write the result as a String value into the response message. Of course, the canWrite() method returns true at this time.

Use the following figure to briefly describe the entire process:

img

During Spring's processing, a request message and a response message are abstracted into a request message HttpInputMessage and a response message HttpOutputMessage respectively.

When processing a request, the appropriate message converter binds the request message to the formal parameter object in the method. Here, the same object may appear in multiple different message forms, such as json and xml. The same goes for responding to requests.

In Spring, there are different HttpMessageConverter implementation classes to handle various message forms for different message forms. As for the different message parsing implementations, they are in different HttpMessageConverter implementation classes.

Replace @ResponseBody's default HttpMessageConverter

A SpringBoot demonstration example is used here. In SpringMVC/SpringBoot, annotations such as @RequestBody use jackson to parse json by default. See the following example:

@Controller
@RequestMapping("/user")
public class UserController {
    
    

  @RequestMapping("/testt")
  @ResponseBody
  public User testt() {
    
    
    User user = new User("name", 18);
    return user;
  }
}
public class User {
    
    

  private String username;

  private Integer age;
  
  private Integer phone;
  
  private String email;

  public User(String username, Integer age) {
    
    
  super();
  this.username = username;
  this.age = age;
  }
}

Browser access /user/testt returns the following:

img

This is the result of using jackson to parse. Now let's change to using fastjson to parse the object. Here is to replace the default HttpMessageConverter, which is to use FastJsonHttpMessageConverter to handle the conversion between Java objects and HttpInputMessage/HttpOutputMessage.

First, create a new configuration class to add and configure FastJsonHttpMessageConverter. Spring 4.x begins to recommend the use of Java configuration and annotation, that is, no xml file, especially for Spring Boot.

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;

import java.nio.charset.Charset;

@Configuration
public class HttpMessageConverterConfig {
    
    

  //引入Fastjson解析json,不使用默认的jackson
  //必须在pom.xml引入fastjson的jar包,并且版必须大于1.2.10
  @Bean
  public HttpMessageConverters fastJsonHttpMessageConverters() {
    
    
    //1、定义一个convert转换消息的对象
    FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();

    //2、添加fastjson的配置信息
    FastJsonConfig fastJsonConfig = new FastJsonConfig();

    SerializerFeature[] serializerFeatures = new SerializerFeature[]{
    
    
        //  输出key是包含双引号
//        SerializerFeature.QuoteFieldNames,
        //  是否输出为null的字段,若为null 则显示该字段
//        SerializerFeature.WriteMapNullValue,
        //  数值字段如果为null,则输出为0
        SerializerFeature.WriteNullNumberAsZero,
        //   List字段如果为null,输出为[],而非null
        SerializerFeature.WriteNullListAsEmpty,
        //  字符类型字段如果为null,输出为"",而非null
        SerializerFeature.WriteNullStringAsEmpty,
        //  Boolean字段如果为null,输出为false,而非null
        SerializerFeature.WriteNullBooleanAsFalse,
        //  Date的日期转换器
        SerializerFeature.WriteDateUseDateFormat,
        //  循环引用
        SerializerFeature.DisableCircularReferenceDetect,
    };

    fastJsonConfig.setSerializerFeatures(serializerFeatures);
    fastJsonConfig.setCharset(Charset.forName("UTF-8"));

    //3、在convert中添加配置信息
    fastConverter.setFastJsonConfig(fastJsonConfig);

    //4、将convert添加到converters中
    HttpMessageConverter<?> converter = fastConverter;

    return new HttpMessageConverters(converter);
  }
}

Here, if the string type value is null, "" is returned, and if the numeric type value is null, 0 is returned. Restart the application, access the /user/testt interface again, and return as follows:

img

You can see that null is converted to "" or 0 at this time.

Guess you like

Origin blog.csdn.net/qq_43842093/article/details/132791948