web-dev-qa-db-ja.com

ルートコンテキストでのJAX-RSアプリケーション-どうすれば実行できますか?

ルートコンテキストでJAX-RXアプリケーションを開始したいので、URLは

http://example.com/restfullPath

ではなく

http://example.com/rest/restfullPath

アプリケーションの注釈をこれから切り替えました

@ApplicationPath("/rest/*")

これに

@ApplicationPath("/*")

しかし、それは/index.htmlなどのファイルの提供を引き継ぐようです

ルートアプリケーションコンテキストでJAX-RSを実行する方法はありますか?

これはJBOSSフォーラムの 前に尋ねた だったようですが、解決策は実際的ではありません

35
Eran Medan

それはおそらくサーブレット仕様の制限としてのバグではありません。 JAX-RS _@ApplicationPath_の処理方法の詳細は実装固有であり、すべての実装について話すことはできませんが、サーブレットのURLパターンとして単純に使用するのが一般的なアプローチだと思います。 JerseyのServletContainerInitializer実装を一例として見ると、 addServletWithApplication() method がサーブレットの作成とリクエストを処理するためのマッピングを担当していることがわかります。実際、_@ApplicationPath_からのパスをJersey ServletContainerのマップされたパスとして使用します。

残念ながら、太古の昔から、サーブレット仕様では、サーブレットをURLパスにマッピングする方法はごく一部しか許可されていません。 仕様のセクション12.2 で提供されるサーブレット3.0の現在のオプションは、残念ながらPDFとしてのみ使用できるため、セクションでリンクできません-

  • _/.../*_ここで、最初の_/..._は0個以上のパス要素です
  • _*.<ext>_ここで_<ext>_は、一致する拡張機能です
  • 空の文字列。空のパス/コンテキストルートにのみマップされます。
  • _/_、単一のスラッシュ。コンテキスト内の「デフォルト」サーブレットを示し、他とは一致しないものを処理します。
  • 一致するリテラル値として扱われるその他の文字列

仕様の同じセクションには、マッチングルールを適用する順序に関する特定のルールもありますが、短いバージョンはこれです。リソースクラスをコンテキストルートでリクエストに応答させるには、_/_のいずれかを使用する必要がありますまたは_/*_をパスとして使用します。 _/_を使用する場合、コンテナーのデフォルトサーブレットを置き換えます。これは通常、静的リソースの処理を担当します。 _/*_を使用すると、貪欲になりすぎて、常にすべてに一致するはずであり、デフォルトのサーブレットが呼び出されることはありません。

したがって、サーブレットURLパターンの制限によって決定されるボックス内にいることを受け入れると、オプションはかなり制限されます。ここに私が考えることができるものがあります:

1)@ApplicationPath("/")を使用し、静的リソースを名前または拡張子でコンテナのデフォルトサーブレットに明示的にマッピングします(TomcatおよびJettyでは「default」という名前ですが、他のものについては不明です)。 web.xmlでは、次のようになります。

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

または ServletContextInitializer のように、

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

マッチングルールの記述方法により、拡張パターンはデフォルトのサーブレットよりも優先されます。静的なファイル拡張子ごとにマッピングを追加する必要があるのは、それらと「拡張」で発生する可能性のある重複がない限りです。あなたのAPI。これは、リンクしたフォーラムの投稿で言及されている望ましくないオプションにかなり近いものです。完全を期すため、およびServletContextInitializerの部分を追加するために、このオプションについて言及しました。

2)APIを_/rest/*_にマップしたままにし、フィルターを使用してAPIのリクエストを識別し、それらをそのパスに転送します。このようにして、サーブレットのURLパターンボックスから抜け出し、URLを任意の方法で照合できます。たとえば、すべてのREST呼び出しが「/ foo」で始まるパスまたは「/ bar」であるパスへの呼び出しであり、他のすべてのリクエストが静的リソースに送られるべきであるとすると、次のようになります。

_import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import Java.io.IOException;
import Java.util.regex.Pattern;

@WebFilter(urlPatterns = "/*")
public class PathingFilter implements Filter {
    Pattern[] restPatterns = new Pattern[] {
            Pattern.compile("/foo.*"),
            Pattern.compile("/bar"),
    };

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        if (request instanceof HttpServletRequest) {
            String path = ((HttpServletRequest) request).getServletPath();
            for (Pattern pattern : restPatterns) {
                if (pattern.matcher(path).matches()) {
                    String newPath = "/rest/" + path;
                    request.getRequestDispatcher(newPath)
                        .forward(request, response);
                    return;
                }
            }
        }
        chain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {}

    @Override
    public void destroy() {}
}
_

上記では、基本的にリクエストを次のように変換します。

_http://example.org/foo          -> http://example.org/rest/foo
http://example.org/foox         -> http://example.org/rest/foox
http://example.org/foo/anything -> http://example.org/rest/foo/anything
http://example.org/bar          -> http://example.org/rest/bar
http://example.org/bart         -> http://example.org/bart
http://example.org/index.html   -> http://example.org/index.html
_

3)前のオプションは基本的にURLの書き換えであり、既存の実装を使用していることを認識してください Apacheのmod_rewriteTuckey書き換えフィルター 、または ocpsoft Rewrite =。

41
Ryan Stewart

内部の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仕様の一部であるか、実装の一部になるかどうかです。

2
Eran Medan

サーブレットコンテナのDefaultServletを探し、web.xmlに手動でサーブレットマッピングを追加して、*。html、*。jspなどのページファイルを処理できます。

例えば。 Tomcat 5.5の場合、ここで説明します: http://Tomcat.Apache.org/Tomcat-5.5-doc/default-servlet.html

1
yatul

別の投稿から@damo for Jersey 2.0を引用

「あるいは、何らかのリダイレクトで何かを引き出すことができるかもしれません。たとえば Pre-matching Filter を使用すると、このようなことをしたことはありませんが、ドキュメントでは「リクエストURIも変更できます。」

0
allegjdm93

代わりに@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を使用してこの動的Webプロジェクトをhelloservice.warという名前のWARファイルにエクスポートし、ローカルマシンで実行されているWildFlyにデプロイしました。そのURL:http://localhost:8080/helloservice/hello

このリンクにアクセスすると、次のように返されました。

hello
0
Thach Van