Thursday, January 7, 2021

Parsing XML Response in Spring Boot

 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.

Parsing XML Response in Spring Boot

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 &amp; 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>

Chúng tôi sẽ phân tích cú pháp phản hồi XML ở trên để tạo một đối tượng Khóa học cũng sẽ chứa danh sách Học viên.
Spring Classes
Sau đây là hai lớp mô hình (Khóa học & Sinh viên) chúng ta cần cho ví dụ này:
Student.java
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;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", firstName='" + firstName + '\'' +
                ", lastName='" + lastName + '\'' +
                ", avatar='" + avatar + '\'' +
                '}';
    }
}
Course.java

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;
    }

    @Override
    public String toString() {
        return "Course{" +
                "id=" + id +
                ", title='" + title + '\'' +
                ", price=" + price +
                ", created=" + created +
                ", students=" + students +
                '}';
    }
}

Lưu ý rằng chúng ta đã ghi đè phương thức toString () trong cả hai lớp để in chi tiết.
DOM XML Parser
Chúng tôi sẽ tạo một dịch vụ Spring có tên là XMLService để gọi API giả của chúng tôi. Dịch vụ này sử dụng trình phân tích cú pháp Java DOM để đọc XML từ một URL từ xa và phân tích cú pháp nó thành một đối tượng Khóa học.
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;

@Service
public class XMLService {

    private final Logger logger = LoggerFactory.getLogger(XMLService.class);


    public Course parseCourse() {

        Course course = null;

        try {
            // fake end point that returns XML response
            String URL = "http://www.mocky.io/v2/5c8bdd5c360000cd198f831e";

            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(URL);

            // normalize XML response
            doc.getDocumentElement().normalize();

            //read course details first
            course = 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 list
            NodeList nodeList = doc.getElementsByTagName("student");

            //create an empty list for students
            List<Student> students = new ArrayList<>();

            //loop all available student nodes
            for (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 course
            course.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);

    }

}

 

No comments:

Post a Comment