Jackson 是当前用的比较广泛的,用来序列化和反序列化 json 的 Java 的开源框架。Jackson 社 区相对比较活跃,更新速度也比较快, 从 Github 中的统计来看,Jackson 是最流行的 json 解析器之一 。 Spring MVC 的默认 json 解析器便是 Jackson。 Jackson 优点很多。 Jackson 所依赖的 jar 包较少 ,简单易用。与其他 Java 的 json 的框架 Gson 等相比, Jackson 解析大的 json 文件速度比较快;Jackson 运行时占用内存比较低,性能比较好;Jackson 有灵活的 API,可以很容易进行扩展和定制。
Jackson 的 1.x 版本的包名是 org.codehaus.jackson ,当升级到 2.x 版本时,包名变为 com.fasterxml.jackson,本文讨论的内容是基于最新的 Jackson 的 2.10.1 版本。
------------------------ start ------------------------
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.1</version>
</dependency>
------------------------ end ------------------------
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provided</scope>
</dependency>
jackson-databind
依赖 jackson-core
和 jackson-annotations
,当添加 jackson-databind
之后, jackson-core
和 jackson-annotations
也随之添加到 Java 项目工程中。在添加相关依赖包之后,就可以使用 Jackson。
Jackson 最常用的 API 就是基于“对象绑定”的 ObjectMapper
。下面是一个 ObjectMapper 的使用的简单示例。
这个例子中涉及三个类 Person、Address、PhoneNumber
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PhoneNumber {
private String code;
private String number;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Address {
private String city;
private String street;
}
@Data
public class Person {
private String firstName;
private String lastName;
private Address address;
private List<PhoneNumber> phoneNumberList;
}
/**
* 入门示例
*/
@Test
void objectMapper() throws JsonProcessingException {
// 实例化 ObjectMapper 对象
ObjectMapper objectMapper = new ObjectMapper();
// 将对象转成 json
String objectToJson = objectMapper.writeValueAsString(newPerson());
System.out.println(objectToJson);
// 将 json 转成对象
Person person = objectMapper.readValue(objectToJson, Person.class);
System.out.println(person);
}
private static Person newPerson() {
List<PhoneNumber> phoneNumberList = new ArrayList<>();
phoneNumberList.add(new PhoneNumber("86", "0411-12345678"));
phoneNumberList.add(new PhoneNumber("86", "12312412323"));
Address address = new Address("Foshan", "Chancheng");
Person person = new Person();
person.setFirstName("Chen");
person.setLastName("Ray");
person.setAddress(address);
person.setPhoneNumberList(phoneNumberList);
return person;
}
ObjectMapper 通过 writeValue
系列方法将 java 对象序列化为 json,并将 json 存储成不同的格式。
ObjectMapper 通过 readValue
系列方法从不同的数据源像将 json 反序列化为 java 对象。
{"firstName":"Chen","lastName":"Ray","phoneNumberList":[{"code":"86","number":"0411-12345678"},{"code":"86","number":"12312412323"}]}
Person(firstName=Chen, lastName=Ray, address=null, phoneNumberList=[PhoneNumber(code=86, number=0411-12345678), PhoneNumber(code=86, number=12312412323)])
ObjectMapper 也提供了下面的 writeValue 方法,帮助我们很方便的将对象输出到不同的目的地。
writeValue(File resultFile, Object value)
writeValue(OutputStream out, Object value)
writeValue(DataOutput out, Object value)
writeValue(Writer w, Object value)
writeValueAsString(Object value)
writeValueAsBytes(Object value)
ObjectMapper 提供了下面的 readValue 方法,帮助我们很方便的从不同的数据源读取对象。
readValue(File src, Class<T> valueType)
readValue(URL src, Class<T> valueType)
readValue(String content, Class<T> valueType)
readValue(Reader src, Class<T> valueType)
readValue(InputStream src, Class<T> valueType)
readValue(byte[] src, Class<T> valueType)
readValue(DataInput src, Class<T> valueType)
我们还可以读取 JSON 到数组(Array),列表(List)和映射(Map)中,下面是三个简单的例子。
/**
* 读取 JSON 到数组(Array)
*/
@Test
void readJsonToArray() throws JsonProcessingException {
// 实例化 ObjectMapper 对象
ObjectMapper objectMapper = new ObjectMapper();
// 准备的 json
String json = "[{\"firstName\":\"Bo\",\"lastName\":\"Shang\"}, {\"firstName\":\"San\",\"lastName\":\"Zhang\"}]";
// 将 json 转成数组
Person[] people = objectMapper.readValue(json, Person[].class);
for (Person p :
people) {
System.out.println(p);
}
}
/**
* 读取 JSON 到列表(List)
*/
@Test
void readJsonToList() throws JsonProcessingException {
// 实例化 ObjectMapper 对象
ObjectMapper objectMapper = new ObjectMapper();
// 准备的 json
String json = "[{\"firstName\":\"Bo\",\"lastName\":\"Shang\"}, {\"firstName\":\"San\",\"lastName\":\"Zhang\"}]";
// 将 json 转成列表
List<Person> people = objectMapper.readValue(json, new TypeReference<List<Person>>() {});
for (Person p :
people) {
System.out.println(p);
}
}
/**
* 读取 JSON 到映射(Map)
*/
@Test
void readJsonToMap() throws JsonProcessingException {
// 实例化 ObjectMapper 对象
ObjectMapper objectMapper = new ObjectMapper();
// 准备的 json
String json = "{\"firstName\":\"Bo\",\"lastName\":\"Shang\"}";
// 将 json 转成映射
Map<String, Object> map = objectMapper.readValue(json, new TypeReference<Map<String, Object>>() {});
System.out.println(map);
}
如果在读写 JSON 时,我们想忽略某些字段,我们可以使用下面的注解。
这个注解是用在字段上,get或者set方法上,效果都是一样的,用来在实体类序列化和反序列化的时候忽略该字段字段。
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
@JsonIgnore
private String username;
private String password;
private Integer age;
}
测试接口
@RestController
public class UserController {
@RequestMapping("/test")
public User test(@RequestBody User u) {
if (u != null) {
return u;
}
User user = new User();
user.setUsername("Ray");
return user;
}
}
访问这个接口返回的参数就不包含username这个字段了
{
"password": null,
"age": null
}
然而我们访问这个接口带过去的参数username这个字段也不会反序列化
{
"username" : "小明",
"password" : "123",
"age" : 15
}
反序列化username属性为空,结果如下:
{
"password": "123",
"age": 15
}
由此可见当我们需要在序列化和反序列化的时候忽略某个字段的时候就用这个注解加在字段上面就行了。
这个注解跟 @JsonIgnore
的效果是一样的,区别就是这个注解是用在类上面的,在需要的注解比较多的情况下,用来一次性定义忽略的字段。
@JsonIgnoreProperties({"username","password"})
public class User {
private String username;
private String password;
private Integer age;
}
这样子useranme和password这两个字段在序列化和反序列化的时候就都忽略了。
{
"age": null
}
还有一个用法就是配合allowGetters,allowSetters一起用用来控制字段忽视是在序列化还是反序列化,这样更加灵活,如下所示
//allowGetters为true的时候说明字段允许序列化,反序列的时候忽略该字段
@JsonIgnoreProperties(value = {"usname","password"},allowGetters = true)
public class User {
private String username;
private String password;
private Integer age;
}
//allowSetters为true说明字段允许反序列化,序列化的时候忽略该字段
@JsonIgnoreProperties(value = {"usname","password"},allowSetters = true)
public class User {
private String username;
private String password;
private Integer age;
这样一个类,如果 json 字符串中的字段数量与类的字段不匹配,这里多了一个 first
,如:
// 准备的 json
String json = "[{\"firstName\":\"Bo\",\"first\":\"B\",\"lastName\":\"Shang\"}, {\"firstName\":\"San\",\"lastName\":\"Zhang\"}]";
准备的实体类,缺少 first 属性
@Data
public class Person {
private String firstName;
private String lastName;
private Address address;
private List<PhoneNumber> phoneNumberList;
private Date birthday;
}
此时就会出现UnrecognizedPropertyException
异常,大致意思是未识别到 first
属性,没有匹配到忽略的标记:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "first" (class io.ray.jackson.entity.Person), not marked as ignorable (4 known properties: "lastName", "firstName", "phoneNumberList", "birthday"])
at [Source: (String)"[{"firstName":"Bo","first":"B","lastName":"Shang"}, {"firstName":"San","lastName":"Zhang"}]"; line: 1, column: 29] (through reference chain: java.lang.Object[][0]->io.ray.jackson.entity.Person["first"])
给 Person 类增加注解,忽略未知错误:
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class Person {
private String firstName;
private String lastName;
private Address address;
private List<PhoneNumber> phoneNumberList;
private Date birthday;
}
问题就解决了。
这个注解是用在类上面的表明这个类在序列化和反序列化的时候被忽略,此时的 Address 为 null。
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreType
public class Address {
private String city;
private String street;
}
前端的同事要求说尽量不要有null,可有为空串“” 或者 0 或者 [], 但尽量不要null。
所以@JsonInclude(Include.NON_NULL)
这个注解放在类头上就可以解决。
实体类与json互转的时候 属性值为null的不参与序列化。
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class User {
private String username;
private String password;
private Integer age;
}
测试示例
/**
* 忽略空字段
*/
@Test
void nonEmpty() throws JsonProcessingException {
// 实例化 ObjectMapper 对象
ObjectMapper objectMapper = new ObjectMapper();
// 将对象转成 json
String json = objectMapper.writeValueAsString(newUser());
System.out.println(json);
}
private static User newUser() {
User user = new User();
user.setUsername("Ray");
user.setAge(18);
//user.setPassword("123456");
return user;
}
{"username":"Ray","password":null,"age":18}
-------------- 使用前后对比 --------------
{"username":"Ray","age":18}
如果 JSON 和对象字段名不匹配,我们可以使用注解 @JsonGetter 和 @JsonSetter
实体类,注解用于 getter 和 setter 方法上。
@ToString
public class PersonTwo {
private String firstName;
private String lastName;
private Date birthday;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@JsonGetter("age")
public Date getBirthday() {
return birthday;
}
@JsonSetter("age")
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
测试示例
/**
* 修改字段名
*/
@Test
void updateFiled() throws JsonProcessingException {
// 实例化 ObjectMapper 对象
ObjectMapper objectMapper = new ObjectMapper();
// 将对象转成 json
String json = objectMapper.writeValueAsString(newPersonTwo());
System.out.println(json);
// 将 json 转成对象
PersonTwo personTwo = objectMapper.readValue(json, PersonTwo.class);
System.out.println(personTwo);
}
private static PersonTwo newPersonTwo() {
PersonTwo personTwo = new PersonTwo();
personTwo.setFirstName("Chen");
personTwo.setLastName("Ray");
personTwo.setBirthday(new Date());
return personTwo;
}
// birthday --> age
{"firstName":"Chen","lastName":"Ray","age":1582447798458}
// toString
PersonTwo(firstName=Chen, lastName=Ray, birthday=Sun Feb 23 16:49:58 CST 2020)
默认情况下,字段的输出顺序和它们在类中的位置一致,我们也可以使用注解 @JsonPropertyOrder
自己指定顺序。
@ToString
@Data
@JsonPropertyOrder({"lastName", "birthday", "firstName"})
public class PersonTwo {
private String firstName;
private String lastName;
private Date birthday;
}
// 指定输出顺序
{"lastName":"Ray","birthday":1582449375241,"firstName":"Chen"}
// toString
PersonTwo(firstName=Chen, lastName=Ray, birthday=Sun Feb 23 17:16:15 CST 2020)
如果一个对象中某个字段中的值是 JSON,输出整个对象会有问题,这时我们可以使用注解 @JsonRawValue
,无转换的将属性值写入到json 字符串中。
@Data
public class PersonThree {
private String firstName;
private String lastName;
@JsonRawValue
private String address;
}
/**
* 输出 JSON 字段
*/
@Test
void outputFiled() throws JsonProcessingException {
// 实例化 ObjectMapper 对象
ObjectMapper objectMapper = new ObjectMapper();
// 将对象转成 json
String json = objectMapper.writeValueAsString(newPersonThree());
System.out.println(json);
}
private static PersonThree newPersonThree() {
PersonThree personThree = new PersonThree();
personThree.setFirstName("Chen");
personThree.setLastName("Ray");
personThree.setAddress("{\"country\":\"China\", \"city\":\"Gd\"}");
return personThree;
}
{"firstName":"Chen","lastName":"Ray","address":{"country":"China", "city":"Gd"}}
如果你想自定义输出的格式,我们可以使用注解 @JsonValue
public class PersonFour {
private String firstName;
private String lastName;
@JsonValue
@Override
public String toString() {
return "PersonFour{" +
"firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
'}';
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
/**
* 自定义输出格式
*/
@Test
void jsonValue() throws JsonProcessingException {
// 实例化 ObjectMapper 对象
ObjectMapper objectMapper = new ObjectMapper();
// 将对象转成 json
String json = objectMapper.writeValueAsString(newPersonFour());
System.out.println(json);
}
private static PersonFour newPersonFour() {
PersonFour personFour = new PersonFour();
personFour.setFirstName("Chen");
personFour.setLastName("Ray");
return personFour;
}
{"firstName":"Chen","lastName":"Ray"}
-------------- 使用前后对比 --------------
// toString 格式
"PersonFour{firstName='Chen', lastName='Ray'}"
如果你的类没有 setter 方法,我们也可以使用注解 @JsonCreator
修饰构造器,使用 @JsonProperty
修饰构造器属性。
@ToString
public class PersonFive {
private String firstName;
private String lastName;
@JsonCreator
public PersonFive(@JsonProperty("firstName") String firstName,
@JsonProperty("lastName") String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
}
/**
* 使用构造器
*/
@Test
void userCreator() throws JsonProcessingException {
// 实例化 ObjectMapper 对象
ObjectMapper objectMapper = new ObjectMapper();
// json 消息
String json = "{\"firstName\":\"Chen\",\"lastName\":\"Ray\"}";
// 将 json 转成对象
PersonFive personFive = objectMapper.readValue(json, PersonFive.class);
System.out.println(personFive);
}
PersonFive(firstName=Chen, lastName=Ray)
我们也可以使用 Map 存储 JSON, 而不用创建对应的对象。
@ToString
public class PersonMap {
private Map<String, Object> properties = new HashMap<>();
@JsonAnySetter
public void set(String fieldName, Object val) {
this.properties.put(fieldName, val);
}
@JsonAnyGetter
public Object get(String fieldName) {
return this.properties.get(fieldName);
}
}
/**
* 使用 Map存储JSON
*/
@Test
void setMap() throws JsonProcessingException {
// 实例化 ObjectMapper 对象
ObjectMapper objectMapper = new ObjectMapper();
// json 消息
String json = "{\"firstName\":\"Chen\",\"lastName\":\"Ray\"}";
// 将 json 转成对象
PersonMap personMap = objectMapper.readValue(json, PersonMap.class);
System.out.println(personMap);
}
PersonMap(properties={firstName=Chen, lastName=Ray})
如果输入输出 JSON 时需要类型转换,我们可以使用注解 @JsonDeserialize
和 @JsonSerialize
序列化类
public class BooleanToIntSerializer extends JsonSerializer<Boolean> {
@Override
public void serialize(Boolean aBoolean, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
if (aBoolean) {
jsonGenerator.writeNumber(1);
} else {
jsonGenerator.writeNumber(0);
}
}
}
反序列化类
public class BooleanToIntDeserializer extends JsonDeserializer<Boolean> {
@Override
public Boolean deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
String val = jsonParser.getText();
if ("0".equals(val)) {
return false;
}
return true;
}
}
@Data
public class PersonSix {
private String firstName;
private String lastName;
@JsonDeserialize(using = BooleanToIntDeserializer.class)
@JsonSerialize(using = BooleanToIntSerializer.class)
private Boolean isMale;
}
/**
* 类型转换
*/
@Test
void jsonConvert() throws JsonProcessingException {
// 实例化 ObjectMapper 对象
ObjectMapper objectMapper = new ObjectMapper();
// 将对象转成 json
String json = objectMapper.writeValueAsString(newPersonSix());
System.out.println(json);
// 将 json 转成对象
PersonSix personSix = objectMapper.readValue(json, PersonSix.class);
System.out.println(personSix);
}
private static PersonSix newPersonSix() {
PersonSix personSix = new PersonSix();
personSix.setFirstName("Chen");
personSix.setLastName("Ray");
personSix.setIsMale(true);
return personSix;
}
// 序列化
{"firstName":"Chen","lastName":"Ray","isMale":1}
-------------- 类型转换对比 --------------
// 反序列化
PersonSix(firstName=Chen, lastName=Ray, isMale=true)
默认情况下,没有 setter 和 getter 方法的字段不会被输出,我们也可以使用注解 @JsonAutoDetect
设置可见性。
@ToString
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public class PersonSeven {
private Integer id = 0;
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
/**
* 输出私有字段
*/
@Test
void outputPrivate() throws JsonProcessingException {
// 实例化 ObjectMapper 对象
ObjectMapper objectMapper = new ObjectMapper();
// 将对象转成 json
String json = objectMapper.writeValueAsString(newPersonSeven());
System.out.println(json);
}
private static PersonSeven newPersonSeven() {
PersonSeven personSeven = new PersonSeven();
personSeven.setFirstName("Chen");
personSeven.setLastName("Ray");
return personSeven;
}
{"id":0,"firstName":"Chen","lastName":"Ray"}
除了 ObjectMapper 外,如果你不想创建和消息格式一样的对象模型,我们还可以使用 JsonNode 来访问 JSON 消息,下面是一个简单的例子
@Test
void jsonNode() throws JsonProcessingException {
// 实例化 ObjectMapper 对象
ObjectMapper objectMapper = new ObjectMapper();
// json 消息
String json = "{\"firstName\":\"Chen\",\"lastName\":\"Ray\"}";
// 将 json 转成 JsonNode 对象
JsonNode rootNode = objectMapper.readTree(json);
// 或者这样 转成 JsonNode 对象
// JsonNode rootNode = objectMapper.readValue(json, JsonNode.class);
// 得到节点值
JsonNode firstNameNode = rootNode.get("firstName");
System.out.println("firstNameNode = " + firstNameNode.asText());
JsonNode lastNameNode = rootNode.get("lastName");
System.out.println("lastNameNode = " + lastNameNode.asText());
// 创建新节点
ObjectNode newNode = objectMapper.createObjectNode();
newNode.setAll((ObjectNode)rootNode);
newNode.put("age", 18);
// 将 JsonNode 对象转成 json
String newJson = objectMapper.writeValueAsString(newNode);
System.out.println(newJson);
}
JSON字符串被解析为JsonNode对象而不是 Person 对象,只需将 JsonNode.class
第二个参数传递给readValue()方法而不是 Person.class
以下是JsonNode使用该 readValue()
方法将JSON解析的示例:
JsonNode rootNode = objectMapper.readValue(json, JsonNode.class);
该ObjectMapper中还有一个特殊的 readTree()
,它总是返回一个方法 JsonNode。以下是JsonNode使用该 ObjectMapper.readTree()
方法将JSON解析的示例:
JsonNode rootNode = objectMapper.readTree(json);
firstNameNode = Chen
lastNameNode = Ray
{"firstName":"Chen","lastName":"Ray","age":18}
/**
* Object 与 JsonNode 互转
*/
@Test
void objectAndJsonNode() throws JsonProcessingException {
// 实例化 ObjectMapper 对象
ObjectMapper objectMapper = new ObjectMapper();
// json 消息
String json = "{\"firstName\":\"Chen\",\"lastName\":\"Ray\"}";
// 创建 JsonNode 对象
JsonNode jsonNode = objectMapper.readTree(json);
// 将 JsonNode 转换为 Object
Person person = objectMapper.treeToValue(jsonNode, Person.class);
System.out.println(person);
// 将 Object 转换为 JsonNode
JsonNode personJsonNode = objectMapper.valueToTree(person);
// 得到节点值
JsonNode firstName = personJsonNode.get("firstName");
System.out.println("firstName = " + firstName.asText());
}
Person(firstName=Chen, lastName=Ray, address=null, phoneNumberList=null)
firstName = Chen
除了 ObjectMapper 和 JsonNode 外,Jackson 还提供了更底层 JsonParser 和 JsonGenerator 来读写 JSON。
/**
* JsonGenerator
*/
@Test
void jsonGenerator() throws IOException {
// 实例化 JsonFactory 和 JsonParser 对象
JsonFactory factory = new JsonFactory();
JsonGenerator generator = factory.createGenerator(new File("D:\\people.json"), JsonEncoding.UTF8);
// 生成 json
generator.writeStartObject();
generator.writeStringField("firstName", "Chen");
generator.writeStringField("lastName", "Ray");
generator.writeNumberField("age", 18);
generator.writeEndObject();
generator.close();
}
/**
* JsonParser
*/
@Test
void jsonParser() throws IOException {
// json 消息
String json = "{\"firstName\":\"Chen\",\"lastName\":\"Ray\",\"age\":18}";
// 实例化 JsonFactory 和 JsonParser 对象
JsonFactory factory = new JsonFactory();
JsonParser parser = factory.createParser(json);
// 解析 json
while (!parser.isClosed()) {
JsonToken jsonToken = parser.nextToken();
if (JsonToken.FIELD_NAME.equals(jsonToken)) {
String fieldName = parser.getCurrentName();
jsonToken = parser.nextToken();
System.out.println("fieldName = " + fieldName);
System.out.println("jsonToken = " + jsonToken);
System.out.println("parser.getValueAsString = " + parser.getValueAsString());
System.out.println("------------------------------------");
}
}
}
执行结果 jsonGenerator() 方法在 D 盘生成 people.json 文件。
jsonParser() 方法结果
fieldName = firstName
jsonToken = VALUE_STRING
parser.getValueAsString = Chen
------------------------------------
fieldName = lastName
jsonToken = VALUE_STRING
parser.getValueAsString = Ray
------------------------------------
fieldName = age
jsonToken = VALUE_NUMBER_INT
parser.getValueAsString = 18
------------------------------------
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-xml -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.10.1</version>
</dependency>
它依赖于下列一系列的包
jackson-annotations-xxx.jar
jackson-core-xxx.jar
jackson-databind-xxx.jar
jackson-module-jaxb-annotations-xxx.jar
stax2-api-xxx.jar
woodstox-core-xxx.jar
@Data
public class GradeDomain {
@JacksonXmlProperty(localName = "gradeId", isAttribute = true)
private int gradeId;
@JacksonXmlText
private String gradeName;
}
@Data
public class ScoreDomain {
@JacksonXmlProperty(localName = "scoreName")
@JacksonXmlCData
private String name;
@JacksonXmlProperty(localName = "scoreNumber")
private int score;
}
<![CDATA[text]]>
,认识 XML CDATA@Data
@JacksonXmlRootElement(localName = "student")
public class StudentDomain {
@JsonIgnore
private String studentName;
@JacksonXmlProperty(localName = "age")
@JacksonXmlCData
private int age;
@JacksonXmlProperty(localName = "grade")
private GradeDomain grade;
@JacksonXmlElementWrapper(localName = "scoreList")
@JacksonXmlProperty(localName = "score")
private List<ScoreDomain> scores;
}
/**
* XmlMapper 示例
*/
@Test
void xmlMapper() throws IOException {
// 实例化 XmlMapper 对象(ObjectMapper 子类)
ObjectMapper xmlMapper = new XmlMapper();
// XmlMapper 配置
// 反序列化时,若实体类没有对应的属性,是否抛出JsonMappingException异常,false忽略掉
xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 序列化是否绕根元素,true,则以类名为根元素
xmlMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, false);
// 忽略空属性
xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// XML标签名:使用骆驼命名的属性名
xmlMapper.setPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE);
// 设置转换模式
xmlMapper.enable(MapperFeature.USE_STD_BEAN_NAMING);
// object 转 xml
String xml = xmlMapper.writeValueAsString(newStudentDomain());
xmlMapper.writeValue(new File("D:\\student.xml"), newStudentDomain());
System.out.println(xml);
// xml 转 object
StudentDomain studentDomain = xmlMapper.readValue(xml, StudentDomain.class);
System.out.println(studentDomain);
}
private static StudentDomain newStudentDomain() {
GradeDomain gradeDomain = new GradeDomain();
gradeDomain.setGradeId(1);
gradeDomain.setGradeName("高三");
ScoreDomain score1 = new ScoreDomain();
score1.setName("语文");
score1.setScore(90);
ScoreDomain score2 = new ScoreDomain();
score2.setName("数学");
score2.setScore(80);
ScoreDomain score3 = new ScoreDomain();
score3.setName("英语");
score3.setScore(60);
List<ScoreDomain> scoreDomains = Arrays.asList(score1, score2, score3);
StudentDomain studentDomain = new StudentDomain();
studentDomain.setStudentName("张三");
studentDomain.setAge(18);
studentDomain.setGrade(gradeDomain);
studentDomain.setScores(scoreDomains);
return studentDomain;
}
// object 转 xml
<student><age>18</age><grade gradeId="1">高三</grade><scoreList><score><scoreName><![CDATA[语文]]></scoreName><scoreNumber>90</scoreNumber></score><score><scoreName><![CDATA[数学]]></scoreName><scoreNumber>80</scoreNumber></score><score><scoreName><![CDATA[英语]]></scoreName><scoreNumber>60</scoreNumber></score></scoreList></student>
// xml 转 object
StudentDomain(studentName=null, age=18, grade=GradeDomain(gradeId=1, gradeName=高三), scores=[ScoreDomain(name=语文, score=90), ScoreDomain(name=数学, score=80), ScoreDomain(name=英语, score=60)])
记录一次项目中使用到 Jackson 操作的过程。
注意:Jackson 使用到的包是
org.codehaus.jackson
,并非 xml 包
这是从接口中获取的数据,其中很多属性是不需要的
{
"data": {
"pageNo": 1,
"pageSize": 2,
"count": 29,
"list": [
{
"id": "f438f2d844e1486bba986d880ebec220",
"remarks": null,
"createDate": "2018-12-08 18:55:31",
"updateDate": "2020-01-20 10:23:36",
"delFlag": "0",
"name": "广东xxx",
"linkMan": "闫xx",
"telphone": "188xxxxxxxx",
"brand": null,
"modelnum": null,
"attrBak1": "1",
"attrBak2": null,
"attrBak3": null,
"address": "佛山市顺德区xxx",
"emailbox": "xx@qq.com",
"orgunitid": null,
"businessLicense": "xxx326U",
"unifiedid": "xxx326U",
"area": null,
"user": null,
"contacts": null,
"tel": null,
"companyCode": null,
"ztAuditrecordList": [],
"certificateList": null,
"againEdit": null,
"oldName": null,
"procInsId": null
},
{
"id": "92a2e5f40f7f49f1b45f80aa94d9a7f5",
"remarks": null,
"createDate": "2019-03-15 13:22:52",
"updateDate": "2020-01-17 11:33:58",
"delFlag": "0",
"name": "湖南cc公司",
"linkMan": "吴c",
"telphone": "186cccccccc",
"brand": null,
"modelnum": null,
"attrBak1": "1",
"attrBak2": null,
"attrBak3": null,
"address": "湖南省长沙市ccc",
"emailbox": "cc@ccc.com",
"orgunitid": null,
"businessLicense": "ccc690",
"unifiedid": null,
"area": null,
"user": null,
"contacts": null,
"tel": null,
"companyCode": null,
"ztAuditrecordList": [],
"certificateList": null,
"againEdit": null,
"oldName": null,
"procInsId": null
}
],
"firstResult": 0,
"maxResults": 2,
"html": ""
},
"success": true,
"errorCode": -1,
"msg": "success"
}
HttpClient是Apache Jakarta Common下的子项目,用来提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包,并且它支持HTTP协议最新的版本和协议。 Android已成功集成了HttpClient,这意味这开发人员可以直接在Android应用中使用HtppClient来提交请求、接收响应
这里使用到 HttpClient 获取数据
/**
* 描述:HttpClient
*
* @author Ray
* @create 2019/11/14
* @since 1.0.0
*/
public class HttpClientUtils {
// POST 请求
public static String HttpPostWithJson(String url, String json) {
String returnValue = "这是默认返回值,接口调用失败";
CloseableHttpClient httpClient = HttpClients.createDefault();
ResponseHandler<String> responseHandler = new BasicResponseHandler();
try{
//第一步:创建HttpClient对象
httpClient = HttpClients.createDefault();
//第二步:创建httpPost对象
HttpPost httpPost = new HttpPost(url);
//第三步:给httpPost设置JSON格式的参数
StringEntity requestEntity = new StringEntity(json,"utf-8");
requestEntity.setContentEncoding("UTF-8");
httpPost.setHeader("Content-type", "application/json");
httpPost.setEntity(requestEntity);
//第四步:发送HttpPost请求,获取返回值
returnValue = httpClient.execute(httpPost,responseHandler); //调接口获取返回值时,必须用此方法
}
catch(Exception e)
{
e.printStackTrace();
}
finally {
try {
httpClient.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//第五步:处理返回值
return returnValue;
}
}
由于我只要其中的一部分的值,所以在类的上加上注解:@JsonIgnoreProperties(ignoreUnknown = true)
表示遇到没有的内容直接跳过就好。如果没有的话就会报错。
/**
* 渣土_终端供应商Entity
* @author Ray
* @version 2020-02-24
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class ZtTerminalProducer extends DataEntity<ZtTerminalProducer> {
private static final long serialVersionUID = 1L;
private String name; // 供应商名
private String linkMan; // 联系人
private String telphone; // 电话
private String address; // 地址
private String emailbox; // 邮箱
private String unifiedid; // unifiedid
private String businessLicense; // business_license
public ZtTerminalProducer() {
super();
}
public ZtTerminalProducer(String id){
super(id);
}
@ExcelField(title="供应商名", align=2, sort=1)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ExcelField(title="联系人", align=2, sort=2)
public String getLinkMan() {
return linkMan;
}
public void setLinkMan(String linkMan) {
this.linkMan = linkMan;
}
@ExcelField(title="电话", align=2, sort=3)
public String getTelphone() {
return telphone;
}
public void setTelphone(String telphone) {
this.telphone = telphone;
}
@ExcelField(title="地址", align=2, sort=4)
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@ExcelField(title="邮箱", align=2, sort=5)
public String getEmailbox() {
return emailbox;
}
public void setEmailbox(String emailbox) {
this.emailbox = emailbox;
}
@ExcelField(title="unifiedid", align=2, sort=6)
public String getUnifiedid() {
return unifiedid;
}
public void setUnifiedid(String unifiedid) {
this.unifiedid = unifiedid;
}
@ExcelField(title="business_license", align=2, sort=7)
public String getBusinessLicense() {
return businessLicense;
}
public void setBusinessLicense(String businessLicense) {
this.businessLicense = businessLicense;
}
}
如果项目中的 createDate 和 updateDate 是自动填充的,可以加上注解 @org.codehaus.jackson.annotate.JsonIgnore
protected 可以被子类,同package下类使用,不对外公开的访问修饰符。
protected String remarks; // 备注
protected User createBy; // 创建者
@org.codehaus.jackson.annotate.JsonIgnore
protected Date createDate; // 创建日期
protected User updateBy; // 更新者
@org.codehaus.jackson.annotate.JsonIgnore
protected Date updateDate; // 更新日期
protected String delFlag; // 删除标记(0:正常;1:删除;2:审核)
/**
* 获取终端运营商列表
*/
public void pullTerminalProducer() throws IOException {
// 计时器
TimeInterval timer = DateUtil.timer();
// 1. 实例化 ObjectMapper 对象
ObjectMapper objectMapper = new ObjectMapper();
// 2. 获取数据
String terminalProducerJson = HttpClientUtils.HttpPostWithJson(TERMINAL_PRODUCER_URL + pullLoginVerification() + "?pageSize=-1", "");
// 3. 读取 json 的数据转换为节点对象
JsonNode jsonNode = objectMapper.readTree(terminalProducerJson);
// 4. 从节点读取数组中的指定内容
JsonNode value = jsonNode.findValue("list");
// 5. 将 json 的数组转化为对象数组
List<ZtTerminalProducer> terminalProducerList = objectMapper.readValue(value.toString(), new TypeReference<List<ZtTerminalProducer>>() {});
for (ZtTerminalProducer t :
terminalProducerList) {
ztTerminalProducerService.save(t);
}
// 花费时间
logger.debug("pullTerminalProducer() 花费时间: [{}]", formattime(timer.interval()));
}
这样就可以直接读取 list
中的内容,同时对于 list
中不存在的属性或标记注解的属性,也可以忽略。
记录一次项目中使用到 Jackson 对 XML 的操作的过程。
注意:Jackson 使用到的包是
com.fasterxml.jackson
,并非原来解析 json 包
<!-- 解析 xml -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>${jackson.version}</version>
</dependency>
这是通过接口获得的部分数据
<?xml version="1.0" encoding="UTF-8" ?>
<response>
<head>
<code>200</code>
<message></message>
</head>
<body>
<TotalPageCount>1</TotalPageCount>
<TotalRecordCount>899</TotalRecordCount>
<GeoManages>
<GeoManage>
<GID>A1</GID>
<GeoName>A2</GeoName>
<GeoFullName>A3</GeoFullName>
<GeoType>A4</GeoType>
<GeoCode>A5</GeoCode>
<GeoDist>A6</GeoDist>
<GeoJSON>A7</GeoJSON>
<RefreshDate>A8</RefreshDate>
<RefreshClerk>A9</RefreshClerk>
<BusinessID>A10</BusinessID>
</GeoManage>
<GeoManage>
<GID>B1</GID>
<GeoName>B2</GeoName>
<GeoFullName>B3</GeoFullName>
<GeoType>B4</GeoType>
<GeoCode>B5</GeoCode>
<GeoDist>B6</GeoDist>
<GeoJSON>B7</GeoJSON>
<RefreshDate>B8</RefreshDate>
<RefreshClerk>B9</RefreshClerk>
<BusinessID>B10</BusinessID>
</GeoManage>
</GeoManages>
</body>
</response>
这部分的数据,我们真正需要的是 <GeoManage>
里面的内容,所以其他都是多余的。在 JSON 中我们可以使用 JsonNode 读取 JSON 的数据转换为节点对象,但是 XML 中读取失败,暂时还没找到原因。
所以我的思路是,将 XML 文件多余的部分删除,留下有用的,删除后的结构如下:
<GeoManages>
<GeoManage>
<GID>A1</GID>
<GeoName>A2</GeoName>
<GeoFullName>A3</GeoFullName>
<GeoType>A4</GeoType>
<GeoCode>A5</GeoCode>
<GeoDist>A6</GeoDist>
<GeoJSON>A7</GeoJSON>
<RefreshDate>A8</RefreshDate>
<RefreshClerk>A9</RefreshClerk>
<BusinessID>A10</BusinessID>
</GeoManage>
<GeoManage>
<GID>B1</GID>
<GeoName>B2</GeoName>
<GeoFullName>B3</GeoFullName>
<GeoType>B4</GeoType>
<GeoCode>B5</GeoCode>
<GeoDist>B6</GeoDist>
<GeoJSON>B7</GeoJSON>
<RefreshDate>B8</RefreshDate>
<RefreshClerk>B9</RefreshClerk>
<BusinessID>B10</BusinessID>
</GeoManage>
</GeoManages>
</body>
</response>
多余的 </body>
和 </response>
没有关系,XML 元素是可扩展,以携带更多的信息(其实是数据量太大,处理异常了)。。
实例中的根元素是 <GeoManages>
。文档中的所有 <GeoManage>
元素都被包含在 <GeoManages>
中。
<GeoManage>
元素有 10 个子元素:<GID>
、<GeoName>
、<GeoFullName>
、<GeoType>
等。
注意:如果根元素换成 <GeoManage>
,获取到的数据会丢失一部分。测试 899 条记录只获得 10 条记录。
/**
* 描述:httpclient工具类
*
* @author Ray
* @create 2020/2/25
* @since 1.0.0
*/
@Slf4j
public class HttpRequestUtil {
/**
* 发送get请求
* @param url
* @param decodeCharset
* @return
*/
public static String sendGetRequest(String url, String decodeCharset) {
HttpClient httpclient = new DefaultHttpClient();
String responseContent = null;
HttpGet httpGet = new HttpGet(url);
HttpEntity entity = null;
try {
HttpResponse response = httpclient.execute(httpGet);
System.out.println(response);
entity = response.getEntity();
if (null != entity) {
responseContent = EntityUtils.toString(entity, decodeCharset == null ? "UTF-8" : decodeCharset);
}
} catch (Exception e) {
log.error("该异常通常是网络原因引起的,如HTTP服务器未启动等,堆栈信息如下", e);
} finally {
try {
EntityUtils.consume(entity);
httpclient.getConnectionManager().shutdown();
} catch (Exception ex) {
log.error("net io excepiton", ex);
}
}
return responseContent;
}
/**
* post 请求
* @param reqURL
* @param data 可以为param="key1=value1&key2=value2"的一串字符串,或者是jsonObject
* @return
*/
public static String sendHttpPostRequest(String reqURL, String data) {
HttpClient httpclient = new DefaultHttpClient();
String respStr = "";
try {
HttpPost httppost = new HttpPost(reqURL);
StringEntity strEntity = new StringEntity(data, "UTF-8");
strEntity.setContentType("application/x-www-form-urlencoded");
httppost.setEntity(strEntity);
log.info(EntityUtils.toString(strEntity));
log.info("executing request " + httppost.getRequestLine());
HttpResponse response = httpclient.execute(httppost);
HttpEntity resEntity = response.getEntity();
if (resEntity != null) {
log.info("返回数据长度: " + resEntity.getContentLength());
respStr = EntityUtils.toString(resEntity);
log.info("respStr " + respStr);
}
} catch (ClientProtocolException e) {
log.error("sendHttpPostRequest : " ,e);
} catch (IOException e) {
log.error("sendHttpPostRequest : " ,e);
} finally {
httpclient.getConnectionManager().shutdown();
}
return respStr;
}
/**
* 发送post请求
* @param url
* @param params
* @return
* @throws Exception
*/
public static String sendHttpPostRequest(String url, Map<String, String> params) {
String respStr = "";
HttpClient httpclient = new DefaultHttpClient();
httpclient.getParams().setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 10000);
httpclient.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 10000);
log.info("url: " + url);
log.info("params: " + params);
try {
HttpPost post = new HttpPost(url);
List<BasicNameValuePair> postData = new ArrayList<BasicNameValuePair>();
for (Map.Entry<String, String> entry : params.entrySet()) {
postData.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(postData, "UTF-8");
post.setEntity(entity);
HttpResponse response = httpclient.execute(post);
HttpEntity resEntity = response.getEntity();
if (resEntity != null) {
log.info("返回数据长度: " + resEntity.getContentLength());
respStr = EntityUtils.toString(resEntity);
log.info("respStr " + respStr);
}
} catch (ClientProtocolException e) {
log.error("sendHttpPostRequest : " +e);
} catch (IOException e) {
log.error("sendHttpPostRequest : " +e);
} finally {
httpclient.getConnectionManager().shutdown();
}
return respStr;
}
/**
* 测试
* @param args
*/
public static void main(String[] args) {
String params = "bankcard=6217856101018144878&key=316fcfd892e7e4d24ded8699f1f7d957";
String resultStr = HttpRequestUtil.sendHttpPostRequest("http://apis.juhe.cn/bankcardcore/query", params);
System.out.println(resultStr);
ObjectMapper mapper = new ObjectMapper();
try {
Map map = mapper.readValue(resultStr, Map.class);
Set<Map.Entry> set = map.entrySet();
for (Map.Entry entry : set) {
System.out.println(entry.getKey() + "==" + entry.getValue());
}
}catch(IOException ioe){
ioe.printStackTrace();
}
}
}
/**
* 获取已绘制区域列表信息Entity
* @author Ray
* @version 2019-11-15
*/
@JacksonXmlRootElement(localName = "GeoManage")
@JsonIgnoreProperties(ignoreUnknown = true)
public class ZtGeoManage extends DataEntity<ZtGeoManage> {
private static final long serialVersionUID = 1L;
@JacksonXmlProperty(localName = "GID")
private String geoId; // 区域ID
@JacksonXmlProperty(localName = "GeoName")
private String geoName; // 区域简称
@JacksonXmlProperty(localName = "GeoFullName")
private String geoFullName; // 区域全称
@JacksonXmlProperty(localName = "GeoType")
private String geoType; // 区域类型
@JacksonXmlProperty(localName = "GeoCode")
private String geoCode; // 区域编号
@JacksonXmlProperty(localName = "GeoDist")
private String geoDist; // 区域区县
@JacksonXmlProperty(localName = "GeoJSON")
private String geoJson; // 区域地理信息
//@JacksonXmlProperty(localName = "RefreshDate") // 这个Date类型需要转格式,先忽略
@JsonIgnore
private Date refreshDate; // 绘制地理信息时间
@JacksonXmlProperty(localName = "RefreshClerk")
private String refreshClerk; // 绘制地理信息人
@JacksonXmlProperty(localName = "BusinessID")
private String businessId; // 区域业务ID
@JsonIgnore
private Date synchroDate; // 同步时间(区分同一批记录)
public ZtGeoManage() {
super();
}
public ZtGeoManage(String id){
super(id);
}
@ExcelField(title="区域ID", align=2, sort=1)
public String getGeoId() {
return geoId;
}
public void setGeoId(String geoId) {
this.geoId = geoId;
}
@ExcelField(title="区域简称", align=2, sort=2)
public String getGeoName() {
return geoName;
}
public void setGeoName(String geoName) {
this.geoName = geoName;
}
@ExcelField(title="区域全称", align=2, sort=3)
public String getGeoFullName() {
return geoFullName;
}
public void setGeoFullName(String geoFullName) {
this.geoFullName = geoFullName;
}
@ExcelField(title="区域类型", align=2, sort=4)
public String getGeoType() {
return geoType;
}
public void setGeoType(String geoType) {
this.geoType = geoType;
}
@ExcelField(title="区域编号", align=2, sort=5)
public String getGeoCode() {
return geoCode;
}
public void setGeoCode(String geoCode) {
this.geoCode = geoCode;
}
@ExcelField(title="区域区县", align=2, sort=6)
public String getGeoDist() {
return geoDist;
}
public void setGeoDist(String geoDist) {
this.geoDist = geoDist;
}
@ExcelField(title="区域地理信息", align=2, sort=7)
public String getGeoJson() {
return geoJson;
}
public void setGeoJson(String geoJson) {
this.geoJson = geoJson;
}
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ExcelField(title="绘制地理信息时间", align=2, sort=8)
public Date getRefreshDate() {
return refreshDate;
}
public void setRefreshDate(Date refreshDate) {
this.refreshDate = refreshDate;
}
@ExcelField(title="绘制地理信息人", align=2, sort=9)
public String getRefreshClerk() {
return refreshClerk;
}
public void setRefreshClerk(String refreshClerk) {
this.refreshClerk = refreshClerk;
}
@ExcelField(title="区域业务ID", align=2, sort=10)
public String getBusinessId() {
return businessId;
}
public void setBusinessId(String businessId) {
this.businessId = businessId;
}
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@NotNull(message="同步时间(区分同一批记录)不能为空")
@ExcelField(title="同步时间(区分同一批记录)", align=2, sort=11)
public Date getSynchroDate() {
return synchroDate;
}
public void setSynchroDate(Date synchroDate) {
this.synchroDate = synchroDate;
}
}
说明:
@JacksonXmlRootElement
:指定生成xml根标签的名字;
@JacksonXmlElementWrapper
:可用于指定List等集合类,外围标签名;
@JacksonXmlProperty
:指定包装标签名,或者指定标签内部属性名;
/**
* 获取已绘制的区域列表信息 - 新
* 2020-2-25 21:25:42
*/
public void pullGeoManageNew() throws IOException {
// 传递参数
Map<String, String> params = new HashMap(2);
params.put("PageSize", "0");
// 经测试,直接传String,会参数错误,要注意接口是使用url发送还是json发送
//String params = "PageSize=0";
String geoManageJson = HttpRequestUtil.sendHttpPostRequest(PULL_GEO_MANAGE_URL, objectMapper.writeValueAsString(params));
// 如果有 html 特殊符号(只列出部分),需转换,不然无法解析,没有需要的可以注释
geoManageJson = geoManageJson.replaceAll("“", "“");
geoManageJson = geoManageJson.replaceAll("”", "”");
geoManageJson = geoManageJson.replaceAll("—", "——");
geoManageJson = geoManageJson.replaceAll("°", "°");
geoManageJson = geoManageJson.replaceAll("€", "");
geoManageJson = geoManageJson.replaceAll("·", "·");
// 截取?之后字符串
String strSub = geoManageJson.substring(0, geoManageJson.indexOf("<GeoManage>"));
geoManageJson = geoManageJson.substring(strSub.length());
// 实例化 XmlMapper 对象(ObjectMapper 子类)
com.fasterxml.jackson.databind.ObjectMapper xmlMapper = new XmlMapper();
/** 下面的配置没经过测试 */
//// 反序列化时,若实体类没有对应的属性,是否抛出JsonMappingException异常,false忽略掉
//xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//// 序列化是否绕根元素,true,则以类名为根元素
//xmlMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, false);
//// 设置让jackson支持转义
//xmlMapper.configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, true);
//// 允许出现特殊字符和转义符
//xmlMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true) ;
//// 允许出现单引号
//xmlMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true) ;
//// 忽略空属性
//xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
//// XML标签名:使用骆驼命名的属性名
//xmlMapper.setPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE);
//// 设置转换模式
//xmlMapper.enable(MapperFeature.USE_STD_BEAN_NAMING);
// XML -> List (可用)
List<ZtGeoManage> ztGeoManageList = xmlMapper.readValue(geoManageJson, new com.fasterxml.jackson.core.type.TypeReference<List<ZtGeoManage>>() {});
System.out.println("ztGeoManageList = " + ztGeoManageList);
// XML -> Array (可用)
ZtGeoManage[] arrays = xmlMapper.readValue(geoManageJson, ZtGeoManage[].class);
System.out.println("arrays = " + arrays);
}
2020-02-26 08:23:56,055 INFO [com.jeeplus.common.utils.HttpRequestUtil] - {"PageSize":"0"}
2020-02-26 08:23:56,067 INFO [com.jeeplus.common.utils.HttpRequestUtil] - executing request POST http://120.78.xx.158:80xx/ups/ztpls/bl/PullGeoManage?authtoken=0024441E-9B7E-4EB7-xxxx-D222A48C795F HTTP/1.1
2020-02-26 08:23:58,717 INFO [com.jeeplus.common.utils.HttpRequestUtil] - 返回数据长度: 718497
ztGeoManageList = [com.jeeplus.modules.ztfx.entity.ZtGeoManage@3f3c8b60[geoId=A1,geoName=A2,geoFullName=A3,geoType=A4,geoCode=A5,geoDist=A6,geoJson=A7,refreshDate=A8,refreshClerk=A9,businessId=A10,synchroDate=<null>,remarks=<null>,createBy=<null>,createDate=<null>,updateBy=<null>,updateDate=<null>,delFlag=0,id=<null>,currentUser=<null>,page=<null>,sqlMap=<null>,isNewRecord=false], com.jeeplus.modules.ztfx.entity.ZtGeoManage@3f357c9d[geoId=B1,geoName=B2,geoFullName=B3,geoType=B4,geoCode=B5,geoDist=B6,geoJson=B7,refreshDate=B8,refreshClerk=B9,businessId=B10,synchroDate=<null>,remarks=<null>,createBy=<null>,createDate=<null>,updateBy=<null>,updateDate=<null>,delFlag=0,id=<null>,currentUser=<null>,page=<null>,sqlMap=<null>,isNewRecord=false]]