在日常开发中,我们都需要向页面传送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字符串反序列化成对象
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中默认的。通过重写相应方法,我们就可以满足自己需求。