# Java Servlet 提供 XML

> 原文： [http://zetcode.com/articles/javaservletservexml/](http://zetcode.com/articles/javaservletservexml/)

Java Servlet 服务 XML 展示了如何从 Java Servlet 服务 XML 数据。 数据存储在 MySQL 表中。 该 Web 应用已部署在 Tomcat Web 服务器上。

## XML 格式

可扩展标记语言（XML）是一种流行的人类可读和机器可读的标记语言。 XML 的设计目标强调互联网的简单性，通用性和可用性。 它是一种文本数据格式，并通过 Unicode 对不同的人类语言提供了强大的支持。 XML 最初是为大规模电子出版而设计的，被广泛用于在软件组件，系统和企业之间交换各种数据。

XML 是由万维网联盟（W3C）开发的行业标准。 它不受任何编程语言或软件供应商的束缚。 XML 是可扩展的，与平台无关的，并且支持国际化。

## JAXB

用于 XML 绑定的 Java 架构（JAXB）提供了 API 和工具，可自动执行 XML 文档和 Java 对象之间的映射。 JAXB 允许将 XML 内容解组为 Java 表示形式，访问和更新 Java 表示形式，并将 XML 内容的 Java 表示形式编组为 XML 内容。

## Java Servlet

Servlet 是 Java 类，可响应特定类型的网络请求-最常见的是 HTTP 请求。 Java servlet 用于创建 Web 应用。 它们在 servlet 容器（例如 Tomcat 或 Jetty）中运行。 现代 Java Web 开发使用在 servlet 之上构建的框架。

## Java Servlet 服务 XML 示例

在下面的 Web 应用中，我们从 MySQL 表加载数据并将其显示为 XML 到客户端。 我们使用 JAXB 解析器将 Java 类转换为 XML。

`cars_mysql.sql`

```java
-- SQL for the Cars table

CREATE TABLE Cars(Id BIGINT PRIMARY KEY AUTO_INCREMENT, Name VARCHAR(150), 
    Price INTEGER);
INSERT INTO Cars(Name, Price) VALUES('Audi', 52642);
INSERT INTO Cars(Name, Price) VALUES('Mercedes', 57127);
INSERT INTO Cars(Name, Price) VALUES('Skoda', 9000);
INSERT INTO Cars(Name, Price) VALUES('Volvo', 29000);
INSERT INTO Cars(Name, Price) VALUES('Bentley', 350000);
INSERT INTO Cars(Name, Price) VALUES('Citroen', 21000);
INSERT INTO Cars(Name, Price) VALUES('Hummer', 41400);
INSERT INTO Cars(Name, Price) VALUES('Volkswagen', 21600);

```

该 SQL 脚本在 MySQL 中创建`Cars`表。

```java
$ tree
.
├── nb-configuration.xml
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── zetcode
    │   │           ├── converter
    │   │           │   └── CarsXmlConverter.java
    │   │           ├── dao
    │   │           │   ├── CarsDAO.java
    │   │           │   └── ICarsDAO.java
    │   │           ├── model
    │   │           │   ├── Car.java
    │   │           │   └── CarList.java
    │   │           ├── service
    │   │           │   ├── CarsService.java
    │   │           │   └── ICarsService.java
    │   │           ├── util
    │   │           │   └── ServiceLocator.java
    │   │           └── web
    │   │               ├── GetCar.java
    │   │               └── GetCars.java
    │   ├── resources
    │   └── webapp
    │       ├── index.html
    │       ├── META-INF
    │       │   └── context.xml
    │       └── WEB-INF
    └── test
        └── java

```

这是项目结构。

`pom.xml`

```java
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>JavaServletServeXml</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>JavaServletServeXml</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.45</version>
        </dependency>        

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>        

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>

        </plugins>
    </build>

</project>

```

这是 Maven POM 文件。 `javax.servlet-api`工件用于 servlet。 `spring-jdbc`依赖项用于`JdbcTemplate`库，该库简化了 Java 中的数据库编程。 `mysql-connector-java`是 Java 语言的 MySQL 驱动程序。 `maven-war-plugin`负责收集 Web 应用的所有工件依赖项，类和资源，并将它们打包到 Web 应用存档（WAR）中。

`context.xml`

```java
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/JavaServletServeXml">

    <Resource name="jdbc/testdb" 
              auth="Container"
              type="javax.sql.DataSource" 
              username="user12" 
              password="s$cret"              
              driverClassName="com.mysql.jdbc.Driver"
              url="jdbc:mysql://localhost:3306/testdb"              
              maxActive="10" 
              maxIdle="4"/>

</Context>

```

在 Tomcat `context.xml`文件中，我们定义了上下文路径和 MySQL 数据源。

`Car.java`

```java
package com.zetcode.model;

import java.util.Objects;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlRootElement(name = "car")
@XmlType(propOrder = {"id", "name", "price"})
public class Car {

    private Long id;
    private String name;
    private int price;

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

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 79 * hash + Objects.hashCode(this.id);
        hash = 79 * hash + Objects.hashCode(this.name);
        hash = 79 * hash + this.price;
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Car other = (Car) obj;
        if (this.price != other.price) {
            return false;
        }
        if (!Objects.equals(this.name, other.name)) {
            return false;
        }
        return Objects.equals(this.id, other.id);
    }
}

```

`Car` bean 从`Cars`数据库表中保留一行。

```java
@XmlRootElement(name = "car")
@XmlType(propOrder = {"id", "name", "price"})

```

使用`@XmlRootElement`注解，我们设置元素的名称。 `@XmlType`用于设置元素标签的生成顺序。

`CarList.java`

```java
package com.zetcode.model;

import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(namespace = "com.zetcode")
@XmlAccessorType(XmlAccessType.FIELD)
public class CarList {

    @XmlElementWrapper(name = "cars")
    @XmlElement(name = "car")
    private List<Car> cars;

    public List<Car> getCars() {
        return cars;
    }

    public void setCars(List<Car> cars) {
        this.cars = cars;
    }
}

```

`CarList`是一个帮助器类，其中包含 JAXB 映射注解，以在 XML 输出中的汽车标签周围创建包装器。

```java
@XmlElementWrapper(name = "cars")

```

`@XmlElementWrapper`注解在列表中的元素周围创建了一个包装。

```java
@XmlElement(name = "car")

```

`@XmlElement`注解设置包装元素的名称。

`ServiceLocator.java`

```java
package com.zetcode.util;

import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

public class ServiceLocator {

    public static DataSource getDataSource(String jndiName) {

        Context ctx = null;
        DataSource ds = null;

        try {
            ctx = new InitialContext();
            ds = (DataSource) ctx.lookup(jndiName);
        } catch (NamingException ex) {
            Logger.getLogger(ServiceLocator.class.getName()).log(
                Level.SEVERE, null, ex);
        }

        return ds;
    }
}

```

`ServiceLocator`通过给定的 JNDI 名称查找数据源，并将其返回给调用方。

`ICarsService.java`

```java
package com.zetcode.service;

import com.zetcode.model.Car;
import java.util.List;

public interface ICarsService {

    public Car findCarById(long id);
    public List<Car> findAllCars();
}

```

`ICarsService`包含两种服务合同方法：`findCarById()`和`findAllCars()`。

`CarsService.java`

```java
package com.zetcode.service;

import com.zetcode.dao.CarsDAO;
import com.zetcode.model.Car;
import java.util.List;

public class CarsService implements ICarsService {

    private CarsDAO carsDao;

    public CarsService() {

        carsDao = createDao();
    }

    @Override
    public Car findCarById(long id) {

        Car car = carsDao.findById(id);
        return car;
    }

    @Override
    public List<Car> findAllCars() {

        List<Car> cars = carsDao.findAll();
        return cars;
    }

    private CarsDAO createDao() {

        carsDao = new CarsDAO();
        return carsDao;
    }
}

```

`CarsService`包含`ICarsService`接口的实现。 服务类调用 DAO 对象的方法，该对象是数据库的中间层。

`ICarsDAO.java`

```java
package com.zetcode.dao;

import com.zetcode.model.Car;
import java.util.List;

public interface ICarsDAO {

    public Car findById(long id);
    public List<Car> findAll();
}

```

在这里，我们有 DAO 合同方法。

`CarsDAO.java`

```java
package com.zetcode.dao;

import com.zetcode.model.Car;
import com.zetcode.util.ServiceLocator;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.sql.DataSource;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;

public class CarsDAO implements ICarsDAO {

    private JdbcTemplate jtm;

    public CarsDAO() {

        createJdbcTemplate();
    }

    @Override
    public Car findById(long id) {

        String sql = "SELECT * FROM Cars WHERE Id=?";

        Car car = new Car();

        try {
            car = (Car) jtm.queryForObject(sql, new Object[]{id},
                    new BeanPropertyRowMapper(Car.class));
        } catch (EmptyResultDataAccessException ex) {
            Logger.getLogger(CarsDAO.class.getName()).log(
                    Level.SEVERE, null, ex);
        }

        return car;
    }

    @Override
    public List<Car> findAll() {

        String sql = "SELECT * FROM Cars";

        List<Car> cars = new ArrayList<>();

        try {
            cars = jtm.query(sql,
                    new BeanPropertyRowMapper(Car.class));

        } catch (EmptyResultDataAccessException ex) {
            Logger.getLogger(CarsDAO.class.getName()).log(
                    Level.SEVERE, null, ex);
        }

        return cars;
    }

    private JdbcTemplate createJdbcTemplate() {

        DataSource ds = ServiceLocator.getDataSource("java:comp/env/jdbc/testdb");
        jtm = new JdbcTemplate(ds);
        return jtm;
    }
}

```

`CarsDAO`包含 DAO 方法的实现。 我们使用 Spring 的`JdbcTemplate`模块访问数据库。

```java
private JdbcTemplate createJdbcTemplate() {

    DataSource ds = ServiceLocator.getDataSource("java:comp/env/jdbc/testdb");
    jtm = new JdbcTemplate(ds);
    return jtm;
}

```

在`createJdbcTemplate()`方法中，我们查找数据源并创建`JdbcTemplate`。

`CarsXmlConverter.java`

```java
package com.zetcode.converter;

import com.zetcode.model.Car;
import com.zetcode.model.CarList;
import java.io.ByteArrayOutputStream;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

public class CarsXmlConverter {

    private ByteArrayOutputStream bos;

    public ByteArrayOutputStream convertList(List<Car> cars) {

        bos = new ByteArrayOutputStream();

        try {
            JAXBContext context = JAXBContext.newInstance(CarList.class);
            Marshaller m = context.createMarshaller();
            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

            CarList carsList = new CarList();
            carsList.setCars(cars);

            m.marshal(carsList, bos);

        } catch (JAXBException ex) {
            Logger.getLogger(CarsXmlConverter.class.getName()).log(Level.SEVERE, null, ex);
        }

        return bos;
    }

    public ByteArrayOutputStream convertObject(Car car) {

        bos = new ByteArrayOutputStream();

        try {
            JAXBContext context = JAXBContext.newInstance(Car.class);
            Marshaller m = context.createMarshaller();
            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
            m.marshal(car, bos);

        } catch (JAXBException ex) {
            Logger.getLogger(CarsXmlConverter.class.getName()).log(Level.SEVERE, null, ex);
        }

        return bos;
    }
}

```

`CarsXmlConverter`包含将 Java 类转换为 XML 数据的方法。

```java
public ByteArrayOutputStream convertList(List<Car> cars) {

```

该方法返回`ByteArrayOutputStream`。

```java
JAXBContext context = JAXBContext.newInstance(CarList.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

```

创建了 JAXB 编组器。

```java
CarList carsList = new CarList();
carsList.setCars(cars);

m.marshal(carsList, bos);

```

我们将 Java 表示形式编组为`ByteArrayOutputStream`。

`GetCars.java`

```java
package com.zetcode.web;

import com.zetcode.converter.CarsXmlConverter;
import com.zetcode.model.Car;
import com.zetcode.service.CarsService;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "GetCars", urlPatterns = {"/GetCars"})
public class GetCars extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("application/xml;charset=UTF-8");

        CarsService carsService = new CarsService();
        List<Car> cars = carsService.findAllCars();

        CarsXmlConverter xmlConverter = new CarsXmlConverter();

        try (ByteArrayOutputStream bos = xmlConverter.convertList(cars)) {
            OutputStream os = response.getOutputStream();
            bos.writeTo(os);
        }
    }
}

```

`GetCars` Servlet 将`Cars`表中的所有数据作为 XML 数据返回。

```java
@WebServlet(name = "GetCars", urlPatterns = {"/GetCars"})

```

Java 类用`@WebServlet`注解修饰。 它映射到`GetCars` URL 模式。

```java
response.setContentType("application/xml;charset=UTF-8");

```

Servlet 将以 XML 输出数据，并且数据的编码设置为 UTF-8。

```java
CarsService carsService = new CarsService();
List<Car> cars = carsService.findAllCars();

```

使用`CarsService`的`findAllCars()`，我们从数据库中检索所有汽车。

```java
CarsXmlConverter xmlConverter = new CarsXmlConverter();

try (ByteArrayOutputStream bos = xmlConverter.convertList(cars)) {
    OutputStream os = response.getOutputStream();
    bos.writeTo(os);
}

```

我们使用`CarsXmlConverter`将数据转换为 XML，并将字节写入`ServletOutputStream`。

`GetCar.java`

```java
package com.zetcode.web;

import com.zetcode.converter.CarsXmlConverter;
import com.zetcode.model.Car;
import com.zetcode.service.CarsService;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "GetCar", urlPatterns = {"/GetCar"})
public class GetCar extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        long id = Long.parseLong(request.getParameter("carId"));

        response.setContentType("application/xml;charset=UTF-8");

        CarsService carsService = new CarsService();
        Car car = carsService.findCarById(id);

        CarsXmlConverter xmlConverter = new CarsXmlConverter();

        try (ByteArrayOutputStream bos = xmlConverter.convertObject(car)) {
            OutputStream os = response.getOutputStream();
            bos.writeTo(os);
        }
    }
}

```

`GetCar` Servlet 以 XML 格式返回一辆汽车。

`index.html`

```java
<!DOCTYPE html>
<html>
    <head>
        <title>Home page</title>
        <meta charset="UTF-8">
    </head>
    <body>

        <a href="GetCars">Get cars</a>
        <br>
        <a href="GetCar?carId=5">Get car with id 5</a>

    </body>
</html>

```

这是主页。 它包含两个链接。 一个检索所有汽车，另一个检索具有 ID 5 的汽车。

在本教程中，我们创建了一个 Java Web 应用，该应用从 MySQL 数据库中选择数据，将其转换为 XML，然后将 XML 数据返回给客户端。

您可能也对以下相关教程感兴趣： [Java Servlet 焊接教程](/articles/javaservletweld/)， [Java Servlet 上传文件](/articles/javaservletuploadfile/)， [Java Log4j 教程](/java/log4j/)， [Java Servlet RESTful 客户端](/articles/javaservletrestclient/) ， [Java `RequestDispatcher`](/java/requestdispatcher/) ，[从 Java Servlet 提供纯文本](/articles/javaservlettext/) ， [Java Servlet 图像教程](/articles/javaservletimage/)或 [Java 教程](/lang/java/)。