SpringBoot基础篇(一)默认转换工具Jackson

Spring Boot 内置了jackson来完成JSON的序列化和反序列化操作。Jackson使用ObjectMapper类将POJO对象序列化成JSON字符串,也能将JSON字符串反序列化成POJO对象。

JackSon支持三种层次的序列化和反序列化方式:

  • 采用JsonParser来解析JSON,解析结果是一串Tokens,采用JsonGenerator来生成JSON,这是最底层的方式。
  • 采用树遍历方式,JSON被读入到JsonNode对象中,可以像操作XML DOM那样读取JSON。
  • 采用DataBind方式,将POJO序列化成JSON,或者反序列化到POJO,这是最直接和最简单的一种方式,不过有时候需要辅助Jackson的注解或者上述序列化实现类来个性化序列化和反序列化操作。

1.对象绑定

应用程序更常见的是使用Java对象来与JSON数据互相绑定,仅仅调用ObjectMapper的readValue来实现,我们现在举个例子,可以创建一个POJO对象来与JSON相对应,POJO类如下:

public class User {
    Long id;
    String name;
    public Long getId() {return id;}
    public void setId(Long id) {this.id = id;}
    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
}

(1)使用readValue方法来反序列化上面的JSON字符串,即json转换为对象:

    @Autowired
    private ObjectMapper mapper;
    @GetMapping("/dataBind.json")
    public @ResponseBody String dataBind() throws IOException{
        String json = "{"name":"lijz","id":10}";
        User user = mapper.readValue(json, User.class);
        return "name:"+user.getName()+",id:"+user.getId();
      }

 (2)将POJO序列化成JSON,使用mapper的writeValueAsString方法

@Autowired
private ObjectMapper mapper;
@GetMapping("/serialization.json")
    public @ResponseBody String dataBind() throws IOException{
    User user = new User();
    user.setName("scg");
    user.setId((long) 18);
    String jsonStr = mapper.writeValueAsString(user);
    return jsonStr;
}

(3)json转集合

 json转集合比较麻烦,因为你无法同时把集合的class和元素的class同时传递到一个参数。因此Jackson做了一个类型工厂,用来解决这个问题:​​​​​​​

// json处理工具
private ObjectMapper mapper = new ObjectMapper();
@Test
public void testJson() throws IOException {
    User user = new User();
    user.setId(8L);
    user.setAge(21);
    user.setName("柳岩");
    user.setUserName("liuyan");
    // 序列化,得到对象集合的json字符串
    String json = mapper.writeValueAsString(Arrays.asList(user, user));
    // 反序列化,接收两个参数:json数据,反序列化的目标类字节码
    List users = mapper.readValue(json,         mapper.getTypeFactory().constructCollectionType(List.class, User.class));
    for (User u : users) {
        System.out.println("u = " + u);
    }
}

 

 (4)json转任意复杂类型

 当对象泛型关系复杂时,类型工厂也不好使了。这个时候Jackson提供了TypeReference来接收类型泛型,然后底层通过反射来获取泛型上的具体类型。实现数据转换。​​​​​​​

// json处理工具
private ObjectMapper mapper = new ObjectMapper();
@Test
public void testJson() throws IOException {
    User user = new User();
    user.setId(8L);
    user.setAge(21);
    user.setName("柳岩");
    user.setUserName("liuyan");

    // 序列化,得到对象集合的json字符串
    String json = mapper.writeValueAsString(Arrays.asList(user, user));
    // 反序列化,接收两个参数:json数据,反序列化的目标类字节码
    List users = mapper.readValue(json, new TypeReference>(){});
    for (User u : users) {
        System.out.println("u = " + u);
    }

}

 

2.Jackson 注解

Jackson包含了很多注解,用来个性化序列化和反序列化操作,主要有如下注解。

(1)@JsonProperty,作用在属性上,用来为JSON Key指定一个别名。​​​​​​​

@JsonProperty("userName")
private String name;

 (2)@JsonIgnore,作用在属性上,用来忽略此属性。

@JsonIgnore
private String age;

(3)@JsonIgnoreProperties,忽略一组属性,作用于类上

@JsonIgnoreProperties({"id","photo"})
public class User {}

(4)@JsonFormat,用于日期格式化。

@JsonFormat(pattern = "yyyy-MM-dd HH-mm-ss")
private Date d;

(5)@JsonView,作用在类或者属性上,用来定义一个序列化组。Spring MVC的Controller方法可以使用同样的@JsonView来序列化属于这一组的配置。比如对于User对象,某些情况下只返回id属性就行,而某些情况下需要返回id和名称。代码如下:​​​​​​​

public class User {
    public interface IdView{};
    public interface IdNameView extends IdView{};
    @JsonView(IdView.class)
    private Integer id;
    @JsonView(IdNameView.class)
    private String name;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
/**
* controller
*/
@JsonView(User.IdView.class)
@RequestMapping("/id.json")
public @ResponseBody User queryIds(){
    User user = new User();
    user.setId(1);
    user.setName("scg");
    return user;
}

(6)@JsonSerialize,指定一个实现类来自定义序列化。类必须实现JsonSerializer接口

3.jack工具类

(1)引入相关包​​​​​​​




    org.springframework.boot
    spring-boot-starter-logging



    com.fasterxml.jackson.core
    jackson-databind
    2.9.6
    compile

(2)jack工具类​​​​​​​

package cn.jun.common.utils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//Nullable需要引入spring-web包
import org.springframework.lang.Nullable;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* jack处理json相关的工具类
* @create: 2018-04-24 17:20
**/
public class JsonUtils {
    public static final ObjectMapper mapper = new ObjectMapper();
    //需要引入spring-boot-starter-logging包
    private static final Logger logger = LoggerFactory.getLogger(JsonUtils.class);
    /**
    * 对象转换为json字符串
    * @param obj
    * @return
    */
    @Nullable
    public static String toString(Object obj) {
        if (obj == null) {
            return null;
        }
        if (obj.getClass() == String.class) {
            return (String) obj;
        }

        try {
            return mapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            logger.error("json序列化出错:" + obj, e);
            return null;
        }
     }
    @Nullable
    public static  T toBean(String json, Class tClass) {
        try {
            return mapper.readValue(json, tClass);
         } catch (IOException e) {
            logger.error("json解析出错:" + json, e);
            return null;
         }
    }
    @Nullable
    public static  List toList(String json, Class eClass) {
        try {
            return mapper.readValue(json,         mapper.getTypeFactory().constructCollectionType(List.class, eClass));
        } catch (IOException e) {
            logger.error("json解析出错:" + json, e);
            return null;
        }
    }
    @Nullable
    public static  Map toMap(String json, Class kClass, Class vClass) {
        try {
            return mapper.readValue(json, mapper.getTypeFactory().constructMapType(Map.class, kClass, vClass));
        } catch (IOException e) {
            logger.error("json解析出错:" + json, e);
            return null;
        }
    }
    @Nullable
    public static  T nativeRead(String json, TypeReference type) {
         try {
             return mapper.readValue(json, type);
         } catch (IOException e) {
             logger.error("json解析出错:" + json, e);
             return null;
         }
    }
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    class User{
        private String name;
        private Integer age;
    }
    public static void main(String[] args) {
        String json="{\"namge\":\"zhuxinjun\",\"age\":\"21\"}";
        Map map = toMap(json, String.class, String.class);
        System.out.println("map:"+map);
        String j="[{\"namge\":\"zhuxinjun\",\"age\":\"21\"},            {\"namge\":\"yangyang\",\"age\":\"32\"}]";
        List> maps = nativeRead(j, new TypeReference>>() {
        });
        for(Map map1:maps){
        System.out.println("map1"+map1);
     }
    }
}

4、ObjectMapper对象和JsonNode对象

        ObjectMapper可以让对象与JSON之间相互转换,除此之外Jackson还提供了JsonGenerator 和JsonParser 这两个类,它们可以更细粒度化。调用ObjectMapper的writeValueAsString()和readValue()方法,最终还是会交给JsonGenerator和JsonParser去处理。

     ObjectMapper类是Jackson库的主要类。Jackson ObjectMapper可以从字符串、流或文件中解析JSON,并创建表示解析JSON的Java对象或对象图。将JSON解析为Java对象也被称为从JSON反序列化Java对象。Jackson ObjectMapper还可以从Java对象创建JSON。从Java对象生成JSON也被称为将Java对象序列化成JSON。Jackson对象映射器可以将JSON解析为由您开发的类的对象,或者为内置JSON树模型的对象中

 

​​​​​
【ObjectMapper对象构造函数说明】

(1)ObjectMapper()无参构造函数:默认的构造函数,这将构建默认JsonFactory必要时使用StdSerializerProvider作为其SerializerProvider,并BeanSerializerFactory作为其SerializerFactory。

(2)ObjectMapper(JsonFactory jf)构造函数:构造使用指定的JsonFactory构建必要的JsonParsers和/或JsonGenerators映射。

(3)ObjectMapper(JsonFactory jf, SerializerProvider sp, DeserializerProvider dp)

(4)ObjectMapper(JsonFactory jf, SerializerProvider sp, DeserializerProvider dp, SerializationConfig sconfig, DeserializationConfig dconfig)

(5)ObjectMapper(SerializerFactory sf) 不推荐使用。使用其他构造来代替; 注意,可以设置序列化工厂。

JsonNode对象就是JackJson的树模型,ObjectMapper构建JsonNode节点树。这是最灵活的方法。它类似于DOM解析器的XML。

5、JackJson处理复杂类型

Jackson处理复杂类型(List,map)方法,这里先写一个demo:

String jsonString="[{'id':'1'},{'id':'2'}]";
ObjectMapper mapper = new ObjectMapper();
JavaType javaType = mapper.getTypeFactory().constructParametricType(List.class, Bean.class);
//如果是Map类型 mapper.getTypeFactory().constructParametricType(HashMap.class,String.class, Bean.class);
List lst = (List)mapper.readValue(jsonString, javaType);

下面就来拿具体的业务场景说明,我们有一个第三方API想要从中获取API的数据,然后对其数据进行解析

【api数据】

{
    "odata.metadata": 
    "http://datamall2.mytransport.sg/ltaodataservice/$metadata#IncidentSet",
    "value": [{
            "Type": "Roadwork",
            "Latitude": 1.3337348070912667,
            "Longitude": 103.81727763683823,
            "Message": "(7/1)9:32 Roadworks on Adam Road (towards Braddell) after PIE. Avoid left lane."
        },
        {
            "Type": "Heavy Traffic",
            "Latitude": 1.2705379265448862,
            "Longitude": 103.85916664583904,
            "Message": "(7/1)9:32 Heavy Traffic on MCE (towards ECP) at Central Boulevard Exit."
        }
      ]
}

【定义一个类,用来接收API数据】

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.Serializable;
import java.util.List;

public class DataMallResult implements Serializable {

    // 定义jackson转换器ObjectMapper,并实例化ObjectMapper对象
    private static final ObjectMapper MAPPER = new ObjectMapper();
    @JsonProperty("odata.metadata")
    private String metadata;
    //响应数据
    private Object value;
    //无参构造
    public DataMallResult() {
    }
    public DataMallResult(Object value) {
        this.value = value;
    }
    public DataMallResult(String metadata, Object value) {
        this.metadata = metadata;
        this.value = value;
    }
    /**
    * 自定义静态构造方法
    */
    public static DataMallResult build(String metadata, Object value){
        return new DataMallResult(metadata,value);
    }
    /**
    * @param jsonData json数据
    * @param clazz 集合中的类型
    * @return
    */
    public static DataMallResult formatToList(String jsonData, Class clazz){
        try {
            //ObjectMapper构建JsonNode节点树,ObjectMapper对象readTree()方法也就是从json创建树
            JsonNode jsonNode = MAPPER.readTree(jsonData);
            //获得jackson树节点下的value
            JsonNode data = jsonNode.get("value");

            Object obj = null;

            if (data.isArray() && data.size() > 0) {
                //MAPPER.getTypeFactory().constructCollectionType(List.class, clazz)就是    JavaType,获得java类型
                //把Jackson树转换为对象
            obj =  MAPPER.readValue(data.traverse(),MAPPER.getTypeFactory().constructCollectionType(List.class, clazz));
            }
        //jsonNode.get("status").intValue()
        return build(jsonNode.get("odata.metadata").asText(),obj);
        } catch (Exception e) {
            return null;
        }
    }
//---------------------get和setter方法-----------------------
    public Object getValue() {
        return value;
    }
    public void setValue(Object value) {
        this.value = value;
    }

}

【解析数据】​​​​​​​

#其中reJson是api中json字符串数据

DataMallResult dataMallResult = DataMallResult.formatToList(reJson, IncidentsVo.class);

List incidentsVoList=(List) dataMallResult.getValue();

【IncidentsVo 对象】

 
@Data
@NoArgsConstructor
@AllArgsConstructor
public class IncidentsVo implements Serializable{

    @JsonProperty("Type")
    private String Type;

    @JsonProperty("Latitude")
    private Double Latitude;

    @JsonProperty("Longitude")
    private Double Longitude;

    @JsonProperty("Message")
    private String Message;

}

 

你可能感兴趣的:(spring,json)