读书笔记《advanced-java-ee-development-with-wildfly》在带有RESTEasy的Java EE 7中使用JAX-RS 2.0
JSR 311 (http://jcp.org/en/jsr/detail ?id=311) 指定 Java API for RESTful Web services (JAX-RS) 用于开发< strong>REST(具象状态传输)使用 Java 的 Web 服务。 REST 是一种独立于协议、松散耦合的分布式系统软件架构风格。 RESTful Web 服务公开一组资源,这些资源只是信息的来源,由 URI (统一资源标识符)。 RESTful Web 服务遵循以下 RESTful 原则:
每个资源都有一个唯一的基础 URI
用于调用 Web 服务操作的 HTTP 协议方法,如
GET
、PUT
、POST< /code> 和
DELETE
被使用客户端向服务发送请求,服务将请求的资源的表示返回给客户端
客户端会话不存储在服务器上,这使得在集群环境中以更少的数据复制更容易扩展服务
JSR 339 (https://www.jcp.org/en /jsr/detail?id=339) 开发 JAX-RS 2.0 版本。 JAX-RS 2.0 提供了几个新功能,例如客户端 API,支持 验证 、过滤器和拦截器和异步处理。我们将使用 RESTEasy (http://resteasy.jboss.org/) 实现。本章包含以下部分:
设置环境
客户端 API
过滤器和拦截器
异步处理
取消请求
会话 bean EJB 资源
从客户端进行异步调用
WildFly 8.1.0.Final:从
wildfly-8.1.0.Final.zip
下载 <一个类="ulink" href="http://wildfly.org/downloads/" target="_blank">http://wildfly.org/downloads/。面向 Java EE 开发人员的 Eclipse IDE:从 https://www.eclipse.org/downloads/packages/release/Luna/SR1。
JBoss Tools (Luna) 4.2.0.Final(或最新版本):将此作为插件从 Eclipse Marketplace 安装到 Eclipse(http://tools.jboss.org/downloads/installation.html)。
Apache Maven:从 http://maven.apache.org/download.cgi。
Java 7:从 http://www.oracle.com/technetwork/java/javase/downloads/index.html?ssSourceSiteId=ocomcn。)
设置环境变量JAVA_HOME
、JBOSS_HOME
和MAVEN_HOME
。添加%JAVA_HOME%/bin
、%MAVEN_HOME%/bin
和%JBOSS_HOME%/ bin
到 PATH
环境变量。
创建一个 WildFly 8.1.0 运行时,如 第 1 章 ,EJB 3.x 入门。如 java:jboss/datasources/MySQLDS 创建 MySQL 数据源/book/application-development/9781783288908/1" linkend="ch01">第 1 章,EJB 3.x 入门 .
首先,我们需要创建一个Java EE web项目,您需要为其选择文件 | 新 | 其他。在 New 中,选择 Web | Java EE Web 项目,如下图所示:
在 Java EE Web 项目 向导中,选择 创建一个空白项目并选择WildFly 8.x Runtime
作为Target Runtime,如下图所示。运行测试以查找是否安装了所需的插件。然后,点击下一步。
指定 项目名称 (jboss- resteasy
) 和 Package (org.jboss.resteasy
),然后点击下一步如下:
指定 组 ID (org. jboss.resteasy
), Artifact Id (jboss-resteasy
), 版本(1.0.0
)和包< /strong> (org.jboss.resteasy
),然后点击下一步 ,如此处所示:
jboss-resteasy
Maven 项目被创建并被添加到 < strong>Project Explorer,如下图所示:
接下来,添加一个 JAX-RS 资源类(HelloWorldResource
),它只是一个Java 类。选择文件 | 新 | Other,并在 New 中选择 Java | 类并点击下一步。选择 Source folder (jboss-resteasy/src/main/java
) 并指定 Package (org.jboss.resteasy.rest
) 和类 < strong>名称 (HelloWorldResource
),然后点击Finish ,如此处所示:
同样,添加一个 Java 客户端类(RESTEasyClient
),如下所示:
jboss-resteasy
应用程序的目录 结构如下图所示:
将 JAX-RS-和RESTEasy相关的依赖添加到pom.xml
中,如下:
在构建中,添加 Maven 编译器插件和 Maven WAR 插件。在 Maven WAR 插件配置中,指定构建应用程序要部署到的输出目录:C:\wildfly-8.1.0.Final\standalone\deployments
目录:
完整的 pom.xml
可在本章的代码下载中找到。接下来,创建 Web 部署描述符 web.xml
。选择文件 | 新 | 其他。在 New 中,选择 JBoss Tools Web | Web Descriptor并点击Next,如下图所示:
在 New Web Descriptor File 中,选择 文件夹为WEB-INF
目录,指定名称< /span> 作为 web.xml
,并选择 Version 作为 3.1
,如下图:
web.xml
部署 描述符被添加到 WEB-INF< /code>,如下图所示:
将 RESTEasy 调度程序 servlet 添加到 web.xml
文件,包括其 URL 映射。添加 RESTEasy 扫描 JAX-RS 类所需的上下文参数。此外,为映射前缀的 RESTEasy servlet 添加上下文参数。 web.xml
文件列举如下:
Client API 是用于访问网络资源和集成的高级API与 JAX-RS 提供程序一起使用,并且包含在 javax.ws.rs.client
包中。
Client
实例 需要构建和运行客户端请求以访问或使用 Web 资源。在 RESTEasy 客户端类 RESTEasyClient.java
中,从 ClientBuilder
Client 实例> 使用 newClient()
方法如下:
可以使用 register()
方法通过 Client
对象配置提供程序、过滤器和功能。例如,org.jboss.resteasy.plugins.providers.JaxrsFormProvider.class
提供者类注册为 如下:
使用
Client 的重载
对象。附加到 URI 的路径是为了使 REST 服务能够处理多个输入:target()
方法从资源 URI 创建一个WebTarget
对象如果需要,使用
path()
方法将一个或多个路径元素添加到WebTarget
对象,该方法返回WebTarget
对象:使用重载的
request()
方法从WebTarget
对象创建请求,您需要在其中定义接受的响应媒体类型.使用重载的get()
方法为请求调用 HTTPGET
方法,以获取作为响应
对象:以
String
对象的形式获取消息实体输入流:fluent API 可用于构建和提交客户端请求,并通过链接方法调用获取响应:
在 /helloworld
URI 路径中创建一个 资源类来测试客户端
API。在相对 URI 路径 /text
处添加资源方法以从名称返回 Hello
消息。资源类HelloWorldResource
列举如下:
要测试资源类和客户端,编译、打包并部署 jboss-resteasy
应用程序到 WildFly。我们将作为 WildFly deployments
目录的输出目录添加到 Maven WAR 插件的配置中,如下所示:
右键单击 pom.xml
上的 并选择 运行作为 | Maven install,如下图所示:
jboss-resteasy
应用程序被编译、构建并输出到 WildFly 8.1 deployments
目录由 Console 中的 "strong">BUILD SUCCESS 消息,如下所示:
现在,登录到 WildFly 8.1 管理控制台并点击< span class="strong">管理部署。 jboss-resteasy.war
应用程序应列为已部署,如以下屏幕截图所示:
要测试客户端,请右键单击 Project Explorer 中的 RESTEasyClient.java
类并 < a id="id522" class="indexterm">选择 运行方式 | Java 应用程序,如下所示:
客户端应用程序运行以调用资源类并生成输出,如以下 Console 所示:
过滤器 提供 扩展功能,例如日志记录和身份验证。拦截器提供实体压缩等扩展功能。在本节中,我们将讨论 JAX-RS 2.0 实现中特定扩展点对过滤器的支持。 JAX-RS 2.0 中提供了两种类型的过滤器:客户端过滤器 和 容器过滤器。 客户端过滤器位于客户端,容器过滤器位于容器端。客户端过滤器对应的接口包含在客户端 API 中,分别是 javax.ws.rs.client.ClientRequestFilter
和 javax.ws.rs。客户端.ClientResponseFilter
。 容器过滤器的接口,包含在服务器 API 中,是 code class="literal">javax.ws.rs.container.ContainerRequestFilter 和 javax.ws.rs.container.ContainerResponseFilter
。要被 JAX-RS 运行时发现,实现接口的过滤器必须使用 @Provider
注释进行注释。创建Java类LoggingFilter
(用于容器过滤器示例)和ClientFilter
(用于客户端过滤器示例),如< span class="strong">项目浏览器。
在讨论客户端和容器过滤器之前,我们需要讨论过滤器拦截客户端和服务器之间通信的连接点:
请求/响应拦截的连接点如下图所示:
首先,我们将通过一个示例来讨论客户端过滤器。 ClientRequestFilter
在 HTTP 请求被传递到网络之前在调用管道中运行。 ClientRequestFilter
应由 @Provider
注释,这是 JAX-RS 运行时在扫描阶段发现的标记. ClientResponseFilter
在从服务器接收到响应之后并且在控件返回给应用程序之前运行。使 ClientFilter
类实现 ClientRequestFilter
和 ClientResponseFilter
接口。添加 filter(ClientRequestContext arg0)
和 filter(ClientRequestContext arg0, ClientResponseContext arg1)
方法的实现。在ClientRequestFilter
实现方法filter(ClientRequestContext arg0)
中,使用getHeaderString(
方法。例如,ClientRequestContext
的 String)Accept-Charset
和 Accept-Encoding
标头给出以下输出:
使用 setUri(URI)
方法设置新的资源 URI,如下所示:
对于客户端过滤器可能发生的问题,请参阅解决常见问题部分/span> 在本章末尾。在客户端类中,RESTEasyClient
向客户端注册客户端过滤器:
我们将使用以下根资源类 HelloWorldResource
来测试客户端过滤器:
用于测试客户端过滤器的客户端类 RESTEasyClient
列出如下:
重新部署 jboss-resteasy
应用程序。要重新部署,请右键单击 Project Explorer 中的 pom.xml
并选择 运行方式 | Maven clean,然后右键单击 pom.xml
并选择 运行方式 | Maven 安装。运行 RESTEasyClient.java
类,在 Console 屏幕中生成如下输出,如下所示:
由于我们修改了客户端过滤器中的资源URI,响应消息不是针对客户端类中指定的John Smith,而是针对史密斯,约翰。
过滤器链处理可能会中止,并使用 abortWith(Response response)
方法将响应返回给客户端。在客户端获得响应之前应用客户端响应过滤器。例如,断开过滤器链并返回 notAcceptable(null)
响应:
保持 RESTEasyClient
和 HelloWorldResource
相同,并重新部署 jboss-restaesy
应用程序。重新运行 RESTEasyClient
类以生成以下输出,其中包括如下所示的 NotAcceptableException
:
容器过滤器是服务器API过滤器。 A ContainerRequestFilter
过滤器在收到来自客户端的请求后运行。 ContainerResponseFilter
在将 HTTP 响应传递给客户端之前在响应管道中运行。接下来,我们将创建一个容器过滤器,用于记录/输出有关请求的一些信息。 ContainerRequestFilter
接口中提供了匹配前后的扩展点。匹配前过滤器在请求与资源方法匹配之前运行,匹配后过滤器在资源方法匹配后应用;默认是赛后。我们将预匹配与 @PreMatching
注释一起使用。使用 @Provider
注释过滤器类,以便 JAX-RS 运行时在扫描阶段发现过滤器。
制作示例容器过滤器LoggingFilter
,实现ContainerRequestFilter
、ContainerResponseFilter
接口,并为 filter(ContainerRequestContext requestContext)
和 filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
方法提供实现。在ContainerRequestFilter
实现方法filter(ContainerRequestContext requestContext)
中,用getMethod输出请求方法()
方法,请求 URI 使用 getUriInfo().getAbsolutePath()
,媒体类型使用 getMediaType()
,以及使用 getAcceptableMediaTypes()
的可接受媒体类型。在 LoggingFilter
中包含一个无参数构造函数,以便可以实例化过滤器。使用 register
方法将 LoggingFilter
注册到客户端配置中。注释掉 ClientFilter
的注册,因为我们将只应用 RESTEasyClient< 中的
LoggingFilter
/代码>类:
默认情况下,容器过滤器 绑定到客户端请求发送到的所有资源,但可以使用 @NameBinding
注释:
保持 RESTEasyClient
和 HelloWorldResource
与 < code class="literal">ClientFilter 示例并重新部署 jboss-restaesy
应用程序。运行 RESTEasyClient
应用程序以生成容器过滤器显示的输出,如下所示:
JAX-RS 2.0 在客户端 API 和服务器 API。默认情况下,当客户端向服务器发送请求时,它会暂停所有其他处理,直到收到响应。通过异步处理,客户端暂停与服务器的连接并在生成服务器响应并将其发送回客户端时继续处理。当响应传递给客户端时,客户端重新建立与服务器的连接并接受响应。下图说明了同步和异步请求/响应中的客户端-服务器模型:
同样,默认情况下,服务器线程会在等待外部进程完成一个客户端请求时阻止所有其他传入的客户端请求。通过异步处理,服务器暂停与客户端的连接,以便它可以接受其他客户端请求。当客户端请求的响应可用时,服务器重新建立与客户端的连接并发送请求。在本节中,我们将通过一个示例来讨论异步处理。创建 Java 类 AsyncResource
(用于根资源类)、AsyncClient
(用于客户端)和 AsyncTimeoutHandler
(用于超时处理程序)。 async
类的目录结构在 Project Explorer 中显示如下:
服务器 API 添加了 javax. ws.rs.container.AsyncResponse
接口表示异步响应,用于服务器端处理异步响应。 javax.ws.rs.container.Suspended
接口用于将暂停的 AsyncResponse
实例注入资源方法参数。 AsyncResponse
实例绑定到活动的客户端请求,可用于在响应可用时异步提供响应。当要向客户端发送响应时,AsyncResponse
实例会恢复暂停的请求。
使用 @ 注入暂停的
注释必须将返回类型声明为 void。如果注入的 AsyncResponse
的资源或 子资源方法SuspendedAsyncResponse
实例没有取消或恢复暂停的异步响应,则响应将无限期暂停。在 AsyncResource
根资源类中,添加一个资源方法(例如称为 timeout),其中注入了一个暂停的 AsyncResponse
实例使用 @Suspended
注释的资源方法参数,如下面的清单所示。模板参数 {timeout}
包含在资源方法的路径 URI 中:
在 AsyncClient
中,class 包含值 60
用于请求 URI 中的 {timeout}
模板参数,如以下清单所示:
运行 pom.xml
文件以 部署 jboss-resteasy< /代码>应用程序。当
AsyncClient
应用程序运行时,服务器不返回响应,因为异步响应被挂起并返回以下异常:
暂停 AsyncResponse
可以选择恢复请求处理,通常在响应可用时,使用 < code class="literal">resume(Object) 方法。使用ResponseBuilder
对象构建响应,可以通过Response static
方法获取ok (对象)
。使用 ResponseBuilder
方法 type(MediaType)
设置响应的媒体类型并创建一个 使用
对象。使用 build()
方法的响应resume(Object)
方法恢复暂停的请求处理以发送 Response
对象。 AsyncResource
根资源类如下:
客户端类 与 Suspended response 部分中列出的相同这一章。要编译和打包 jboss-resteasy
应用程序,右键单击 pom.xml
并选择 运行方式 | Maven 安装。启动 WildFly 8.1 服务器以部署应用程序,应用程序部署完成后,运行客户端类 AsyncClient
。右键单击 Package Explorer 中的 AsyncClient.java
并选择 运行方式 | Java 应用程序。客户端运行产生输出,如下所示:
发送的 Response
对象可能是 String
字面意思。如果在 resume(Object)
中使用了 String
文字,如此处所示,则 < strong>Hello after timeout 消息生成:
AsyncResponse
实例可以选择更新挂起集数据以设置新的挂起超时。使用 setTimeout(long time, TimeUnit unit)
方法设置新的暂停超时,如下所示:
ar
变量是 AsyncResponse
对象。新的暂停超时值将覆盖先前的超时值。在第一次调用 setTimeout
时,暂停超时已从无限期暂停变为暂停指定的超时值。 javax.ws.rs.container.TimeoutHandler
接口用于提供超时事件的自定义解决方案。超时事件的默认解决方案是让 JAX-RS 2.0 运行时生成 Service不可用
异常。使用 setTimeoutHandler(TimeoutHandler handler)
方法设置暂停超时处理程序:
用于设置挂起超时处理程序的 AsyncResource
类列出如下:
使 AsyncTimeoutHandler
超时处理程序类实现TimeoutHandler
界面。在 AsyncTimeoutHandler
中,实现 handleTimeout(AsyncResponse asyncResponse)
方法,可以使用以下方法之一处理暂停超时:
可以使用
resume(Object)
方法恢复异步响应可以使用
resume(Throwable)
方法抛出异常来恢复响应可以使用
cancel()
方法取消响应可以使用
setTimeout(long time, TimeUnit unit)
方法的另一个调用来延长挂起超时
在 AsyncTimeoutHandler
类中,使用 resume( Object)
方法向客户端返回响应。 AsyncTimeoutHandler
类列举如下:
使用 Maven 重新部署 应用程序并重新运行 AsyncClient
类。应用新的暂停超时,响应暂停 60 秒,如消息 timeout-enter with timeout=60s
所示,如下所示:
当请求处理恢复时,如下图所示的响应被发送到客户端并从客户端类AsyncClient.java
输出:
在之前的示例中,我们在超时处理程序中恢复了请求。可以在资源方法中恢复请求,其中在新的挂起超时运行之前设置了新的挂起超时和超时处理程序,如下面清单中的资源方法所示:
要应用新的挂起超时,必须在超时处理程序中恢复请求。如果设置了新的挂起超时和超时处理程序,并且挂起的超时处理程序不执行任何操作,则默认解决方案是使用 ServiceUnAvailableException
异常恢复请求处理。要恢复发送响应的请求,必须使用 resume(Object)
方法显式恢复请求。
我们有 as 但只讨论了服务器 API 中的异步支持。客户端 API 中也提供了异步请求处理。可以使用 async()
方法异步发送客户端请求。
异步调用资源意味着调用立即返回。或者,可以使用 InvocationCallback
接口注册回调。实现 completed(RESPONSE response)
和 failed(Throwable throwable)
方法。 completed(RESPONSE response)
方法在调用成功完成时调用,failed(Throwable throwable)
方法在调用成功时调用调用失败。在 AsyncClient.java
客户端中异步发出客户端请求,如下所示:
在资源方法中设置暂停的超时和超时处理程序,并在超时处理程序中恢复请求,如下所示:
当 应用程序运行时,调用立即返回并显示消息 Call to get returns immediate
(消息可以获取输出并继续处理而不会注意到消息)。
暂停超时以消息开始。这显示在以下屏幕截图中:
暂停超时运行后,将返回响应,如以下屏幕截图所示。调用立即返回时的消息输出也显示在此处: