OpenFeign攔截器 在微服務中比較常見的場景:前端帶了JWT令牌請求服務A,在服務A中使用Feign遠程調用服務B、服務C等,A、B、C都接入了Spring Security;此時就會存在這樣的需求,如服務A調用服務B、C時不帶有JWT令牌就會出現服務調用失敗,無法通過服務B、C鑒權認證; 此 ...
Jackson 除了可以處理 JSON,還可以用來處理 XML(jackson-dataformat-xml 模塊),可以輕鬆完成 Java 對象和 XML 文檔的互轉;本文主要介紹使用 Jackson 來處理 XML,文中所使用到的軟體版本:Java 1.8.0_321、Jackson 2.13.3。
1、簡介
jackson-dataformat-xml 模擬 JAXB "代碼優先" 的數據綁定方式,提供低級以及高級的方法來完成數據綁定工作。值得註意的是,jackson-dataformat-xml 的目標不是完整的 JAXB 克隆,或者成為一個通用的 XML 工具包。具體來說:
- While XML serialization should ideally be similar to JAXB output, deviations are not automatically considered flaws (there are reasons for some differences)
- What should be guaranteed is that any XML written using this module must be readable using module as well ("read what I wrote"): that is, we do aim for full round-trip support
- From above: there are XML constructs that module will not be able to handle; including some cases JAXB (and other Java XML libraries) supports
- This module also support constructs and use cases JAXB does not handle: specifically, rich type and object id support of Jackson are supported.
詳情可參考官網文檔:https://github.com/FasterXML/jackson-dataformat-xml.
2、Jackson 配置
處理 XML 的 XMLMapper 對象繼承自處理 JSON 的 ObjectMapper 對象,因此他們的配置是類似的,具體可參考:Java 操作 JSON 數據(4)--Jackson 操作 JSON 數據。這裡列出僅針對 XML 處理的註解:
註解 | 作用域 | 說明 | 實現時機 |
@JacksonXmlRootElement | 類上 | 指定 XML 根標簽的名字 | 序列化時 |
@JacksonXmlProperty | 屬性或getter/setter方法上 | 指定屬性對應 XML 映射的名稱 | 序列化和反序列化時 |
@JacksonXmlText | 屬性或getter/setter方法上 | 將屬性直接作為未被標簽包裹的普通文本 | 序列化和反序列化時 |
@JacksonXmlCData | 屬性或getter/setter方法上 | 將屬性值包裹在 CDATA 標簽中 | 序列化時 |
@JacksonXmlElementWrapper | 屬性或getter/setter方法上 | 類中有集合的屬性時,是否生成包裹的標簽 | 序列化時 |
3、具體使用
3.1、引入依賴
<dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> <version>2.13.3</version> </dependency>
3.2、定義實體類
3.2.1、Grade
package com.abc.demo.xml; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; import lombok.Data; import lombok.ToString; import java.util.List; @Data @ToString @JacksonXmlRootElement(namespace = "http://www.w3.org/TR/html4/school/", localName = "school:grade") public class Grade { @JacksonXmlElementWrapper(useWrapping = false) @JacksonXmlProperty(localName = "student", namespace = "http://www.w3.org/TR/html4/school/") List<Student> students; }
3.2.2、Student
package com.abc.demo.xml; import com.fasterxml.jackson.dataformat.xml.annotation.*; import lombok.Data; import lombok.ToString; @Data @ToString public class Student { @JacksonXmlProperty(isAttribute = true) private int rollno; @JacksonXmlProperty(isAttribute = true) private int age; @JacksonXmlProperty(namespace = "http://www.w3.org/TR/html4/school/") private String firstname; private String lastname; private String nickname; private String marks; public Student() {} public Student(int rollno, int age, String firstname, String lastname, String nickname, String marks) { this.rollno = rollno; this.age = age; this.firstname = firstname; this.lastname = lastname; this.nickname = nickname; this.marks = marks; } }
3.3、定義待解析 XML(student.xml)
<?xml version="1.0" encoding="utf-8" ?> <school:grade xmlns:school="http://www.w3.org/TR/html4/school/"> <school:student rollno="1" school:age="10"> <school:firstname>cxx1</school:firstname> <lastname>Bob1</lastname> <nickname>stars1</nickname> <marks>85</marks> </school:student> <student rollno="2"> <firstname>cxx2</firstname> <lastname>Bob2</lastname> <nickname>stars2</nickname> <marks>85</marks> </student> <student rollno="3"> <firstname>cxx3</firstname> <lastname>Bob3</lastname> <nickname>stars3</nickname> <marks>85</marks> </student> </school:grade>
3.4、序列化及反序列化
package com.abc.demo.xml; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.dataformat.xml.XmlMapper; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; public class JacksonCase { private static final Logger logger = LoggerFactory.getLogger(JacksonCase.class); /** * 序列化 */ @Test public void serialize() throws IOException { List<Student> students = new ArrayList<>(); Student student1 = new Student(1, 11,"cxx1", "Bob1", "stars1", "85"); Student student2 = new Student(2, 12, "cxx2", "Bob2", "stars2", "85"); Student student3 = new Student(3, 13, "cxx3", "Bob3", "stars3", "85"); students.add(student1); students.add(student2); students.add(student3); Grade grade = new Grade(); grade.setStudents(students); XmlMapper xmlMapper = new XmlMapper(); //美化輸出 xmlMapper.enable(SerializationFeature.INDENT_OUTPUT); logger.info(xmlMapper.writeValueAsString(grade)); } /** * 反序列化 */ @Test public void deserialize() throws IOException { XmlMapper xmlMapper = new XmlMapper(); InputStream inputStream = JacksonCase.class.getResourceAsStream("student.xml"); //反序列化為實體對象 Grade grade = xmlMapper.readValue(inputStream, Grade.class); logger.info(grade.toString()); inputStream = JacksonCase.class.getResourceAsStream("student.xml"); TypeReference<List<Student>> typeReference = new TypeReference<List<Student>>(){}; //反序列化為集合 List<Student> students = xmlMapper.readValue(inputStream, typeReference); logger.info(students.toString()); inputStream = JacksonCase.class.getResourceAsStream("student.xml"); //使用樹模型 API 解析 XML JsonNode root = xmlMapper.readTree(inputStream); JsonNode jsonNode = root.get("student").get(1); logger.info("第一條數據,{}",jsonNode.toString()); logger.info("第一條數據,firstname={}", jsonNode.get("firstname").asText()); logger.info("第一條數據,marks={}", jsonNode.get("marks").asInt()); } }