Hosting Static Content and JAX-RS Services Under the Same Root Context

心已入冬 提交于 2019-12-19 03:18:07

问题


We have multiple Java web apps packaged as WARs all packaged in an EAR. Our RESTful services are built using JAX-RS and in version specific WARs.

We'd like to add static content for each of these version specific WARs, but use the root context (of the WAR) for both the static content and the RESTful service API calls, such that all of the following URLs will work:

{hostname}/v1/swagger.yaml  <-- Static Content describing the v1 API
{hostname}/v1/orders/{uid}  <-- JAX-RS RESTful API (v1)

{hostname}/v2/swagger.yaml  <-- Static Content describing the v2 API
{hostname}/v2/orders/{uid}  <-- JAX-RS RESTful API (v2)

The following deployment structure is what we currently have, which works for the JAX-RS services, but not the static content. In other words these URLs work:

{hostname}/v1/orders/{uid}  <-- JAX-RS RESTful API (v1)
{hostname}/v2/orders/{uid}  <-- JAX-RS RESTful API (v2)

But the problem is that these URLS are inaccessible:

{hostname}/v1/swagger.yaml  <-- Static Content describing the v1 API
{hostname}/v2/swagger.yaml  <-- Static Content describing the v2 API

Question: How do we get these static URLs to work?

Here's the exploded EAR:

example.ear

    META-INF
        application.xml

    v1.war
        swagger.yaml
        WEB-INF
            web.xml
            classes
                ApplicationV1.class
                OrdersResourceV1.class

    v2.war
        swagger.yaml
        WEB-INF
            web.xml
            classes
                ApplicationV2.class
                OrdersResourceV2.class

Here's the EARs application.xml:

<?xml version="1.0"?>
<application xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_6.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="6">
  <application-name>...</application-name>
  <module>
    <web>
      <web-uri>v1.war</web-uri>
      <context-root>/v1</context-root>
    </web>
  </module>
  <module>
    <web>
      <web-uri>v2.war</web-uri>
      <context-root>/v2</context-root>
    </web>
  </module>
  <module>
    <web>
      <web-uri>another.war</web-uri>
      <context-root>/</context-root>
    </web>
  </module>
</application>

Here's the v1 & v2 web.xml:

<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
</web-app>

Here's the ApplicationV1.java (JAX-RS) implementation, notice the URL mapping:

import java.util.HashSet;
import java.util.Set;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;


@ApplicationPath("/")
public class ApplicationV1 extends Application {

  private Set<Object> singletons = new HashSet<Object>();

  public ApplicationV1() {
    singletons.add(new OrdersResourceV1());
  }

  @Override
  public Set<Object> getSingletons() {
    return singletons;
  }

}

Here's the OrdersResourceV1.java (JAX-RS) implementation, notice the URL mapping:

import javax.enterprise.context.RequestScoped;
import javax.ws.rs.*;

@RequestScoped
@Path("/orders")
public class OrdersResourceV1 {

  @GET
  @Path("/{uid}")
  @Produces("application/json;charset=UTF-8")
  public Response getOrder(@PathParam("uid") String orderUid) {
    <ommited for brevity>
  }

}

I do know that if we changed ApplicationV*.java's mapping to @ApplicationPath("/services"), that the static content will be assessable, but the URLs will then be as follows, but it's our goal to not include any extraneous path elements like this.

{hostname}/v1/swagger.yaml  <-- Static Content describing the v1 API
{hostname}/v1/services/orders/{uid} <-- JAX-RS RESTful API (v1)

{hostname}/v2/swagger.yaml  <-- Static Content describing the v2 API
{hostname}/v2/services/orders/{uid} <-- JAX-RS RESTful API (v2)

So my question is, how do we get the JAX-RS and static content under the root context for the WAR (/v1 and /v2)? Is there a different way to map the URLs? Or is there a configuration option that allows for a static fallback if JAX-RS doesn't have a handler for the URL?

I'm hoping that this can be solved a JavaEE generic fashion, but if not, we're using Wildfly 8.1 on Java8.


回答1:


So I found a solution (tested) that works. As stated in the Resteasy Documentation - RESTEasy as a servlet Filter:

The downside of running Resteasy as a Servlet is that you cannot have static resources like .html and .jpeg files in the same path as your JAX-RS services. Resteasy allows you to run as a Filter instead. If a JAX-RS resource is not found under the URL requested, Resteasy will delegate back to the base servlet container to resolve URLs.

web.xml example

<web-app>
    <filter>
        <filter-name>Resteasy</filter-name>
        <filter-class>
            org.jboss.resteasy.plugins.server.servlet.FilterDispatcher
        </filter-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>com.restfully.shop.services.ShoppingApplication</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>Resteasy</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>



回答2:


I found another solution (thanks to https://stackoverflow.com/a/3582215/589525 ). This works for RestEasy on JBoss 6. Simply add the default servlet to the mapping

<!--existing mapping: -->
<servlet-mapping>
  <servlet-name>Resteasy</servlet-name>
  <url-pattern>/rest/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
  <servlet-name>default</servlet-name>
  <url-pattern>*</url-pattern>
</servlet-mapping>


来源:https://stackoverflow.com/questions/30111978/hosting-static-content-and-jax-rs-services-under-the-same-root-context

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!