JAX-RS应用程序在根上下文中 - 如何完成?

时间:2012-06-03 21:47:40

标签: java jax-rs

我想让我的JAX-RX应用程序从根上下文开始,所以我的URL将是

http://example.com/restfullPath

而不是

http://example.com/rest/restfullPath

我从此

切换了我的应用程序注释
@ApplicationPath("/rest/*")

到这个

@ApplicationPath("/*")

但似乎它接管了服务文件,例如/index.html

有没有办法在根应用程序上下文中运行JAX-RS但仍然提供静态页面?

在JBOSS论坛上看来这是asked before,但解决方案并不实用

5 个答案:

答案 0 :(得分:38)

这可能不是Servlet规范限制的错误。有关如何处理JAX-RS @ApplicationPath的详细信息是特定于实现的,我不能代表所有实现,但我猜想典型的方法是将其用作servlet URL模式。看看Jersey的ServletContainerInitializer实现作为一个例子,你会发现addServletWithApplication() method负责创建servlet和映射来处理请求,你可以看到它确实使用了来自{的路径。 {1}}作为Jersey ServletContainer的映射路径。

不幸的是,从远古时代开始,Servlet规范只允许少数几种将servlet映射到URL路径的方法。在Section 12.2 of the spec中给出的Servlet 3.0的当前选项 - 遗憾的是仅作为PDF提供,因此不能按部分链接 - 是:

  • @ApplicationPath,其中初始/.../*为零个或多个路径元素
  • /...其中*.<ext>是匹配
  • 的扩展名
  • 空字符串,仅映射到空路径/上下文根
  • <ext>,单斜杠,表示上下文中的“默认”servlet,它处理与其他任何内容不匹配的任何内容
  • 任何其他字符串,被视为匹配
  • 的文字值

规范的相同部分对匹配规则应该应用的顺序也有特定的规则,但是短版本是这样的:要在上下文根处创建资源类应答请求,您必须使用{{ 1}}或/作为路径。如果使用/,那么您将替换容器的默认servlet,它通常负责处理静态资源。如果你使用/*,那么你就太贪婪了,并说它应该始终匹配所有的东西,并且永远不会调用默认的servlet。

因此,如果我们接受我们在由servlet URL模式的限制确定的框内,我们的选项相当有限。以下是我能想到的:

1)使用/,并通过名称或扩展名将静态资源显式映射到容器的默认servlet(Tomcat和Jetty中名为“default”,不确定其他人)。在web.xml中,它看起来像

/*

ServletContextInitializer,如

@ApplicationPath("/")

由于编写匹配规则的方式,扩展模式胜过默认的servlet,因此只需要在每个静态文件扩展名之间添加映射,只要这些扩展模块与任何“扩展”之间没有重叠即可。可能出现在您的API中。这非常接近您链接的论坛帖子中提到的不受欢迎的选项,我只是提到它的完整性并添加了ServletContextInitializer部分。

2)将您的API映射到<!-- All html files at any path --> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping> <!-- Specifically index.html at the root --> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/index.html</url-pattern> </servlet-mapping> ,并使用过滤器来识别API请求并将其转发到该路径。这样,您就可以打破servlet URL模式框,并以任何方式匹配URL。例如,假设您所有的REST调用都是以“/ foo”开头或完全是“/ bar”的路径,而所有其他请求都应该转到静态资源,那么就像:

public class MyInitializer implements ServletContainerInitializer {
    public void onStartup(Set<Class<?>> c, ServletContext ctx) {
        ctx.getServletRegistration("default").addMapping("*.html");
        ctx.getServletRegistration("default").addMapping("/index.html");
    }
}

通过上述内容,您基本上可以按如下方式翻译请求:

/rest/*

3)意识到上一个选项基本上是URL重写并使用现有的实现,例如Apache's mod_rewriteTuckey rewrite filterocpsoft Rewrite

答案 1 :(得分:1)

您可以尝试查找servlet容器的DefaultServlet并在web.xml中手动添加servlet-mapping来处理页面文件,例如* .html,* .jsp或其他任何内容。

E.g。对于Tomcat 5.5,它在这里描述:http://tomcat.apache.org/tomcat-5.5-doc/default-servlet.html

答案 2 :(得分:1)

我找到了另一个涉及内部Jersey类的解决方案,我认为它可能还不是JAX-RS规范的一部分。 (基于:http://www.lucubratory.eu/simple-jerseyrest-and-jsp-based-web-application/

<强>的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">
  <display-name>jersey-rest-jsp-frame-1</display-name>

  <filter>
    <filter-name>jersey</filter-name>
    <filter-class>
      com.sun.jersey.spi.container.servlet.ServletContainer
    </filter-class>
    <init-param>
      <param-name>
        com.sun.jersey.config.property.JSPTemplatesBasePath
      </param-name>
      <param-value>/WEB-INF/jsp</param-value>
    </init-param>
    <init-param>
      <param-name>
        com.sun.jersey.config.property.WebPageContentRegex
      </param-name>
      <param-value>
        (/(image|js|css)/?.*)|(/.*\.jsp)|(/WEB-INF/.*\.jsp)|
        (/WEB-INF/.*\.jspf)|(/.*\.html)|(/favicon\.ico)|
        (/robots\.txt)
      </param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>jersey</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>

<强> WEB-INF / JSP / index.jsp的

<%@ page contentType="text/html; charset=UTF-8" language="java" %>

<html>
<body>
<h2>Hello ${it.foo}!</h2>
</body>
</html>

<强> IndexModel.java

package example;

import com.sun.jersey.api.view.Viewable;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.net.URI;
import java.util.HashMap;

@Path("/")
@Produces(MediaType.TEXT_HTML)
public class IndexModel {

    @GET
    public Response root() {
      return Response.seeOther(URI.create("/index")).build();
    }

    @GET
    @Path("index")
    public Viewable index(@Context HttpServletRequest request) {
      HashMap<String, String> model = new HashMap<String, String>();
      model.put("foo","World");
      return new Viewable("/index.jsp", model);
    }
}

这似乎有效,但我想知道它是否是/将成为JAX-RS规范/实现的一部分。

答案 3 :(得分:0)

从另一篇文章引用@damo for Jersey 2.0

“或者,您可以通过某种重定向来解决问题。例如,使用Pre-matching Filter。我从未做过这样的事情,但文档建议”您甚至可以修改请求URI“。”

答案 4 :(得分:0)

改为使用@ApplicationPath("/")(不使用星号)。它会对你的情况有所帮助。

以下是REST Web服务示例:

1. JaxRsActivator.java

package com.stackoverflow;

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

@ApplicationPath("/")
public class JaxRsActivator extends Application {
}

2. HelloService.java

package com.stackoverflow;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/hello")
public class HelloService {
    @GET
    @Produces(MediaType.TEXT_HTML)
    public String hello() {
        return "hello";
    }
}

我使用Eclipse将此Dynamic Web项目导出到名为helloservice.war的WAR文件,并将其部署到在本地计算机上运行的WildFly。其网址为:http://localhost:8080/helloservice/hello

访问此链接时,它返回:

hello