61.7. Entity Writer Interceptor
概述
本节介绍如何在客户端或服务器端 写入消息正文时截获实体拦截器。这通常可用于请求正文的通用转换,如加密和解密、压缩和解压缩。
WriterInterceptor 接口
javax.ws.rs.ext.WriterInterceptor
接口定义如下:
// Java ... package javax.ws.rs.ext; public interface WriterInterceptor { void aroundWriteTo(WriterInterceptorContext context) throws java.io.IOException, javax.ws.rs.WebApplicationException; }
通过实施 WriterInterceptor
接口,您可以截获消息正文(实体
对象),因为它在服务器端或客户端上写入。您可以在以下任何一个上下文中使用实体拦截器:
- 服务器端- 如果作为服务器端拦截器绑定,实体写器将截获响应消息正文,紧接在响应消息正文后再发送回客户端。
- client side- 如果作为客户端侧拦截器绑定,实体写入器会截获请求消息正文,紧接在请求消息正文被封锁并发送到服务器。
WriterInterceptorContext 接口
WriterInterceptor
的 aroundWriteTo
方法收到类型为 javax.ws.rs.ext.WriterInterceptorContext
的参数,可用于访问消息正文(实体
对象)和消息元数据。
WriterInterceptorContext
接口定义如下:
// Java ... package javax.ws.rs.ext; import java.io.IOException; import java.io.OutputStream; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MultivaluedMap; public interface WriterInterceptorContext extends InterceptorContext { void proceed() throws IOException, WebApplicationException; Object getEntity(); void setEntity(Object entity); OutputStream getOutputStream(); public void setOutputStream(OutputStream os); MultivaluedMap<String, Object> getHeaders(); }
InterceptorContext 接口
WriterInterceptorContext
接口也支持从基础 InterceptorContext
接口继承的方法。有关 InterceptorContext
的定义,请参阅 “InterceptorContext 接口”一节。
客户端上的实现示例
要为客户端实施实体拦截器,请定义一个实现 WriterInterceptor
接口的类。
例如,以下代码显示了客户端侧的实体写器(优先级为 10)的示例,它将额外文本行附加到传出请求的消息正文中:
// Java package org.jboss.fuse.example; import java.io.IOException; import java.io.OutputStream; import javax.ws.rs.WebApplicationException; import javax.ws.rs.ext.WriterInterceptor; import javax.ws.rs.ext.WriterInterceptorContext; import javax.annotation.Priority; @Priority(value = 10) public class SampleClientWriterInterceptor implements WriterInterceptor { @Override public void aroundWriteTo(WriterInterceptorContext interceptorContext) throws IOException, WebApplicationException { OutputStream outputStream = interceptorContext.getOutputStream(); String appendedContent = "\nInterceptors always get the last word in."; outputStream.write(appendedContent.getBytes()); interceptorContext.setOutputStream(outputStream); interceptorContext.proceed(); } }
服务器端的实现示例
要为服务器端实施实体拦截器,请定义一个实施 WriterInterceptor
接口的类,并使用 @Provider
注释给它添加注解。
例如,以下代码显示了服务器端的实体写器示例(优先级为 10),这会将额外的文本行附加到传出请求的消息正文中:
// Java package org.jboss.fuse.example; import java.io.IOException; import java.io.OutputStream; import javax.ws.rs.WebApplicationException; import javax.ws.rs.ext.Provider; import javax.ws.rs.ext.WriterInterceptor; import javax.ws.rs.ext.WriterInterceptorContext; import javax.annotation.Priority; @Priority(value = 10) @Provider public class SampleServerWriterInterceptor implements WriterInterceptor { @Override public void aroundWriteTo(WriterInterceptorContext interceptorContext) throws IOException, WebApplicationException { OutputStream outputStream = interceptorContext.getOutputStream(); String appendedContent = "\nInterceptors always get the last word in."; outputStream.write(appendedContent.getBytes()); interceptorContext.setOutputStream(outputStream); interceptorContext.proceed(); } }
在客户端绑定 writer 拦截器
使用 JAX-RS 2.0 客户端 API,您可以在 javax.ws.rs. client.Client 对象或
对象上直接注册实体拦截器。实际上,这意味着 writer interceptor 可以选择性地应用到不同的范围,以便只有特定的 URI 路径会受到拦截器的影响。
javax.ws.rs
.client.WebTarget
例如,以下代码演示了如何注册 SampleClientReaderInterceptor
拦截器,使其适用于使用 client
对象进行的所有调用:
// Java ... import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Invocation; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.Response; ... Client client = ClientBuilder.newClient(); client.register(SampleClientReaderInterceptor.class);
有关使用 JAX-RS 2.0 客户端注册拦截器的详情,请参考 第 49.5 节 “配置客户端端点”。
在服务器端绑定写器
要在服务器端 绑定 拦截器(即要将它安装到 Apache CXF 运行时中),请执行以下步骤:
将
@Provider
注释添加到 writer interceptor 类,如以下代码片段所示:// Java package org.jboss.fuse.example; ... import javax.ws.rs.WebApplicationException; import javax.ws.rs.ext.Provider; import javax.ws.rs.ext.WriterInterceptor; import javax.ws.rs.ext.WriterInterceptorContext; import javax.annotation.Priority; @Priority(value = 10) @Provider public class SampleServerWriterInterceptor implements WriterInterceptor { ... }
当写器实施加载到 Apache CXF 运行时中时,REST 实施会自动扫描加载的类,以搜索标有
@Provider
注解( 扫描阶段)。在 XML 中定义 JAX-RS 服务器端点(例如,请参阅 第 18.1 节 “配置 JAX-RS 服务器端点”)时,将 writer interceptor 添加到
jaxrs:providers
元素中的供应商列表中。<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs" xmlns:cxf="http://cxf.apache.org/blueprint/core" ... > ... <jaxrs:server id="customerService" address="/customers"> ... <jaxrs:providers> <ref bean="interceptorProvider" /> </jaxrs:providers> <bean id="interceptorProvider" class="org.jboss.fuse.example.SampleServerWriterInterceptor"/> </jaxrs:server> </blueprint>
注意此步骤是 Apache CXF 的非标准要求。根据 JAX-RS 标准,严格说,
@Provider
注释应全部是绑定拦截器所必需的。但是在实践中,标准方法有些不灵活,当许多库包含在大型项目中时,可能会导致禁止提供程序。