61.3. 컨테이너 응답 필터

61.3.1. 개요

이 섹션에서는 서버 측에서 나가는 응답 메시지를 가로채는 데 사용되는 컨테이너 응답 필터 를 구현하고 등록하는 방법을 설명합니다. 컨테이너 응답 필터는 응답 메시지에 헤더를 자동으로 채우는 데 사용할 수 있으며 일반적으로 모든 종류의 일반 응답 필터에 사용할 수 있습니다.

61.3.2. 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 확장 포인트에 대한 필터를 생성하여 호출 응답 메시지를 필터링할 수 있습니다.

참고

컨테이너 응답 필터는 요청 메시지( requestContext 인수를 통해) 및 응답 메시지( responseContext 메시지를 통해) 모두에 액세스할 수 있지만 이 단계에서 응답만 수정할 수 있습니다.

61.3.3. ContainerResponseContext 인터페이스

ContainerResponseFilter필터 방법은 javax.ws.rs.container.ContainerRequestContext 유형의 인수와 유형 javax.ws.rs.container.ContainerResponseContext 의 인수이며, 발신 응답 메시지 및 관련 메타데이터에 액세스하는 데 사용할 수 있는 두 가지 인수를 수신합니다. “ContainerRequestContext interface”

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);
}

61.3.4. 샘플 구현

ContainerResponse 확장 포인트(즉, 서버 측에서 호출이 실행된 후 필터가 실행되는 컨테이너 응답 필터)를 구현하려면 ContainerResponseFilter 인터페이스를 구현하는 클래스를 정의합니다.

예를 들어 다음 코드는 우선 순위가 10인 ContainerResponse 확장 지점에 설치된 간단한 컨테이너 응답 필터의 예를 보여줍니다.

// 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!");
    }
  }
}

61.3.5. 서버 응답 필터 바인딩

서버 응답 필터(즉, 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 Server 엔드 포인트 구성”참조), 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 주석은 필터를 바인딩하는 데 필요한 모든 것이어야 합니다. 그러나 실제로는 표준 접근 방식은 다소 무독하며 많은 라이브러리가 대규모 프로젝트에 포함될 때 번들링 공급자로 이어질 수 있습니다.