在日常开发中,我们都需要向页面传送json格式的字符串给页面进行渲染,怎么将对象序列化成json,我们只需要在对应方法头上加@ResponseBody注解或者直接在类上加@RestController注解,其实@RestController注解也就是@ResponseBody+@Controller的组合。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
    @AliasFor(
        annotation = Controller.class
    )
    String value() default "";
}  
    那么在Spring Boot中默认的JSON解析方案是怎么样的?今天在看完视频学习后,顺便做一下笔记记录一下,方便以后查阅。
    首先我们进行测试一下,创建User实体类:
/**
 * @Author ChoiBin
 * @Date 2019-07-28 14:27
 * @Version 1.0
 */
public class User {

    private Integer id;
    private String username;
    private String address;
//省略get set方法
}    
    创建一个UserController
package com.choi.json.controller;

import com.choi.json.bean.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author ChoiBin
 * @Date 2019-07-28 14:28
 * @Version 1.0
 */
@RestController
public class UserController {

    @GetMapping("/user")
    public List<User> getUser(){
        List<User> users = new ArrayList<>();

        for(int i = 0;i < 10;i++){
            User user = new User();
            user.setId(i);
            user.setUsername("choibin" + i);
            user.setAddress("abc" + i);
            users.add(user);
        }

        return users;
    }

}
    测试结果

    在开发中,我们都需要将对象序列化成json字符串,也需要将json字符串反序列化成对象,其实在底层这两个过程都需要借助一个HttpMessageConverter对象,这是一个消息转换对象,主要有两方面的功能:
  • 将服务端返回的对象序列化JSON字符串
  • 将前端传来的JSON字符串反序列化成对象
    所有的JSON生成都离不开相关的HttpMessageConverter,Spring MVC中自动配置了Jackson和Gson的HttpMessageConverter,在Spring Boot中又对此作了自动化配置,所以用户需要使用Jackson或者Gson,没有其他额外配置,则只需要添加依赖就可以了。
    Spring Boot中自动配置Jackson的类是
    org.springframework.boot.autoconfigure.http.JacksonHttpMessageConvertersConfiguration
@Configuration
class JacksonHttpMessageConvertersConfiguration {
    JacksonHttpMessageConvertersConfiguration() {
    }

    //...还有其他方法

    //当加入了JSON依赖以后,以下的配置就会生效,在序列化成JSON的过程,主要依赖的就是ObjectMapper对象     
      @Configuration
    @ConditionalOnClass({ObjectMapper.class})
    @ConditionalOnBean({ObjectMapper.class})
    @ConditionalOnProperty(
        name = {"spring.http.converters.preferred-json-mapper"},
        havingValue = "jackson",
        matchIfMissing = true
    )
    protected static class MappingJackson2HttpMessageConverterConfiguration {
        protected MappingJackson2HttpMessageConverterConfiguration() {
        }

          //添加了JSON依赖后,默认会帮我们配置一个MappingJackson2HttpMessageConverter对象加入到容器当中,这个对象也就对象转换成JSON的工具类         @Bean
        @ConditionalOnMissingBean(
            value = {MappingJackson2HttpMessageConverter.class},
            ignoredType = {"org.springframework.hateoas.mvc.TypeConstrainedMappingJackson2HttpMessageConverter", "org.springframework.data.rest.webmvc.alps.AlpsJsonHttpMessageConverter"}
        )
        public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
            return new MappingJackson2HttpMessageConverter(objectMapper);
        }
    }
}     
    而配置Gson的类是:org.springframework.boot.autoconfigure.http.GsonHttpMessageConvertersConfiguration。本文最主要的是JSON,所以就不贴源码了。
    我们看了JSON的自动配置类,了解到转换过程是依赖于MappingJackson2HttpMessageConverter 这个对象,那么我们就使用一下,进行测试。
    在User类中添加出生时间:
/**
 * @Author ChoiBin
 * @Date 2019-07-28 14:27
 * @Version 1.0
 */
public class User {

    private Integer id;
    private String username;
    private String address;
    private Date birthDay;
}    
    测试结果

    我们发现,最终显示的JSON中时间的格式不是我们想要的格式,这时我们在User类中的birthDay属性上加上@JsonFormat(pattern = "yyyy-MM-dd")
public class User {

    private Integer id;
    private String username;
    private String address;
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date birthDay;
}    
    重新测试

    这种方法在类很多的时候,就需要很大的工作量,因此可以使用全局的方法,我们可以创建一个config类,重写mappingJackson2HttpMessageConverter方法,来进行实现,如下所示
    
/**
 * @Author ChoiBin
 * @Date 2019-07-28 15:08
 * @Version 1.0
 */
@Configuration
public class WebMvcConfig {

    @Bean
    MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(){
        MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = new ObjectMapper();    //主要是依赖于ObjectMapper来进行实现
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));
        mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper);
        return mappingJackson2HttpMessageConverter;
    }
}
    同样可以得到一样的结果
    在源码中,ObjectMapper是通过参数创建来的,那这个参数又是从哪里来的?它来自于org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration这个类
@Configuration
@ConditionalOnClass({ObjectMapper.class})
public class JacksonAutoConfiguration {
    private static final Map<?, Boolean> FEATURE_DEFAULTS;

    public JacksonAutoConfiguration() {
    }

   @Configuration
    @ConditionalOnClass({Jackson2ObjectMapperBuilder.class})
    static class JacksonObjectMapperConfiguration {
        JacksonObjectMapperConfiguration() {
        }

        @Bean
        @Primary
        @ConditionalOnMissingBean
        public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
            return builder.createXmlMapper(false).build();
        }
    }
}    
    如果我们没有实现ObjectMessage类,那么默认的就会使用这个;那么我们自定义一个ObjectMessage对象,也可以得到同样的结果。
public class WebMvcConfig {

//    @Bean
//    MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(){
//        MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
//        ObjectMapper objectMapper = new ObjectMapper();
//        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));
//        mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper);
//        return mappingJackson2HttpMessageConverter;
//    }

    @Bean
    ObjectMapper objectMapper(){
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy/MM/dd"));
        return objectMapper;
    }
}    
    
    通过这个例子的实现,自己也是明白了Spring Boot中JSON配置的原理,如果自己没有实现对应的方法,那么就会使用Spring Boot中默认的。通过重写相应方法,我们就可以满足自己需求。