1. 简介

JAX-RS(Java API for RESTful Web Services)是一套用于创建 REST API 的 Java 规范。它大量使用注解来简化开发流程,提升开发效率。

在本教程中,我们将使用 JBoss 提供的 JAX-RS 实现框架 —— RESTEasy 来构建一个简单的 RESTful Web 服务。

2. 项目配置

我们将考虑两种常见的部署场景:

  • 独立部署(Standalone Setup) – 适用于任意应用服务器
  • JBoss AS 部署(JBoss AS Setup) – 仅适用于部署在 JBoss 应用服务器上

2.1. 独立部署

我们以 JBoss WildFly 10 为例,进行独立部署的配置。

WildFly 10 默认集成的是 RESTEasy 3.0.11 版本,但我们将在 pom.xml 中手动升级到 3.0.14 版本。

得益于 resteasy-servlet-initializer 模块,RESTEasy 可以通过 ServletContainerInitializer 接口与支持 Servlet 3.0 的容器进行集成。

以下是 pom.xml 的关键依赖配置:

<properties>
    <resteasy.version>3.0.14.Final</resteasy.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-servlet-initializer</artifactId>
        <version>${resteasy.version}</version>
    </dependency>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-client</artifactId>
        <version>${resteasy.version}</version>
    </dependency>
</dependencies>

jboss-deployment-structure.xml

在 JBoss 中,WAR、JAR 或 EAR 都被视为模块,称为 动态模块。此外,JBoss 还提供了一些预定义的 静态模块,位于 $JBOSS_HOME/modules 目录下。

由于 JBoss 自带了 RESTEasy 的静态模块,若想使用我们自定义的版本,就必须通过 jboss-deployment-structure.xml 来排除默认模块,避免冲突。

配置如下,确保 WAR 中的类和 JAR 能够被优先加载:

<jboss-deployment-structure>
    <deployment>
        <exclude-subsystems>
            <subsystem name="resteasy" />
        </exclude-subsystems>
        <exclusions>
            <module name="javaee.api" />
            <module name="javax.ws.rs.api"/>
            <module name="org.jboss.resteasy.resteasy-jaxrs" />
        </exclusions>
        <local-last value="true" />
    </deployment>
</jboss-deployment-structure>

2.2. JBoss AS 部署

如果你使用的是 JBoss AS 6 或更高版本,可以直接使用服务器自带的 RESTEasy 库,这样可以简化 pom.xml 配置:

<dependencies>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jaxrs</artifactId>
        <version>${resteasy.version}</version>
    </dependency>
</dependencies>

⚠️ 注意:此时不再需要 jboss-deployment-structure.xml 文件。

3. 服务端代码实现

3.1. Servlet 3.0 的 web.xml 配置

下面是我们项目中 web.xml 的简化配置示例:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
     http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

   <display-name>RestEasy Example</display-name>

   <context-param>
      <param-name>resteasy.servlet.mapping.prefix</param-name>
      <param-value>/rest</param-value>
   </context-param>

</web-app>

参数 resteasy.servlet.mapping.prefix 用于指定 REST 接口的统一前缀路径。

✅ 你可能注意到我们没有在 web.xml 中显式声明 Servlet,这是因为我们已经在 pom.xml 中引入了 resteasy-servlet-initializer 依赖。RESTEasy 内部通过 org.jboss.resteasy.plugins.servlet.ResteasyServletInitializer 实现了 ServletContainerInitializer 接口,在容器启动时自动注册相关组件。

3.2. Application 类

javax.ws.rs.core.Application 是标准的 JAX-RS 类,用于提供部署信息。我们可以继承它来注册服务:

@ApplicationPath("/rest")
public class RestEasyServices extends Application {

    private Set<Object> singletons = new HashSet<Object>();

    public RestEasyServices() {
        singletons.add(new MovieCrudService());
    }

    @Override
    public Set<Object> getSingletons() {
        return singletons;
    }
}

📌 该类通过 @ApplicationPath 注解指定 REST API 的根路径,构造函数中注册了具体的资源类。如果返回空集合,则容器会自动扫描带有 JAX-RS 注解的类。

3.3. 实际服务实现类

下面是一个简单的 REST 接口实现类:

@Path("/movies")
public class MovieCrudService {

    private Map<String, Movie> inventory = new HashMap<String, Movie>();

    @GET
    @Path("/getinfo")
    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    public Movie movieByImdbId(@QueryParam("imdbId") String imdbId) {
        if (inventory.containsKey(imdbId)) {
            return inventory.get(imdbId);
        } else {
            return null;
        }
    }

    @POST
    @Path("/addmovie")
    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    public Response addMovie(Movie movie) {
        if (null != inventory.get(movie.getImdbId())) {
            return Response
              .status(Response.Status.NOT_MODIFIED)
              .entity("Movie is Already in the database.").build();
        }

        inventory.put(movie.getImdbId(), movie);
        return Response.status(Response.Status.CREATED).build();
    }
}

📌 说明:

  • @Path:定义资源路径
  • @GET / @POST:定义 HTTP 方法
  • @Produces / @Consumes:指定支持的媒体类型
  • @QueryParam:从请求参数中提取值
  • Response:用于构建 HTTP 响应

4. 总结

在本教程中,我们快速上手了 RESTEasy,并构建了一个简单的 REST API 示例。RESTEasy 提供了强大的功能和灵活的扩展性,非常适合用于构建企业级 RESTful 服务。

本例的完整代码已上传至 GitHub:sample project in GitHub



原始标题:A Guide to RESTEasy

« 上一篇: Guava 19 新特性详解
» 下一篇: Java Web周报112