具有Resteasy的多个端点

时间:2013-12-19 16:49:14

标签: java spring rest jax-rs resteasy

我在一个应用程序中有两个单独的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>

PeopleServiceManagementService实现只是Spring bean。 以上web.xml配置会在/public上公开它们(因此分别有/public/people/public/management)。

我想要实现的是在PeopleService上公开/public,以便完整路径变为/public/people并在ManagementService上公开/internal ,使其完整路径变为/internal/management

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

我该怎么做?

2 个答案:

答案 0 :(得分:15)

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

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

<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>  

请注意我们为每个servlet初始化个人resteasy.servlet.mapping.prefixresteasy.resources这一事实。 请不要忘记 NOT 包含任何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

    }

}

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

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

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

这是一个黑客,但它可以解决问题。

测试该解决方案的RESTEasy 2.3.6

<强> EDITED

也适用于3.0.9.final!

答案 1 :(得分:2)

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

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

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