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 运行时),请执行以下步骤:

  1. @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 注释( 扫描阶段)的类。

  2. 在 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 注释应属于绑定该过滤器所需的所有内容。但是,在实践中,标准方法非常不灵活,如果大型项目中纳入了许多库,则可能会导致供应商冲突。