具有 Resteasy 的多个端点

2022-09-04 20:09:32

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

和 实现只是 Spring bean。上面的配置将分别公开它们(因此具有 和)。PeopleServiceManagementServiceweb.xml/public/public/people/public/management

我想完成的是公开 on ,这样完整的路径就会变成 on,而暴露 on ,这样它的完整路径就会变成 。PeopleService/public/public/peopleManagementService/internal/internal/management

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

我应该怎么做?


答案 1

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

1)在你的案例中声明多个不安的服务(在我的情况下是两个)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>  

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

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

那么为什么它有效(或者为什么它不起作用)?

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

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

如果你让它成为你的调用你的第二个将获得相同的配置!这就是为什么您需要在某个地方清理此信息的原因。这就是为什么我们使用我们的'清空上下文',这样全新的 rest servlet 就可以用我们声明的所有 init 参数初始化自身。/protectedrestCleanupFilter

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

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

编辑

也适用于3.0.9.final!


答案 2

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

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

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