61.7. 实体写入程序 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
接口,您可以截获消息正文(实体
对象),因为它正在在服务器端或客户端进行写入。您可以在以下任意上下文中使用实体写入器:
- 服务器端- 如果作为服务器端拦截器绑定,则实体写入器会截获响应消息正文,然后被绑定并发回到客户端。
- 客户端侧- 如果作为客户端拦截器绑定,则实体写入器在请求消息正文之前截获请求消息正文,并将其发送到服务器。
WriterInterceptorContext interface
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)的实体写入器示例(优先级为 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 对象或 javax.ws.rs.client
.client.client. client.client
对象上直接注册实体写入器拦截器。这意味着写入器拦截器可以选择性地应用到不同的范围,以便只有某些 URI 路径受到拦截器的影响。
例如,以下代码演示了如何注册 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 拦截器类,如以下代码片段所示:// 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 拦截器添加到
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
注释应当是绑定拦截器所需的所有内容。但是,在实践中,标准方法非常不灵活,如果大型项目中纳入了许多库,则可能会导致供应商冲突。