使用嵌入式 Jetty 的 Jersey 应用
最后修改于 2020 年 7 月 13 日
在本教程中,我们将创建一个简单的 Java REST 应用,使用 Jersey 和嵌入式 Jetty。我们还将展示如何将该应用打包成一个可执行的 uber JAR。
Jersey 是一个开源框架,用于在 Java 中开发 RESTful Web 服务。它是 Java API for RESTful Web Services (JAX-RS) 规范的参考实现。
Jetty 是一个 Java HTTP (Web) 服务器和 Java Servlet 容器。它可以轻松地嵌入到设备、工具、框架、应用程序服务器和集群中。
RESTful 应用程序
RESTful 应用程序创建了一个遵循 REST 架构风格的系统(API),该风格用于设计网络化应用程序。RESTful 应用程序使用 HTTP 请求对资源执行 CRUD(创建/读取/更新/删除)操作。
代码示例
下面是一个用 Jersey 和嵌入式 Jetty 服务器创建的非常简单的 Java RESTful 应用程序。
$ tree . ├── pom.xml └── src ├── main │ ├── java │ │ └── com │ │ └── zetcode │ │ ├── app │ │ │ └── Main.java │ │ └── res │ │ └── MyMessage.java │ └── resources └── test └── java
这是我们的项目结构。
该项目包含两个 Java 源代码文件和一个 Maven POM 文件。
<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.zetcode</groupId> <artifactId>JerseyJettyEx</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>JerseyJettyEx</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.glassfish.jersey.containers</groupId> <artifactId>jersey-container-jetty-http</artifactId> <version>2.25</version> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-util</artifactId> <version>9.4.0.v20161208</version> </dependency> <dependency> <groupId>org.glassfish.jersey.core</groupId> <artifactId>jersey-server</artifactId> <version>2.25</version> </dependency> <dependency> <groupId>org.glassfish.jersey.containers</groupId> <artifactId>jersey-container-servlet-core</artifactId> <version>2.25</version> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-servlet</artifactId> <version>9.4.0.v20161208</version> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-server</artifactId> <version>9.4.0.v20161208</version> </dependency> </dependencies> <build> <finalName>JerseyJettyEx</finalName> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>1.5.0</version> <executions> <execution> <goals> <goal>java</goal> </goals> </execution> </executions> <configuration> <mainClass>com.zetcode.app.Main</mainClass> </configuration> </plugin> </plugins> </build> </project>
在 pom.xml
文件中,我们包含了必要的 Jersey 和 Jetty 依赖。我们还使用了 exec-maven-plugin
,它用于执行 Java 程序。
package com.zetcode.res; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; @Path("msg") public class MyMessage { @GET @Produces(MediaType.TEXT_PLAIN) public String getMessage() { return "My message\n"; } }
我们定义了一个资源。它响应 HTTP GET 请求并返回纯文本。
@Path("msg") public class MyMessage {
@Path
注释标识了资源响应的 URL 路径。
package com.zetcode.app; import java.util.logging.Level; import java.util.logging.Logger; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.glassfish.jersey.servlet.ServletContainer; public class Main { public static void main(String[] args) { Server server = new Server(8080); ServletContextHandler ctx = new ServletContextHandler(ServletContextHandler.NO_SESSIONS); ctx.setContextPath("/"); server.setHandler(ctx); ServletHolder serHol = ctx.addServlet(ServletContainer.class, "/rest/*"); serHol.setInitOrder(1); serHol.setInitParameter("jersey.config.server.provider.packages", "com.zetcode.res"); try { server.start(); server.join(); } catch (Exception ex) { Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); } finally { server.destroy(); } } }
在 Main.java
中,我们设置并启动了 Jetty。
Server server = new Server(8080);
Jetty 服务器开始监听 8080 端口。
ServletContextHandler ctx = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
下一步是创建一个 ServletContextHandler
对象。
ctx.setContextPath("/");
通过 setContextPath
方法,我们设置了应用程序映射的路径。
ServletHolder serHol = ctx.addServlet(ServletContainer.class, "/rest/*");
我们将 Jersey 的 ServletContainer
添加到 Jetty 的 servlet 持有者中。这基本上是将 Jersey 与 Jetty 连接起来。
serHol.setInitParameter("jersey.config.server.provider.packages", "com.zetcode.res");
这里我们告诉 Jersey 在哪里查找资源。
构建和运行应用程序
在接下来的步骤中,我们将构建并运行应用程序。
$ mvn package
我们使用 mvn package
命令构建应用程序。
$ mvn exec:java
使用 mvn exec:java
命令启动应用程序。
$ curl localhost:8080/rest/msg My message
我们使用 curl
工具向我们的资源发出 HTTP GET 请求。
Uber JAR
Uber JAR 是一个 JAR 文件,它包含我们的包及其所有依赖项,所有这些都打包在一个 JAR 文件中。这种 JAR 也被称为 fat JAR。
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>2.4.3</version> <configuration> <createDependencyReducedPom>true</createDependencyReducedPom> <filters> <filter> <artifact>*:*</artifact> <excludes> <exclude>META-INF/*.SF</exclude> <exclude>META-INF/*.DSA</exclude> <exclude>META-INF/*.RSA</exclude> </excludes> </filter> </filters> </configuration> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" /> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <manifestEntries> <Main-Class>com.zetcode.app.Main</Main-Class> </manifestEntries> </transformer> </transformers> </configuration> </execution> </executions> </plugin>
使用 maven-shade-plugin
,我们可以创建一个包含所有依赖项的可执行 JAR。
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <manifestEntries> <Main-Class>com.zetcode.app.Main</Main-Class> </manifestEntries> </transformer>
为了使 JAR 可执行,它必须在 manifest 文件中有一个主类。这是通过 ManifestResourceTransformer
实现的。
$ mvn clean package
我们清理并构建应用程序。
$ java -jar target/JerseyJettyEx-1.0-SNAPSHOT.jar
我们使用此命令启动应用程序。
在本教程中,我们用 Jersey 和嵌入式 Jetty 创建了一个简单的 Java REST 应用程序。我们还展示了如何创建一个 uber JAR。