具有Resteasy的多个端点

pbe*_*ean 11 java rest spring jax-rs resteasy

我在一个应用程序中有两个单独的REST服务.让我们说一个主要的"人"服务和一个辅助"管理"服务.我想要的是在服务器上的不同路径中公开它们.我正在使用JAX-RS,RESTEasy和Spring.

例:

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

@Path("/management")
public interface ManagementService {
  // Stuff
}
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

PeopleServiceManagementService实施只是春豆.上面的web.xml配置将它们都暴露在外/public(因此分别具有/public/people/public/management).

我想要完成的是暴露PeopleServiceon /public,以便完整路径将成为/public/people并暴露ManagementServiceon /internal,以便它的完整路径将成为/internal/management.

不幸的是,我无法更改@Path注释的值.

我该怎么办?

Ant*_*ton 15

实际上你可以.经过几个小时的调试后,我想出了这个:

1)在你的声明中声明多个resteasy servlet web.xml(在我的情况下为两个)

<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>  
Run Code Online (Sandbox Code Playgroud)

请注意我们初始化个人resteasy.servlet.mapping.prefixresteasy.resources每个servlet 的事实.请不要忘记包含任何botstrap类作为过滤器或servlet!并禁用自动扫描.

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

    }

}
Run Code Online (Sandbox Code Playgroud)

注册它以获取对您服务的任何请求(此处我将其用于所有简化请求):

<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> 
Run Code Online (Sandbox Code Playgroud)

这就是它!现在你有两个不同的REST服务,它们位于不同的前缀下:/openrest这意味着服务所有的公共请求/protectedrest,并关注应用程序中的所有私有内容.

那么它为什么会起作用(或者为什么它不起作用)呢?

当你openrest第一次调用实例时,它会尝试初始化自己,并在完成时将状态保存在全局中,servletContext如下所示:

 servletContext.setAttribute(ResteasyProviderFactory.class.getName(), deployment.getProviderFactory());
 servletContext.setAttribute(Dispatcher.class.getName(), deployment.getDispatcher());
Run Code Online (Sandbox Code Playgroud)

如果你愿意,那么你的第二个电话/protectedrest就会得到相同的配置!这就是为什么你需要在某些地方清理这些信息.这就是为什么我们使用我们CleanupFilter清空上下文的原因,所以全新的rest servlet可以使用我们声明的所有init参数初始化自己.

这是一个黑客攻击,但它可以解决问题.

该解决方案针对RESTEasy 2.3.6进行了测试

EDITED

兼容3.0.9.final!


Xav*_*lon 2

AFAIK,您的 JAX-RS 实现不能有多个 servlet 映射。您可以做的是:将 RESTEasy 映射到'/'(或者'/api'例如,如果您的应用程序有其他资源需要服务,并且您不希望 JAX-RS 部分干扰),然后使用以下@Path注释:

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

@Path("/internal/management")
public interface ManagementService {
  // Stuff
}
Run Code Online (Sandbox Code Playgroud)