Mặc dù JSON đã trở thành một lựa chọn phổ biến cho giao tiếp không đồng bộ, XML vẫn được một số lượng lớn các công ty sử dụng để trao đổi dữ liệu trong các dịch vụ web SOAP. Là một nhà phát triển Spring Boot, bạn có thể gặp phải yêu cầu phân tích cú pháp phản hồi XML của một dịch vụ web trong sự nghiệp của mình. Nó không hiếm cho lắm.
Trong hướng dẫn này, chúng ta sẽ học cách phân tích cú pháp phản hồi XML của một dịch vụ web bằng trình phân tích cú pháp DOM XML trong Spring Boot. Bộ phân tích cú pháp DOM XML tải toàn bộ dữ liệu vào bộ nhớ và phân tích cú pháp nó thành một tài liệu XML. Tài liệu XML đã phân tích cú pháp có thể được sử dụng để duyệt qua các phần tử và nút khác nhau theo bất kỳ thứ tự nào.
Trình phân tích cú pháp DOM XML tương đối chậm và chỉ tốt để phân tích cú pháp các tài liệu XML nhỏ vì nó tải một tài liệu XML hoàn chỉnh vào bộ nhớ. Điều này khiến nó trở thành một lựa chọn tồi để phân tích cú pháp các tài liệu XML lớn. Đối với các tệp XML lớn, bạn nên sử dụng trình phân tích cú pháp SAX. Tôi sẽ giải thích cách hoạt động của trình phân tích cú pháp SAX và cách nó tốt hơn trình phân tích cú pháp DOM trong tương lai.
Sự phụ thuộc
Trình phân tích cú pháp DOM XML là một phần của các phần mở rộng Java tiêu chuẩn (javax) và không yêu cầu bất kỳ sự phụ thuộc nào của bên thứ ba. Chúng ta chỉ cần sự phụ thuộc của Spring-boot-starter cho dự án Spring Boot. Đây là cách tệp build.gradle của chúng tôi trông như thế nào:
build.gradle
plugins {
id 'org.springframework.boot' version '2.1.3.RELEASE'
id 'java'
}
apply plugin: 'io.spring.dependency-management'
group = 'com.attacomsian.xml'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
}
XML Response
Đối với hướng dẫn này, chúng tôi sẽ sử dụng một API giả mạo trả về phản hồi XML. Đây là cách phản hồi XML của chúng tôi trông như thế nào:
<?xml version="1.0" encoding="UTF-8" ?>
<course>
<id>1</id>
<title>Introduction to Spring Boot & Thymeleaf</title>
<price>49.99</price>
<created>2019-03-15</created>
<student>
<id>1</id>
<first_name>George</first_name>
<last_name>Bluth</last_name>
<avatar>https://s3.amazonaws.com/uifaces/faces/twitter/calebogden/128.jpg</avatar>
</student>
<student>
<id>2</id>
<first_name>Janet</first_name>
<last_name>Weaver</last_name>
<avatar>https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128.jpg</avatar>
</student>
<student>
<id>3</id>
<first_name>Emma</first_name>
<last_name>Wong</last_name>
<avatar>https://s3.amazonaws.com/uifaces/faces/twitter/olegpogodaev/128.jpg</avatar>
</student>
</course>
package com.attacomsian.xml.models;public class Student {private int id;private String firstName;private String lastName;private String avatar;public Student(int id, String firstName, String lastName, String avatar) {this.id = id;this.firstName = firstName;this.lastName = lastName;this.avatar = avatar;}public int getId() {return id;}public void setId(int id) {this.id = id;}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;}public String getAvatar() {return avatar;}public void setAvatar(String avatar) {this.avatar = avatar;}@Overridepublic String toString() {return "Student{" +"id=" + id +", firstName='" + firstName + '\'' +", lastName='" + lastName + '\'' +", avatar='" + avatar + '\'' +'}';}}
package com.attacomsian.xml.models;import java.util.Date;import java.util.List;public class Course {private int id;private String title;private double price;private Date created;private List<Student> students;public Course(int id, String title, double price, Date created) {this.id = id;this.title = title;this.price = price;this.created = created;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}public Date getCreated() {return created;}public void setCreated(Date created) {this.created = created;}public List<Student> getStudents() {return students;}public void setStudents(List<Student> students) {this.students = students;}@Overridepublic String toString() {return "Course{" +"id=" + id +", title='" + title + '\'' +", price=" + price +", created=" + created +", students=" + students +'}';}
package com.attacomsian.xml.services;import com.attacomsian.xml.models.Course;import com.attacomsian.xml.models.Student;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Service;import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.Node;import org.w3c.dom.NodeList;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.List;@Servicepublic class XMLService {private final Logger logger = LoggerFactory.getLogger(XMLService.class);public Course parseCourse() {Course course = null;try {// fake end point that returns XML responseString URL = "http://www.mocky.io/v2/5c8bdd5c360000cd198f831e";DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();DocumentBuilder builder = factory.newDocumentBuilder();Document doc = builder.parse(URL);// normalize XML responsedoc.getDocumentElement().normalize();//read course details firstcourse = new Course(Integer.parseInt(doc.getElementsByTagName("id").item(0).getTextContent()),doc.getElementsByTagName("title").item(0).getTextContent(),Double.parseDouble(doc.getElementsByTagName("price").item(0).getTextContent()),new SimpleDateFormat("yyyy-MM-dd").parse(doc.getElementsByTagName("created").item(0).getTextContent()));//read students listNodeList nodeList = doc.getElementsByTagName("student");//create an empty list for studentsList<Student> students = new ArrayList<>();//loop all available student nodesfor (int i = 0; i < nodeList.getLength(); i++) {Node node = nodeList.item(i);if(node.getNodeType() == Node.ELEMENT_NODE) {Element elem = (Element) node;Student student = new Student(Integer.parseInt(elem.getElementsByTagName("id").item(0).getTextContent()),elem.getElementsByTagName("first_name").item(0).getTextContent(),elem.getElementsByTagName("last_name").item(0).getTextContent(),elem.getElementsByTagName("avatar").item(0).getTextContent());students.add(student);}}//set students in coursecourse.setStudents(students);} catch (Exception ex) {logger.error(ex.getMessage());}return course;}}
Trong phương thức parseCourse () ở trên, chúng ta xây dựng một phiên bản của DocumentBuilder bằng cách sử dụng DocumentBuilderFactory. Sau đó, phương thức parse () thể hiện này được sử dụng để gửi một yêu cầu HTTP đến API giả của chúng tôi để lấy XML và phân tích cú pháp nó thành một đối tượng Document. Sau đó, chúng tôi duyệt qua phần tử tài liệu này và các nút để tạo một đối tượng Course.
Executing Application
Bây giờ chúng ta hãy tạo lớp ứng dụng chính thực thi giao diện CommandLineRunner để chạy dự án Spring Boot như một ứng dụng bảng điều khiển.
package com.attacomsian.xml;
import com.attacomsian.xml.models.Course;
import com.attacomsian.xml.services.XMLService;
import org.springframework.boot.Banner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class XmlParserApplication implements CommandLineRunner {
private XMLService xmlService;
public XmlParserApplication(XMLService xmlService) {
this.xmlService = xmlService;
}
public static void main(String[] args) {
SpringApplication app = new SpringApplication(XmlParserApplication.class);
// disable spring banner
app.setBannerMode(Banner.Mode.OFF);
app.run(args);
}
@Override
public void run(String... args) throws Exception {
// load course from XMLService
Course course = xmlService.parseCourse();
// print course details
System.out.println(course);
}
}
Post a Comment
Post a Comment