一.前言
1.介绍
- 我们常在项目中使用的Json转换工具是
fastjson
,事实上spring本身集成了非常优秀的json工具,分别为Jackson
,Gson
,JSON-B
,但是官方项目中默认推荐使用Jackson,所以本文着重介绍使用Jackson进行json的转换以及Jackson的注解使用
2.项目例子
- 此文章用到的例子在spring-boot项目中,传送门
- 此篇文章用到项目模块:
- 还有更多:spring-cloud项目
3.进阶文档
- spring-boot-json这是spring-boot官方介绍,寥寥数笔,所以我们还需要查看jackson的分项目jackson-annotations来了解具体用法
二.Jackson在Controller中的应用
1.基本介绍
- 在Controller中使用
@RestController
,默认方法接口返回json,在返回前使用Jackson将对象序列化为json,返回方法中可以省略@ResponseBody
;当在形参中使用@RequestBody
,默认使用Jackson将json反序列化为对象。
2.范例
- 创建对象
class User { private String userAccount; private String password; private int age; private Date birthday; ...省略Getter和Setter }
- 创建Controller
@RestController public class SpringBootJsonController { @PostMapping("testJson") public User testJson(@RequestBody User user){ return user; } }
@RestController
:标定使用Rest风格,此注解包含了@Controller
和@ResponseBody
,所有类中所有接口都不需要再标注@ResponseBody
@RequestBody
:表示使用Jackson将接收到的json字符串反序列化为对象- 在此方法中我们将接收的对象原样返回
- 在测试类中进行测试
@RunWith(SpringRunner.class) @SpringBootTest @AutoConfigureMockMvc public class SpringBootJsonControllerTest { @Autowired private MockMvc mvc; @Autowired private ObjectMapper objectMapper; @Test public void testJson() throws Exception { User user = new User(); user.setAge(12); user.setBirthday(new Date()); user.setUserAccount("Joey"); user.setPassword("Joey's password"); String s = objectMapper.writeValueAsString(user); this.mvc.perform(post("/testJson").content(s.getBytes()).contentType(MediaType.APPLICATION_JSON_VALUE)).andExpect(status().isOk()).andExpect(content().string(containsString("Joey's password"))).andDo(print()); } }
@RunWith(SpringRunner.class)
:@RunWith
是一个JUnit4的注解,表明测试运行器@SpringBootTest
:加载Web ApplicationContext
并提供模拟Web环境- 在测试类上添加
@AutoConfigureMockMvc
标定自动装配MockMvc
,代码中注入MockMvc
,模拟外部请求 - 注入
ObjectMapper
是Jackson对外工具类,提供了Jackson序列化和反序列化json的全套服务 - 注意一点,在模拟请求的时候添加
contentType(MediaType.APPLICATION_JSON_VALUE)
,此方法会在请求头中添加如下健值Content-Type:"application/json;charset=UTF-8"
,用来想接口表明请求主题类型为json - 关于测试更多的详情,可见Spring Boot中单元测试详解
- 运行测试类,可见如下详情
MockHttpServletRequest: HTTP Method = POST Request URI = /testJson Parameters = { } Headers = [Content-Type:"application/json;charset=UTF-8"] Body = { "userAccount":"Joey","password":"Joey's password","age":12,"birthday":"2019-08-05T07:43:48.666+0000"} Session Attrs = { } Handler: Type = com.friends.springbootjson.SpringBootJsonController Method = public com.friends.springbootjson.User com.friends.springbootjson.SpringBootJsonController.testJson(com.friends.springbootjson.User) Async: Async started = false Async result = null Resolved Exception: Type = null ModelAndView: View name = null View = null Model = null FlashMap: Attributes = null MockHttpServletResponse: Status = 200 Error message = null Headers = [Content-Type:"application/json;charset=UTF-8"] Content type = application/json;charset=UTF-8 Body = { "userAccount":"Joey","password":"Joey's password","age":12,"birthday":"2019-08-05T07:43:48.666+0000"} Forwarded URL = null Redirected URL = null Cookies = []
三.Jackson注解:与序列化有关的注解
@JsonAnyGetter
注解,将拓展的map映射到实体类上
实体类
我们的测试类class UserJsonAnyGetter { private String userName; private Map<String, String> properties; @JsonAnyGetter public Map<String, String> getProperties() { return properties; }
运行返回,可见map中的key和value都映射到了实体类中@Test public void testJsonAnyGetter() throws Exception { UserJsonAnyGetter ujg = new UserJsonAnyGetter(); ujg.setUserName("Rose"); Map<String, String> properties = new HashMap<>(); properties.put("character1","geeky brother"); properties.put("character2","biologist"); ujg.setProperties(properties); String result = new ObjectMapper().writeValueAsString(ujg); System.out.println(result); assertThat(result,containsString("character1")); assertThat(result,containsString("character2")); }
{ "userName":"Rose","character2":"biologist","character1":"geeky brother"}
@JsonGetter
注解,此注解在getter方法中可替代@JsonProperty注释,替换json的key值,@JsonProperty后文有讲解
实体类
我们的测试类class UserJsonGetter { private String userName; private Integer id; @JsonGetter("name") public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; }
运行返回,可见userName使用了我们自定义的name@Test public void testUserJsonGetter() throws JsonProcessingException { final UserJsonGetter ujg = new UserJsonGetter("Joey",1); final String result = new ObjectMapper().writeValueAsString(ujg); System.out.println(result); assertThat(result, containsString("Joey")); assertThat(result, containsString("1")); }
{ "id":1,"name":"Joey"}
@JsonPropertyOrder
注解,此注解可以指定序列化的顺序
实体类
我们的测试类@JsonPropertyOrder({ "id","userName" }) class UserJsonPropertyOrder { private String userName; private Integer id;
@Test public void testUserJsonPropertyOrder() throws JsonProcessingException { final UserJsonPropertyOrder ujg = new UserJsonPropertyOrder("Joey",1); final String result = new ObjectMapper