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 인터페이스”

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에서 Cryostat-RS 서버 끝점을 정의할 때(예: 18.1절. “Cryostat-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의 비표준 요구 사항입니다. Cryostat-RS 표준에 따라 @Provider 주석은 필터를 바인딩하는 데 필요한 모든 주석이어야 합니다. 그러나 실제로 표준 접근 방식은 다소 유연하지 않으며 많은 라이브러리가 대규모 프로젝트에 포함될 때 충돌하는 공급자로 이어질 수 있습니다.