복붙노트

[SPRING] Resteasy로 여러 끝점 제공

SPRING

Resteasy로 여러 끝점 제공

하나의 응용 프로그램에서 2 개의 별도 REST 서비스를 제공합니다. 메인 "사람"서비스와 보조 "관리"서비스를 가정 해 봅시다. 내가 원하는 것은 서버에서 별도의 경로에 그들을 노출하는 것입니다. JAX-RS, RESTEasy 및 Spring을 사용하고 있습니다.

예:

@Path("/people")
public interface PeopleService {
  // Stuff
}

@Path("/management")
public interface ManagementService {
  // Stuff
}

web.xml에는 현재 다음과 같은 설정이 있습니다.

<listener>
    <listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
</listener>

<listener>
    <listener-class>org.jboss.resteasy.plugins.spring.SpringContextLoaderListener</listener-class>
</listener>

<context-param>
    <param-name>resteasy.servlet.mapping.prefix</param-name>
    <param-value>/public</param-value>
</context-param>

<servlet>
    <servlet-name>Resteasy</servlet-name>
    <servlet-class>
        org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
    </servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>Resteasy</servlet-name>
    <url-pattern>/public/*</url-pattern>
</servlet-mapping>

PeopleService 및 ManagementService 구현은 스프링 빈일뿐입니다. 위의 web.xml 구성은 / public (따라서 각각 / public / people 및 / public / management를 가짐)에 둘 다 노출합니다.

내가 달성하고자하는 것은 전체 경로가 / public / people이 될 수 있도록 PeopleService를 / public에 노출하여 전체 경로가 / internal / management가되도록 / internal에서 ManagementService를 노출하는 것입니다.

불행히도 @Path 주석의 값을 변경할 수는 없습니다.

어떻게해야합니까?

해결법

  1. ==============================

    1.실제로하실 수 있습니다. 몇 시간 동안 디버깅을 한 후에 나는 이것을 생각해 냈다.

    실제로하실 수 있습니다. 몇 시간 동안 디버깅을 한 후에 나는 이것을 생각해 냈다.

    1) web.xml에 여러 개의 resteasy 서블릿을 선언하십시오 (제 경우에는 2 개).

    <servlet>
        <servlet-name>resteasy-servlet</servlet-name>
        <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
        <init-param>
            <param-name>resteasy.servlet.mapping.prefix</param-name>
            <param-value>/openrest</param-value>
        </init-param>       
        <init-param>
            <param-name>resteasy.resources</param-name>
            <param-value>com.mycompany.rest.PublicService</param-value>
        </init-param>
    </servlet>
    
        <servlet>
        <servlet-name>private-resteasy-servlet</servlet-name>
        <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
        <init-param>
            <param-name>resteasy.servlet.mapping.prefix</param-name>
            <param-value>/protectedrest</param-value>
        </init-param>       
        <init-param>
            <param-name>resteasy.resources</param-name>
            <param-value>com.mycompany.rest.PrivateService</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>private-resteasy-servlet</servlet-name>
        <url-pattern>/protectedrest/*</url-pattern>
    </servlet-mapping>      
    
    <servlet-mapping>
        <servlet-name>resteasy-servlet</servlet-name>
        <url-pattern>/openrest/*</url-pattern>
    </servlet-mapping>  
    

    각 서블릿에 대해 개인 resteasy.servlet.mapping.prefix 및 resteasy.resources를 초기화한다는 사실에주의하십시오. 어떤 보봇 (botstrap) 클래스도 필터 나 서블릿으로 포함시키지 마십시오! 자동 스캔도 비활성화하십시오.

    2) 컨텍스트에서 저장하는 RESTeasy의 전역 정보에서 응용 프로그램을 정리하는 필터를 만듭니다.

    public class ResteasyCleanupFilter implements Filter {
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            // TODO Auto-generated method stub
    
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
                ServletException {
            request.getServletContext().setAttribute(ResteasyProviderFactory.class.getName(), null);
            request.getServletContext().setAttribute(Dispatcher.class.getName(), null);
            chain.doFilter(request, response);
    
    
        }
    
        @Override
        public void destroy() {
            // TODO Auto-generated method stub
    
        }
    
    }
    

    귀하의 서비스에 대한 요청을 위해 등록하십시오 (여기서는 단순성을 위해 모든 요청에 ​​사용했습니다).

    <filter>
        <filter-name>CleanupFilter</filter-name>
        <filter-class>com.mycompany.ResteasyCleanupFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>CleanupFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping> 
    

    이제는 서로 다른 접두사 아래에 두 가지 REST 서비스가 있습니다. / openrest는 모든 공개 요청을 처리하기위한 것이고 / / protectedrest는 앱의 모든 비공개 정보를 관리합니다.

    그렇다면 왜 작동합니까 (또는 왜 작동하지 않는 것입니까?)?

    openrest 인스턴스를 처음 호출하면 자신을 초기화하려고 시도하고 완료되면 다음과 같이 전역 servletContext에 상태를 저장합니다.

     servletContext.setAttribute(ResteasyProviderFactory.class.getName(), deployment.getProviderFactory());
     servletContext.setAttribute(Dispatcher.class.getName(), deployment.getDispatcher());
    

    그리고 두 번째 / protectrest에 대한 전화가되도록하면 같은 구성을 갖게됩니다! 그래서이 정보를 정리해야합니다. 그래서 컨텍스트를 비우는 CleanupFilter를 사용하여 새로운 rest servlet이라는 브랜드가 선언 한 모든 초기화 매개 변수로 자체를 초기화 할 수있었습니다.

    이것은 해킹이지만 트릭입니다.

    이 솔루션은 RESTEasy 2.3.6

    편집 됨

    3.0.9.final에서도 작동합니다!

  2. ==============================

    2.AFAIK, JAX-RS 구현을위한 서블릿 매핑을 여러 개 가질 수는 없습니다. 할 수있는 일은 : RESTEasy를 '/'(또는 애플리케이션에 다른 리소스가 있고 JAX-RS가 간섭하지 않도록하려는 경우 '/ api')로 매핑 한 다음 다음과 같은 @Path 주석을 사용합니다 :

    AFAIK, JAX-RS 구현을위한 서블릿 매핑을 여러 개 가질 수는 없습니다. 할 수있는 일은 : RESTEasy를 '/'(또는 애플리케이션에 다른 리소스가 있고 JAX-RS가 간섭하지 않도록하려는 경우 '/ api')로 매핑 한 다음 다음과 같은 @Path 주석을 사용합니다 :

    @Path("/public/people")
    public interface PeopleService {
      // Stuff
    }
    
    @Path("/internal/management")
    public interface ManagementService {
      // Stuff
    }
    
  3. from https://stackoverflow.com/questions/20687251/multiple-endpoints-with-resteasy by cc-by-sa and MIT license