上篇文章我们介绍了在Spring Boot Web中Jackson的基本使用,当使用Jackson实现Json与Bean之间转换时,最主要的类便是Jackson的ObjectMapper。
当集成在Spring Boot时,会自动对该类进行初始化。本篇文章,我们一探究竟,并自定义ObjectMapper来实现相应的功能。
Spring Boot初始化ObjectMapper
在Spring Boot的自动配置JacksonAutoConfiguration中有这样的初始化代码:
@Configuration(proxyBeanMethods = false)@ConditionalOnClass(Jackson2ObjectMapperBuilder.class)static class JacksonObjectMapperConfiguration { @Bean @Primary @ConditionalOnMissingBean ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) { return builder.createXmlMapper(false).build(); }}
这段代码的基本操作就是当类路径下存在Jackson2ObjectMapperBuilder类时,该配置会自动实例化,而其内部的jacksonObjectMapper会实例化一个ObjectMapper对象来处理Json与Bean的转换。
该方法上的@ConditionalOnMissingBean说明,当不存在ObjectMapper时便执行该方法的实例化的操作,也就是说会通过Jackson2ObjectMapperBuilder来创建一个ObjectMapper对象。
换句话说,我们自己如果自定义了ObjectMapper对象,那么上述代码便不会进行相应的自动化配置。
处理日期格式化
在这里对User中的createDate字段进行格式化处理。
public class User { private String userNo; private String username; private int age; private Date createDate; // 省略getter/setter方法 }
自定义ObjectMapper的实例化。
@Configurationpublic class JacksonConfig { @Bean public ObjectMapper jacksonObjectMapper() { ObjectMapper mapper = new ObjectMapper(); mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss")); return mapper; }}
再执行单元测试,获得的返回结果便是:
返回结果信息:{"userNo":"1000","username":"Tom","age":18,"createDate":"2019-12-31 05:15:30"}
很显然,按照预期的格式进行了格式化。对应的,如果传递的参数有日期格式的字符需要被解析,则字符串要符合“yyyy-MM-dd hh:mm:ss”格式,否则无法解析。
使用ObjectMapper
除了Spring Boot在Web请求是使用HttpMessageConverter间接调用ObjectMapper来替我们进行Json与Bean直接的转换,我们还可以自己主动使用该注解。
通过@Autowired获取容器中的ObjectMapper实例并注入,然后调用其对应的方法进行操作。
@RestControllerpublic class JsonController { @Autowired private ObjectMapper objectMapper; @GetMapping("writeString") public String writeString() throws JsonProcessingException { User user = new User(); user.setUserNo("1000"); user.setUsername("Tom"); user.setAge(18); user.setCreateDate(new Date()); return objectMapper.writeValueAsString(user); }}
上述方法主动调用objectMapper的writeValueAsString方法对Bean进行转换。也就是说,我们不仅仅可以依赖Spring Boot自动进行转换,我们也可以自己获取该对象进行操作。相关单元测试代码如下:
@Testvoid writeString() throws Exception { MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get("/writeString")).andReturn(); String result = mvcResult.getResponse().getContentAsString(); logger.info("返回结果信息:{}",result);}
同样的,反序列化时可以使用JsonNode或直接绑定对象。对应的代码实现实例如下。
@PostMapping("readJson")public void readJson(String userJson) throws JsonProcessingException { User user = objectMapper.readValue(userJson,User.class); System.out.println("userNo: " + user.getUserNo()); System.out.println("username: " + user.getUsername()); System.out.println("age: " + user.getAge()); System.out.println("createDate: " + user.getCreateDate()); System.out.println("----------------------"); JsonNode jsonNode = objectMapper.readTree(userJson); JsonNode userNo = jsonNode.get("userNo"); System.out.println("userNo(get from jsonNode):" + userNo.textValue());}
单元测试调用代码如下:
@Testvoid readJson() throws Exception { String userJson = "{\"userNo\":\"1000\",\"username\":\"Tom\",\"age\":18,\"createDate\":\"2019-12-31 05:12:42" + "\"}"; mockMvc.perform( MockMvcRequestBuilders.post("/readJson").param("userJson",userJson) );}
其中,当采用树遍历时,JSON被读入到JsonNode对象中,可以像操作XML DOM那样读取JSON。readTree方法实现重载了接受字符串、字节数组、文件、InputStream等多种数据格式。
关于ObjectMapper的自定义及使用本篇文章就讲解到这里,后面继续讲解其他相关功能。
相关源代码:https://github.com/secbr/springboot-all/tree/master/springboot-json