# Java Servlet RESTFul 客户端

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

在 Java Servlet RESTFul 客户端教程中，我们使用 JAX-RS 在 Java Servlet 中创建 RESTFul 客户端。

用于 RESTful Web 服务的 Java API（JAX-RS）是 Java API 规范，它提供了根据代表性状态转移（REST）架构模式创建 Web 服务的支持。

Jersey 是 Java RESTful Web 服务框架和 JAX-RS 参考实现。

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

## Java Servlet 应用

以下 Web 应用向`api.randomuser.me`站点创建一个请求，该站点是一个随机用户生成器。

Java servlet 使用`ClientBuilder`创建一个`Client`，这是用于构建和执行客户端请求以使用返回的响应的流畅 API 的主要入口点。

```java
$ tree
.
├── nb-configuration.xml
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── zetcode
    │   │           ├── model
    │   │           │   ├── Location.java
    │   │           │   ├── Name.java
    │   │           │   ├── Person.java
    │   │           │   └── PersonsList.java
    │   │           ├── service
    │   │           │   └── PersonService.java
    │   │           └── web
    │   │               └── MyServlet.java
    │   ├── resources
    │   └── webapp
    │       ├── index.html
    │       ├── META-INF
    │       │   └── context.xml
    │       ├── show.jsp
    │       └── 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>JavaServletRestClient</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>JavaServletRestClient</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>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>           

        <dependency>
            <groupId>org.glassfish.jersey.core</groupId>
            <artifactId>jersey-client</artifactId>
            <version>2.25.1</version>
        </dependency>      

        <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-json-jackson</artifactId>
            <version>2.22</version>
        </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 文件。 我们有四个工件：用于 servlet 的`javax.servlet-api`，用于标准 JSP 标签库的`jstl`，用于 RESTFul 核心客户端实现的`jersey-client`和用于 JSON / Java Bean 数据绑定的`jersey-media-json-jackson`。

`context.xml`

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

```

在 Tomcat `context.xml`文件中，我们定义了上下文路径。 它是 Web 应用的名称。

在该应用中，我们有三个 bean。 这些 bean 将被响应中的数据填充。

`Location.java`

```java
package com.zetcode.model;

public class Location {

    private String street;
    private String city;
    private String state;
    private String postcode;

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    public String getPostcode() {
        return postcode;
    }

    public void setPostcode(String postcode) {
        this.postcode = postcode;
    }

    @Override
    public String toString() {

        StringBuilder sb = new StringBuilder();
        sb.append(street).append(" ")
                .append(city).append(" ")
                .append(state).append(" ")
                .append(postcode);
        return sb.toString();
    }
}

```

`Location`存储用户的地址。

`Name.java`

```java
package com.zetcode.model;

public class Name {

    private String first;
    private String last;
    private String title;

    public String getFirst() {
        return first;
    }

    public void setFirst(String firstName) {
        first = firstName;
    }

    public String getLast() {
        return last;
    }

    public void setLast(String lastName) {
        last = lastName;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    @Override
    public String toString() {

        StringBuilder sb = new StringBuilder();
        sb.append(title).append(" ").append(first)
                .append(" ").append(last);
        return sb.toString();
    } 
}

```

`Name`存储用户名详细信息。

`Person.java`

```java
package com.zetcode.model;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public class Person {

    private Name name;
    private Location location;
    private String email;
    private String gender;

    public void setName(Name name) {
        this.name = name;
    }

    public Name getName() {
        return name;
    }    

    public Location getLocation() {
        return location;
    }

    public void setLocation(Location location) {
        this.location = location;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getEmail() {
        return email;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {

        StringBuilder sb = new StringBuilder();
        sb.append("Name: ").append(name)
                .append("Address: ").append(location)
                .append("Email ").append(email)
                .append("Gender: ").append(gender);
        return sb.toString();
    }
}

```

`Person`类存储有关用户的数据，包括姓名，地址，电子邮件和性别。

```java
@JsonIgnoreProperties(ignoreUnknown = true)

```

使用`@JsonIgnoreProperties`批注，我们告诉 Jackson 忽略`Person`中未列出的属性。

`PersonsList.java`

```java
package com.zetcode.model;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.util.List;

@JsonIgnoreProperties(ignoreUnknown = true)
public class PersonsList {

    List<Person> results;

    public List<Person> getResults() {
        return results;
    }

    public void setResults(List<Person> result) {
        results = result;
    }
}

```

这是`Person`对象的列表。 Web 服务使用数据填充此列表。

`MyServlet.java`

```java
package com.zetcode.web;

import com.zetcode.model.Person;
import com.zetcode.service.PersonService;
import java.io.IOException;
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 = "MyServlet", urlPatterns = {"/MyServlet"})
public class MyServlet extends HttpServlet {

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

        response.setContentType("text/html;charset=UTF-8");

        List<Person> people = PersonService.fetchPeople(0, 50);

        request.setAttribute("people", people);
        request.getRequestDispatcher("show.jsp").forward(request, response);
    }
}

```

`MyServlet` Servlet 调用`PersonService.fetchPeople()`，它返回`Person`对象的列表。 该列表将作为属性存储，并且处理将分派到`show.jsp`页面。 JSP 页面呈现`Person`对象的列表。

`PersonService.java`

```java
package com.zetcode.service;

import com.zetcode.model.Person;
import com.zetcode.model.PersonsList;
import java.util.List;

import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;

public class PersonService {

    private static WebTarget resource = ClientBuilder.newBuilder()
            .build().target("https://api.randomuser.me/");

    public static List<Person> fetchPeople(int offset, int num) {
        PersonsList res = resource.queryParam("seed", 1)
                .queryParam("results", num).queryParam("page", 1)
                .request(MediaType.APPLICATION_JSON).get(PersonsList.class);
        return res.getResults();
    }      
}

```

`PersonService`包含用于在`api.randomuser.me` Web 服务上执行查询的`fetchPeople()`方法。 该服务随机返回用户对象。

```java
private static WebTarget resource = ClientBuilder.newBuilder()
        .build().target("https://api.randomuser.me/");

```

使用`ClientBuilder`创建一个 Web 资源目标。 `api.randomuser.me`网站随机返回用户列表。

```java
public static List<Person> fetchPeople(int offset, int num) {
    PersonsList res = resource.queryParam("seed", 1)
            .queryParam("results", num).queryParam("page", 1)
            .request(MediaType.APPLICATION_JSON).get(PersonsList.class);
    return res.getResults();
}    

```

我们向网络资源发送查询； 数据存储在`PersonsList`中。

`index.html`

```java
<!DOCTYPE html>
<html>
    <head>
        <title>Home Page</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <a href="MyServlet">List people</a>
    </body>
</html>

```

这是主页。 它包含一个调用`MyServlet`的链接。

`show.jsp`

```java
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Show people</title>
    </head>
    <body>
        <table>
            <thead>
                <tr>
                    <th>Title</th>
                    <th>First name</th>
                    <th>Last name</th>
                    <th>Street</th>
                    <th>City</th>
                    <th>State</th>
                    <th>Postcode</th>
                    <th>Email</th>
                    <th>Gender</th>
                </tr>
            </thead>
            <tbody>

                <c:forEach var="per" items="${people}">
                    <tr>
                        <td><c:out value="${per.name.title}"/></td>
                        <td><c:out value="${per.name.first}"/></td>
                        <td><c:out value="${per.name.last}"/></td>
                        <td><c:out value="${per.location.street}"/></td>
                        <td><c:out value="${per.location.city}"/></td>
                        <td><c:out value="${per.location.state}"/></td>
                        <td><c:out value="${per.location.postcode}"/></td>
                        <td><c:out value="${per.email}"/></td>
                        <td><c:out value="${per.gender}"/></td>
                    </tr>
                </c:forEach>
            </tbody>
        </table>
    </body>    
</html>

```

`show.jsp`页面使用 JSTL 库中的`c:forEach`和`c:out`标签在 HTML 表中显示数据。

在本教程中，我们向 Web 服务创建了一个 JAX-RS 客户端请求，该请求会随机生成用户。 该请求是从 Java Servlet 发送的。

您可能也对以下相关教程感兴趣： [Java servlet Log4j 教程](/articles/javaservletlog4j/)， [Java servlet JSON 教程](/articles/javaservletjson/)， [Java Servlet PDF 教程](/articles/javaservletpdf/)， [Java servlet 复选框教程](/articles/javaservletcheckbox/)， [Java servlet 图像教程](/articles/javaservletimage/)， [Java Servlet HTTP 标头](/articles/javaservlethttpheaders/)或 [Java 教程](/lang/java/)。