61.3. 容器响应过滤器
概述
本节介绍如何实施和注册 容器响应过滤器,该过滤器 用于截获服务器端的传出响应消息。容器响应过滤器可用于在响应消息中自动填充标头,一般可用于任何类型的通用响应处理。
ContainerResponseFilter 接口
javax.ws.rs.container.ContainerResponseFilter
接口定义如下:
// Java ... package javax.ws.rs.container; import java.io.IOException; public interface ContainerResponseFilter { public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException; }
通过实施 ContainerResponseFilter
,您可以在服务器端为 ContainerResponse
扩展点创建一个过滤器,它会在调用 执行后 过滤响应消息。
容器响应过滤器可让您同时访问请求消息(通过 请求Context
参数)和响应消息(通过 responseContext
消息),但这个阶段只能修改响应。
ContainerResponseContext 接口
ContainerResponseFilter
的 过滤器
方法接收了两个参数:参数 javax.ws.rs.container.ContainerRequestContext
(请参阅 “ContainerRequestContext 接口”一节);以及类型为 javax.ws.rs.container.ContainerResponseContext
的参数,它可用于访问传出响应消息及其相关元数据。
ContainerResponseContext
接口定义如下:
// Java ... package javax.ws.rs.container; import java.io.OutputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.net.URI; import java.util.Date; import java.util.Locale; import java.util.Map; import java.util.Set; import javax.ws.rs.core.EntityTag; import javax.ws.rs.core.Link; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.NewCookie; import javax.ws.rs.core.Response; import javax.ws.rs.ext.MessageBodyWriter; public interface ContainerResponseContext { public int getStatus(); public void setStatus(int code); public Response.StatusType getStatusInfo(); public void setStatusInfo(Response.StatusType statusInfo); public MultivaluedMap<String, Object> getHeaders(); public abstract MultivaluedMap<String, String> getStringHeaders(); public String getHeaderString(String name); public Set<String> getAllowedMethods(); public Date getDate(); public Locale getLanguage(); public int getLength(); public MediaType getMediaType(); public Map<String, NewCookie> getCookies(); public EntityTag getEntityTag(); public Date getLastModified(); public URI getLocation(); public Set<Link> getLinks(); boolean hasLink(String relation); public Link getLink(String relation); public Link.Builder getLinkBuilder(String relation); public boolean hasEntity(); public Object getEntity(); public Class<?> getEntityClass(); public Type getEntityType(); public void setEntity(final Object entity); public void setEntity( final Object entity, final Annotation[] annotations, final MediaType mediaType); public Annotation[] getEntityAnnotations(); public OutputStream getEntityStream(); public void setEntityStream(OutputStream outputStream); }
实现示例
要为 ContainerResponse
扩展点实施容器响应过滤器(即,在服务器端执行调用后执行过滤器),请定义一个实现 ContainerResponseFilter
接口的类。
例如,以下代码显示了在 ContainerResponse
扩展点中安装的简单容器响应过滤器示例,其优先级为 10:
// Java package org.jboss.fuse.example; import javax.annotation.Priority; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerResponseContext; import javax.ws.rs.container.ContainerResponseFilter; import javax.ws.rs.ext.Provider; @Provider @Priority(value = 10) public class SampleContainerResponseFilter implements ContainerResponseFilter { public SampleContainerResponseFilter() { System.out.println("SampleContainerResponseFilter starting up"); } @Override public void filter( ContainerRequestContext requestContext, ContainerResponseContext responseContext ) { // This filter replaces the response message body with a fixed string if (responseContext.hasEntity()) { responseContext.setEntity("New message body!"); } } }
绑定服务器响应过滤器
要 绑定 服务器响应过滤器(即,将其安装到 Apache CXF 运行时),请执行以下步骤:
将
@Provider
注释添加到容器响应过滤器类,如以下代码片段所示:// Java package org.jboss.fuse.example; import javax.annotation.Priority; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerResponseContext; import javax.ws.rs.container.ContainerResponseFilter; import javax.ws.rs.ext.Provider; @Provider @Priority(value = 10) public class SampleContainerResponseFilter implements ContainerResponseFilter { ... }
当容器响应过滤器实现加载到 Apache CXF 运行时时,REST 实施会自动扫描加载的类,以搜索标有
@Provider
注释( 扫描阶段)的类。在 XML 中定义 JAX-RS 服务器端点(例如,查看 第 18.1 节 “配置 JAX-RS 服务器端点”)时,将服务器响应过滤器添加到
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="filterProvider" /> </jaxrs:providers> <bean id="filterProvider" class="org.jboss.fuse.example.SampleContainerResponseFilter"/> </jaxrs:server> </blueprint>
注意此步骤是 Apache CXF 非标准要求。严格根据 JAX-RS 标准进行说明,
@Provider
注释应属于绑定该过滤器所需的所有内容。但是,在实践中,标准方法非常不灵活,如果大型项目中纳入了许多库,则可能会导致供应商冲突。