java - 使用 Resteasy 的多个端点

标签 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分别)。

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

很遗憾,我无法更改 @Path 注释的值。

我该怎么做?

最佳答案

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

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。 请不要忘记包含任何 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 意味着服务所有公共(public)请求和 /protectedrest 负责所有应用程序中的私有(private)内容。

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

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

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

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

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

此解决方案已针对 RESTEasy 2.3.6

进行了测试

已编辑

也适用于 3.0.9.final!

关于java - 使用 Resteasy 的多个端点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20687251/

相关文章:

java - 使用 Java 将数据发送到本地托管网站上的表单

java - Android Activity 菜单

java - Spring Boot 部署 - NoClassDefFoundError

rest - PUT 的 HTTP 状态代码

Java - Selenium Webdriver : Entering text into text field, 并自动从文本字段中删除

java - AbstractAction 作为 WindowListener

java - Hibernate Envers 条件审核,运行时忽略自定义 EnversIntegrator

java - Hibernate、Spring 和 HSQL : Table not Found Exception

Django、REST 和 Angular 路由

c# - 如何使用 HttpClient 发帖?