带有 JAX-RS 的 Apache CXF


在继续本章之前,我们假设你知道如何用 Java 编写 RESTful Web 服务。我将向你展示如何在此 JAX-RS(用于 RESTful Web 服务的 Java API)之上使用 CXF。我们将创建一个维护最新电影列表的 Web 服务。当用户请求一部电影时,他在请求中指定了电影ID,服务器将定位该电影并将其返回给客户端。在我们的简单案例中,我们将简单地将电影名称返回给客户端,而不是实际的二进制 MP4 文件。因此,让我们开始创建 JAX-RS 应用程序。

声明电影元素


我们将声明一个名为 Movie 的 XML 根元素,用于存储给定电影的 id 和名称。该元素在名为 Movie.java 的文件中声明。文件内容如下所示:

// 电影.java
package com.newbiego.cxf.jaxrs.movie;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "Movie")
public class Movie {
    private long id;
    private String name;
    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;
    }
}

注意使用 XmlRootElement 用于声明 XML 元素的标记 Movie 标签。接下来,我们将创建一个服务,在其数据库中保存电影列表。

创建电影服务数据库


为了存储我们使用 Java 提供的电影列表 Map 存储键值对。如果列表很大,你将使用更易于管理的外部数据库存储。在我们的简单案例中,我们将仅在数据库中存储五部电影。 MovieService类的代码如下:

// 电影服务.java
package com.newbiego.cxf.jaxrs.movie;
import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
@Path("/movieservice/")
@Produces("text/xml")
public class MovieService {
    long currentId = 123;
    Map<Long, Movie> movies = new HashMap<>();
    public MovieService() {
        init();
    }
    @GET
    @Path("/movie/{id}/")
    public Movie getMovie(@PathParam("id") String id) {
        long idNumber = Long.parseLong(id);
        return movies.get(idNumber);
    }
    final void init() {
        Movie c1 = new Movie();
        c1.setName("Aquaman");
        c1.setId(1001);
        movies.put(c1.getId(), c1);
      
        Movie c2 = new Movie();
        c2.setName("Mission Imposssible");
        c2.setId(1002);
        movies.put(c2.getId(), c2);
      
        Movie c3 = new Movie();
        c3.setName("Black Panther");
        c3.setId(1003);
        movies.put(c3.getId(), c3);
      
        Movie c4 = new Movie();
        c4.setName("A Star is Born");
        c4.setId(1004);
        movies.put(c4.getId(), c4);
      
        Movie c5 = new Movie();
        c5.setName("The Meg");
        c5.setId(1005);
        movies.put(c5.getId(), c5);
    }
}

请注意,我们使用以下两个注解来指定我们的电影服务的 URL 路径及其返回类型:

@Path("/movieservice/")
@Produces("text/xml")

我们使用 @GET 和 @Path 注解来指定 GET 请求的 URL,如下所示:

@GET
@Path("/movie/{id}/")

电影数据库本身是在 init 方法中初始化的,我们在该方法中将五个电影项目添加到数据库中。

我们的下一个任务是编写一个服务器应用程序。

开发服务器


要创建服务器,我们使用提供的 CXF JAXRSServerFactoryBean class.

JAXRSServerFactoryBean factory = new JAXRSServerFactoryBean();

我们通过调用 设置资源类 method.

factory.setResourceClasses(Movie.class);
factory.setResourceClasses(MovieService.class);

我们通过调用 设置资源提供者 method.

factory.setResourceProvider(MovieService.class,
new SingletonResourceProvider(new MovieService()));

我们设置想要的 publish 通过调用地址 aet地址 method:

factory.setAddress("http:// 本地主机:9000/");

最后,我们通过在服务器上调用 create 方法发布服务器 factory 实例。

factory.create();

服务端应用的完整代码如下:

// 服务器.java
package com.newbiego.cxf.jaxrs.movie;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
public class Server {
    public static void main(String[] args) throws Exception {
        JAXRSServerFactoryBean factory = new JAXRSServerFactoryBean();
        factory.setResourceClasses(Movie.class);
        factory.setResourceClasses(MovieService.class);
        factory.setResourceProvider(MovieService.class,
            new SingletonResourceProvider(new MovieService()));
        factory.setAddress("http:// 本地主机:9000/");
        factory.create();
      
        System.out.println("Server ready...");
        Thread.sleep(5 * 60 * 1000);
      
        System.out.println("Server exiting ...");
        System.exit(0);
    }
}

最后的 pom.xml


这里我们已经包含了以下 pom.xml 的最终版本:

<?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.newbiego</groupId>
    <artifactId>cxf-jaxrs</artifactId>
    <version>1.0</version>
    <packaging>jar</packaging>
    <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>
    <profiles>
        <profile>
            <id>server</id>
            <build>
                <defaultGoal>test</defaultGoal>
                <plugins>
                    <plugin>
                        <groupId>org.codehaus.mojo</groupId>
                        <artifactId>exec-maven-plugin</artifactId>
                        <version>1.6.0</version>
                        <executions>
                            <execution>
                                <phase>test</phase>
                                <goals>
                                    <goal>java</goal>
                                </goals>
                                <configuration>
                                    <mainClass>
                                        com.newbiego.cxf.jaxrs.movie.Server
                                    </mainClass>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
            <dependencies>
                <dependency>
                    <groupId>org.apache.cxf</groupId>
                    <artifactId>cxf-rt-transports-http-jetty</artifactId>
                    <version>3.3.0</version>
                </dependency>
            </dependencies>
        </profile>
        <profile>
            <id>client</id>
            <build>
                <defaultGoal>test</defaultGoal>
                <plugins>
                    <plugin>
                        <groupId>org.codehaus.mojo</groupId>
                        <artifactId>exec-maven-plugin</artifactId>
                        <executions>
                            <execution>
                                <phase>test</phase>
                                <goals>
                                    <goal>java</goal>
                                </goals>
                                <configuration>
                                    <mainClass>
                                        com.newbiego.cxf.jaxrs.movie.Client
                                    </mainClass>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>
    <dependencies>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>3.3.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http-jetty</artifactId>
            <version>3.3.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxrs</artifactId>
            <version>3.3.0</version>
            </dependency>
        <dependency>
            <groupId>jakarta.ws.rs</groupId>
            <artifactId>jakarta.ws.rs-api</artifactId>
            <version>2.1.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.7</version>
        </dependency>
    </dependencies>
</project>

开发客户


编写 RS 客户端很简单。我们只需创建一个 URL 对象并打开它的流。我们使用 CXF 提供的 IOUtils 类将输入流的内容复制到本地流。

URL url = new URL("http:// localhost:9000/movieservice/movie/1002");
try (输入Stream instream = url.openStream();
Cached输出Stream outstream = new Cached输出Stream()) {
    IOUtils.copy(instream, outstream);
}

客户端应用程序的完整代码如下:

// 客户端.java
package com.newbiego.cxf.jaxrs.movie;
import java.io.输入Stream;
import java.net.URL;
import org.apache.cxf.helpers.IOUtils;
import org.apache.cxf.io.Cached输出Stream;
public class Client {
    public static void main(String[] args) throws Exception {
        URL url = new URL("http:// localhost:9000/movieservice/movie/1002");
        try (输入Stream instream = url.openStream();
        Cached输出Stream outstream = new Cached输出Stream()) {
            IOUtils.copy(instream, outstream);
            String str = outstream.getOut().toString();
            System.out.println(str);
        }
    }
}

测试 JAX-RS 应用程序


在命令行窗口中使用以下命令运行服务器:

mvn -Pserver

现在,你将在控制台上看到以下消息:

INFO: Setting the server's publish address to be http:// 本地主机:9000

现在,打开浏览器并输入以下 URL:

http:// 本地主机:9000/movieservice/movie/1002

你将在浏览器窗口中看到以下内容。

browser window

你可以使用我们开发的 Java 客户端应用程序调用服务,方法是在单独的命令行窗口中运行以下命令。

mvn -Pclient

你将看到以下输出:

<?xml version="1.0" encoding = "UTF-8" standalone="yes"?>
<Movie><id>1002</id><name>Mission Imposssible</name></Movie>

CXF 示例提供了几个关于如何将 CXF 与 JAX-RS 一起使用的示例。鼓励有兴趣的读者研究这些样本。