4. Jackson

写在开头,在MVC框架中,Spring Boot 内置了 Jackson 来完成JSON的序列化和反序列化。

  • @ResponseBody 在Controller对应请求方法上就好了,自动将方法返回的对象序列化成JSON。
  • 序列化、反序列化方式
    Jackson是一个流行的高性能JavaBean到JSON的绑定工具,Jackson使用ObjectMapper类将POJO对象序列化成JSON字符串,也能将JSON字符串反序列化成POJO对象。

方式

说明

JsonParser

采用JsonParser来解析JSON,解析结果是一串Tokens。

采用JSONGenerator来生成JSON,最底层方式。

树遍历 (Tree Traversing)

JSON被读入到JsonNode对象中,可以像操作XML DOM那样读取JSON

DataBind

数据绑定方式,最简单直接的一种方式。

有时候需要相关注解或序列化实现类来进行个性化序列化等操作

对应用程序来讲,最常用的方式是DataBind,也就是将POJO对象转换成JSON字符串,或者解析JSON字符串并映射到POJO对象上。
那么,如果没有现成的POJO对象做数据绑定的时候,也可以通过树遍历的方式来获取JSON数据。

  • Jackson 树遍历(Tree Traversing)
    树遍历方式通常适合没有POJO对象的JSON。
@Autowired ObjectMapper mapper;

  @GetMapping("/readtree.json")
  public @ResponseBody String readtree() throws JsonProcessingException, IOException {
  	String json = "{\"name\":\"zhangsan\", \"id\":10}";
  	// JSON序列化
  	JsonNode node = mapper.readTree(json);
  	// 获取序列化结果
  	String name = node.get("name").asText();
  	int id = node.get("id").asInt();
  	return "name" + name + ",id" + id;
  }

readTree 方法可以接受一个字符串或者字节数组、文件、inputStream等,返回JsonNode作为根结点。
关于读取数据,JsonNode支持以下方法读取序列化后的JSON数据:

  • axXXX:for example,asText、asBoolean、asInt etc… 读取JsonNode对应的值。
  • isArray:判断JsonNode是否是数组,如果是数组,则可以调用 get(i) 来进行遍历。
  • get(“key”):获取当前节点的子节点,返回JsonNode。
    注:JSON规范要求key是字符串,且要使用双引号。
  • ObjectMapper 序列化和反序列化
  • 序列化 POJO to JSON
User user = mapper.readValue(json, User.class);
  • 反序列化 JSON to POJO
String json = mapper.writeValueAsString(user);
  • 树模型和数据绑定都是基于流失操作完成的,即通过JsonParser类解析JSON,形成JsonToken流。
  • JsonParser 的解析结果包含了一些列JsonToken,JsonToken是一个枚举类型。列举常用的常量:

枚举常量

说明

START_OBJECT

{

END_OBJECT

}

START_ARRAY

[

END_ARRAY

]

FIELD_NAME

JSON key

VALUE_STRING

JSON value 字符串类型

VALUE_NUMBER_INT

JSON value 整型

序列化简易流程:

// 模拟JSON数据,Map形式 
  String json = "{\"name\":\"zhangsan\"}";
  // 定义暂存数据变量
  String key = null, value = null;
  /**
  * 开始解析JSON
  */ 	
  JsonFactory f = mapper.getFactory();
  JsonParser parser = f.createParser(json);
  // { -> START_OBJECT,忽略第一个Token
  JsonToken token = parser.nextToken();
  token = parser.nextToken();
  // JSON key  -> FIELD_NAME 保存至暂存数据变量key中
  if(token == JsonToken.FIELD_NAME) {
  	key = parser.getCurrentName();
  }
  token = parser.nextToken();
  // JSON value -> VALUE_STRING 保存至暂存数据变量value中
  value = parser.getValueAsString();
  // 关闭 parser
  parser.close();
  return key + " : " + value;

判断Token类型后,通过getValueAsXXX获取其值,XXX是其值的类型。
反序列化简易流程:

JsonFactory f = mapper.getFactory();
  // 输出到 StringWriter
  StringWriter sw = new StringWriter();
  JsonGenerator g = f.createGenerator(sw);
  // 输出 {
  g.writeStartObject();
  // 输出数据
  g.writeStringField(key, value);
  // 输出 }
  g.writeEndObject();
  // 关闭 StringWriter
  g.colse();
  retrun sw.toString();
  • Jackson 常用注解

注解

说明

实例

@JsonProperty

作用在属性上,为JSON Key指定别名

@JsonProperty(“userName”)

private String name;

@JsonIgnore

作用在属性上,用来忽略此属性

@JsonIgnore

private String password;

@JsonIgnoreProperties

作用于类上,忽略一组属性

@JsonIgnoreProperties({“id”, “phone”})

public static class SamplePojo{…}

@JsonFormat

日期格式化

@JsonFormat(pattern = “yyyy-MM-dd”)

private Date date;

补充不常用注解:
@JsonSerialize 指定一个实现类来自定义序列化,类必须继承JsonSerializer

public static class UserSerializer extends JsonSerializer<User> {
  @Override
  public void serialize(User user, JsonGenerator jsonGenerator,
                        SerializerProvider serializerProvider) throws IOException {
    jsonGenerator.writeStartObject();
    jsonGenerator.writeStringField("user_name", user.getName());
    jsonGenerator.writeEndObject();
  }
}

JsonGenerator 对象是 Jackson 底层的序列化实现,上述代码中对name属性做了序列化,输出key形式上变更为:user_name。
使用@JsonSerialize注解需要制定对象的序列化方式,例如:

@JsonSerialize(using = UserSerializer.class)
public class User {
  ...
}

同样的,自定义反序列化,需要通过反序列化实现类继承JsonDeserializer,使用@JsonDeserialize注解制定对象反序列化方式。
@JsonView,作用在类或者属性上,用来序列化组。Spring MVC的Controller方法可以使用同样的@JsonView来序列化属于本组的设置。
对于User对象,有些情况下只需要返回id属性,有些情况需要返回id和name,因此User对象可以定义为如下:

public class User {
  public interface IdView {};
  public interface IdNameView extends IdView {};
  
  @JsonView(IdView.class)
  private Integer id;
  @JsonView(IdNameView.class)
  private String name;
  @JsonIgnore
  BigDecimal salary;
}

User定义了两个接口类,IdView、IdNameView(继承IDView接口)。这两个接口代表了两个序列化组的名称。
Spring MVC 的Controller方法运行使用@JsonView()指定一个序列化组名,被序列化的对象只有在该序列组中的属性才会被序列化。

@JsonView(User.IdView.class)
@RequestMapping("/id.json")
public @ResponseBody User queryIds() {
  User user = new User();
  user.setId(1);
  user.setName("hello");
  return user;
}

上述代码,只会输出id属性内容。更换成@JsonView(User.IdNameView.class)将输出id和name,因为组名IdView是IdNameView的父类。

  • 集合的反序列化
    Spring MVC的Controller方法中,可以对参数列表使用@RequestBody注解,将提交的JSON自动映射到方法参数上。
    注意是@RequestBody,是@RequestBody,是@RequestBody,不是@ResponseBody
@RequestMapping("/addUser.json")
public @ResponseBody String addUser(@RequestBody User user) {
  ...
  return user.toString();
}

通过Postman进行接口调用的时候需要注意:接收的是JSON请求

springboot json串转实体 springboot json转对象_JSON