39

Java では、Web アプリは WAR にバンドルされています。デフォルトでは、多くのサーブレット コンテナがアプリケーションのコンテキスト名として WAR 名を使用します。

したがって、 myapp.war はhttp://example.com/myappにデプロイされます。

問題は、webapp がその「ルート」を「ルート」または単に「/」と見なすのに対し、HTML はアプリケーションのルートを「/myapp」と見なすことです。

サーブレット API と JSP には、これを管理するのに役立つ機能があります。たとえば、サーブレットで response.sendRedirect("/mypage.jsp") を実行すると、コンテナーはコンテキストを先頭に追加し、URL を作成します: http://example.com/myapp/mypage.jsp ".

ただし、たとえば HTML の IMG タグではそれができません。<img src="/myimage.gif"/> を実行すると、おそらく 404 が返されます。これは、実際に必要だったのが "/myapp/myimage.gif" であるためです。

多くのフレームワークには、同様にコンテキストを認識する JSP タグがあり、JSP 内で正しい URL を作成するさまざまな方法があります (特に洗練された方法はありません)。

コーダーにとって、「App Relative」URL と絶対 URL のどちらを使用するかを判断するのは重要な問題です。

最後に、オンザフライで URL を作成する必要がある Javascript コードと、CSS 内に埋め込まれた URL (背景画像など) の問題があります。

この問題を緩和して回避するために他の人がどのような手法を使用しているかに興味があります。多くの場合、サーバーのルートまたは使用しているコンテキストに単純にパントしてハードコーディングします。私はすでにその答えを知っています、それは私が探しているものではありません。

職業はなんですか?

4

13 に答える 13

24

URL の作成には JSTL を使用できます。

たとえば<c:url value="/images/header.jpg" />、コンテキスト ルートのプレフィックスになります。

CSS では、これは通常、私にとって問題ではありません。

次のような Web ルート構造があります。

/css
/画像

CSS ファイルでは、相対 URL (../images/header.jpg) を使用するだけでよく、コンテキスト ルートを認識する必要はありません。

JavaScriptに関しては、私にとってうまくいくのは、次のようにページヘッダーにいくつかの一般的なJavaScriptを含めることです。

<script type="text/javascript">
var CONTEXT_ROOT = '<%= request.getContextPath() %>';
</script>

次に、すべてのスクリプトでコンテキスト ルートを使用できます (または、パスを作成する関数を定義できます - もう少し柔軟な場合があります)。

明らかに、これはすべてJSPとJSTLの使用に依存しますが、私はFaceletsでJSFを使用しており、関連する手法は似ています.唯一の本当の違いは、異なる方法でコンテキストルートを取得することです.

于 2008-09-24T08:24:51.090 に答える
8

HTMLページの場合、HTML<base>タグを設定するだけです。すべての相対リンク(つまり、schemeまたはで始まらない/)は、それに関連するようになります。ですぐにそれを取得するクリーンな方法はない HttpServletRequestので、ここではJSTLの助けはほとんど必要ありません。

<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<c:set var="req" value="${pageContext.request}" />
<c:set var="url">${req.requestURL}</c:set>
<c:set var="uri">${req.requestURI}</c:set>

<!DOCTYPE html>
<html lang="en">
  <head>
    <base href="${fn:substring(url, 0, fn:length(url) - fn:length(uri))}${req.contextPath}/" />
    <link rel="stylesheet" href="css/default.css">
    <script src="js/default.js"></script>
  </head>
  <body>
    <img src="img/logo.png" />
    <a href="other.jsp">link</a>
  </body>
</html>

ただし、これには注意が必要です。アンカー(#identifierURL)もベースパスに対して相対的なものになります。それらのいずれかがある場合は、代わりにリクエストURL(URI)を基準にして作成します。だから、次のように変更します

<a href="#identifier">jump</a>

<a href="${uri}#identifier">jump</a>

JSでは<base>、相対URLを絶対URLに変換するときはいつでも、DOMから要素にアクセスできます。

var base = document.getElementsByTagName("base")[0].href;

または、jQueryを実行する場合

var base = $("base").attr("href");

CSSでは、画像のURLはスタイルシート自体のURLを基準にしています。したがって、スタイルシート自体に関連するフォルダに画像をドロップするだけです。例えば

/css/style.css
/css/images/foo.png

次のように参照してください

background-image: url('images/foo.png');

CSSフォルダと同じレベルのフォルダに画像をドロップしたい場合

/css/style.css
/images/foo.png

次に、を使用../して共通の親フォルダに移動します

background-image: url('../images/foo.png');

参照:

于 2011-02-10T11:39:37.137 に答える
4

遅刻に同意します。私もフィルターに注意を払い、プロジェクトUrlRewriteFilterに直面して解決策を見つけました。次のような単純な構成:

<rule>
    <from>^.+/resources/(.*)$</from>
    <to>/resources/$1</to>
</rule>

*/resources パスのすべてのリクエストを /resources パス (コンテキスト パス プレフィックスを含む) に転送するのに役立ちます。そのため、すべての画像CSSファイルをresourcesフォルダーに配置し、背景画像やその他のケースのスタイルで相対 URL を引き続き使用できます。

于 2011-02-10T09:46:31.960 に答える
3

サーブレット API と JSP には、これを管理するのに役立つ機能があります。たとえば、サーブレットで response.sendRedirect("/mypage.jsp") を実行すると、コンテナーはコンテキストを先頭に追加し、URL を作成します: http://example.com/myapp/mypage.jsp ".

ああ、たぶん、そうではないかもしれません - それはあなたのコンテナとサーブレットの仕様に依存します!

サーブレット 2.3から: 公開された新機能:

そして最後に、専門家グループによる長い議論の後、サーブレット API 2.3 は、非ルート コンテキスト内で実行されているサーブレットの res.sendRedirect("/index.html") 呼び出しで何が起こるかを完全に明確にしました。問題は、サーブレット API 2.2 では、"/index.html" のような不完全なパスがサーブレット コンテナーによって完全なパスに変換される必要があることですが、コンテキスト パスがどのように処理されるかについては言及されていません。呼び出しを行うサーブレットがパス「/contextpath」のコンテキストにある場合、リダイレクト URI はコンテナー ルート ( http://server:port/index.html ) またはコンテキスト ルート ( http://サーバー:ポート/contextpath/index.html)? 移植性を最大限に高めるには、動作を定義することが不可欠です。長い議論の末、専門家はコンテナのルートを基準にして翻訳することを選択しました。コンテキスト相対が必要な場合は、getContextPath() からの出力を URI の先頭に追加できます。

いいえ、2.3 では、パスはコンテキスト パスを含むように自動的に変換されません。

于 2008-10-04T04:16:23.240 に答える
1

request.getContextPath() を使用して、特定のコンテキストにハードコーディングされていない絶対 URL を作成できます。以前の回答が示したように、JavaScript の場合、JSP の先頭 (またはできればテンプレート内) に変数を設定し、それをコンテキストとしてプレフィックスします。

CSS ファイルを動的に生成する場合を除き、これは CSS 画像の置換では機能しません。動的に生成すると、他の問題が発生する可能性があります。しかし、CSS ファイルが画像に関連してどこにあるかはわかっているので、相対 URL を使用することができます。

何らかの理由で、IE での相対 URL の処理に問題があり、JavaScript 変数がコンテキストに設定された式を使用するようにフォールバックする必要がありました。IE 画像の置換を独自のファイルに分割し、IE マクロを使用して正しいものを取り込みました。とにかく透明なPNGを扱うためにそれをしなければならなかったので、それは大したことではありませんでした. きれいではありませんが、機能します。

于 2008-09-25T07:22:53.943 に答える
1

Vilmantas はここで正しい言葉を言いました: 相対 URL です。

IMG で行う必要があるのは、

<img src="myimage.gif"/>

それ以外の

<img src="/myimage.gif"/>

そして、それはアプリのコンテキストに対して相対的になります(ブラウザがURLを解釈して移動するため)

于 2008-09-24T17:36:38.640 に答える
1

1 つのオプションは、可能な限り「フラットな」アプリケーション構造と相対 URL を使用することです。

「フラット」とは、アプリケーションのルートの下にサブディレクトリがないことを意味します。おそらく、「images/」などの静的コンテンツ用のディレクトリがいくつかあるだけです。すべての JSP、アクション URL、サーブレットは、ルートの直下に配置されます。

これで問題が完全に解決されるわけではありませんが、大幅に単純化されます。

于 2008-09-24T07:03:34.777 に答える
1

特別な場合を除いて、絶対 URL をこのように使用しないことをお勧めします。これまで。絶対 URL は、別の Web アプリが Webアプリ内の何かを指している場合に適しています。内部的に -- 1 つのリソースが同じコンテキスト内の 2 番目のリソースを指している場合 -- リソースは自分がどこにいるかを知っている必要があるため、2 番目のリソースへの相対パスを表現できる必要があります。

もちろん、それらを含むリソースを知らないモジュラー コンポーネントを作成します。例えば:

/myapp/user/email.jsp:
Email: <a href="../sendmail.jsp">${user.email}</a>

/myapp/browse/profile.jsp:
<jsp:include page="../user/email.jsp" />

/myapp/home.jsp:
<jsp:include page="../user/email.jsp" />

では、どうやっemail.jspて の相対パスを知るのsendmail.jspでしょうか? 明らかに、リンクはどちら/myapp/browse/profile.jspかで壊れるか、で壊れ/myapp/home.jspます。答えは、すべての URL を同じフラット ファイルパス スペースに保持することです。つまり、すべての URL の の後にスラッシュを入れてはなりません/myapp/

URL とコンテンツを生成する実際のファイルとの間に何らかのマッピングがある限り、これは非常に簡単に実現できます。(たとえば、Spring では、DispatcherServlet を使用して URL を JSP ファイルまたはビューにマップします。)

特殊なケースがあります。たとえば、ブラウザ側のアプリケーションを Javascript で作成している場合、フラットなファイルパス スペースを維持するのは難しくなります。<%= request.getContextPath() %>その場合、または他の特別な場合、または個人的な好みがある場合は、絶対パスを作成するために使用することは実際には大したことではありません。

于 2008-09-24T17:59:50.940 に答える
1

私はこれらの手法のほとんどを使用しました (XSLT アーキテクチャーを保存してください)。

問題の核心 (そしてコンセンサス) は、潜在的に複数のディレクトリを持つサイトを持つことだと思います。

ディレクトリの深さが (適切な用語がないため) 一定である場合は、CSS などで相対 URL を使用できます。

レイアウトは完全にフラットである必要はなく、一貫していることに注意してください。

たとえば、/css、/js、/common、/admin、/user などの階層を作成しました。適切なページとリソースを適切なディレクトリに配置します。このような構造を持つことは、コンテナベースの認証で非常にうまく機能します。

また、*.css と *.js を JSP サーブレットにマップし、それらを動的にして、その場で構築できるようにしました。

私が見逃したかもしれない何かが他にあることを願っていました。

于 2008-09-26T04:30:36.750 に答える
1

ヘルパー クラスを使用して img タグなどを生成しました。このヘルパー クラスは、パスにアプリケーションの contextPath のプレフィックスを付けます。(これは機能しますが、私はあまり好きではありません。より良い代替手段があれば教えてください。)

cssファイルのパスなどについては、本番環境のsite.cssと開発環境のsite.development.cssにsite.production.cssを使うAntのビルドスクリプトを使っています。

あるいは、 @token@トークンをさまざまな環境の適切なデータに置き換えるAnt スクリプトを使用することもあります。この場合、@contextPAth@ トークンは正しいコンテキスト パスに置き換えられます。

于 2008-09-24T06:47:29.293 に答える
0

私は、以下がエレガントな問題であるとは決して主張しません。実際、後から考えると、(最も可能性が高い)パフォーマンスの低下を考えると、この問題はお勧めしません。

私たちのウェブアプリのJSPは厳密にXML生データでした。次に、この生データは、適切なCSSタグを適用するXSL(サーバー側)に送信され、XHTMLを吐き出しました。

Webサイトのさまざまなコンポーネント用に持っていた複数のXSLファイルによって継承される単一のtemplate.xslがありました。パスはすべて、paths.xmlというXSLファイルで定義されています。

<?xml version="1.0" encoding="UTF-8"?>
<paths>
    <path name="account" parent="home">Account/</path>
    <path name="css">css/</path>
    <path name="home">servlet/</path>
    <path name="icons" parent="images">icons/</path>
    <path name="images">images/</path>
    <path name="js">js/</path>
</paths>

内部リンクは、次のようにXMLに含まれます。

<ilink name="link to icons" type="icons">link to icons</ilink>

これはXSLによって処理されます。

<xsl:template match="ilink">
    <xsl:variable name="temp">
        <xsl:value-of select="$rootpath" />
        <xsl:call-template name="paths">
            <xsl:with-param name="path-name"><xsl:value-of select="@type" /></xsl:with-param>
        </xsl:call-template>
        <xsl:value-of select="@file" />
    </xsl:variable>
        <a href="{$temp}" title="{@name}" ><xsl:value-of select="." /></a>
</xsl:template>

$rootPathは、JSP / JavaファイルにハードコーディングするのではなくXMLを使用するという考え方で、各ファイルに渡され${applicationScope.contextPath}ました。再コンパイルする必要はありませんでした。

繰り返しになりますが、このソリューションはまったく良いものではありません...しかし、私たちは一度それを使用しました!

編集:実際、ビュー全体にJSPを使用できなかったため、問題が複雑になりました。なぜ誰か${applicationScope.contextPath}がコンテキストパスを取得するためだけに使用しないのですか?その時はうまくいきました。

于 2008-09-24T04:29:30.967 に答える
0

私は自分のコア JavaScript ライブラリの一部としてプロパティを作成する傾向があります。完璧だとは思いませんが、私が達成できた最高のものだと思います。

まず、アプリのコアの一部であり、常に利用可能なモジュールがあります

(function (APP) {
  var ctx;
  APP.setContext = function (val) {
    // protect rogue JS from setting the context.
    if (ctx) {
      return;
    }
    val = val || val.trim();
    // Don't allow a double slash for a context.
    if (val.charAt(0) === '/' && val.charAt(1) === '/') {
      return;
    }
    // Context must both start and end in /.
    if (val.length === 0 || val === '/') {
      val = '/';
    } else {
      if (val.charAt(0) !== '/') {
        val = '/' + val;
      }
      if (val.slice(-1) !== '/') {
        val += '/';
      }
    }
    ctx = val;
  };
  APP.getContext = function () {
    return ctx || '/';
  };
  APP.getUrl = function (val) {
    if (val && val.length > 0) {
      return APP.getContext() + (val.charAt(0) === '/' ? val.substring(1) : val);
    }
    return APP.getContext();
  };
})(window.APP = window.APP || {});

次に、常に次を含む共通ヘッダーを持つ apache タイルを使用します。

<script type="text/javascript">
  APP.setContext('${pageContext.request['contextPath']}');
  // If preferred use JSTL cor, but it must be available and declared.
  //APP.setContext('<c:url value='/'/>');
</script>

これで、任意の場所 (js ファイルまたは jsp/html 内) から使用できるコンテキストを初期化したので、コンテキストgetUrl(path)内の指定された入力文字列の絶対パスを返します。

以下は意図的にどちらも同等であることに注意してください。getUrl相対パスは最初にコンテキストを知る必要がないため、常に絶対パスを返します。

var path = APP.getUrl("/some/path");
var path2 = APP.getUrl("some/path");
于 2016-09-08T15:27:53.190 に答える
0

サイトをゼロから作成するときは、@Will を支持します。相対参照を維持できるように、一貫性のある予測可能な URL 構造を目指します。

しかし、もともとサイト ルート "/" (単純な JSP サイトではかなり一般的) の直下で動作するように構築されたサイトを正式なJava EEパッケージ (コンテキスト ルートはルートの下のパス) に更新する場合、事態は非常に厄介になる可能性があります。 )。

これは、多くのコード変更を意味する可能性があります。

コードの変更を回避または延期したいが、正しいコンテキスト ルート参照を確保したい場合、私がテストした手法は、サーブレット フィルターを使用することです。フィルターは、(web.xml を除いて) 何も変更せずに既存のプロジェクトにドロップでき、アウトバウンド HTML 内のすべての URL 参照を正しいパスに再マップし、リダイレクトが正しく参照されるようにします。

EnforceContextRootFilter-1.0-src.zipで入手できるサンプル サイトと使用可能なコード 注意: 実際のマッピング ルールは、サーブレット クラスで正規表現として実装され、非常に一般的なキャッチオールを提供しますが、特定の状況では変更が必要になる場合があります。

ところで、 「/」から非ルート コンテキスト パスへの既存のコード ベースの移行に対処するために、少し異なる質問をフォークしました

于 2008-09-27T03:28:14.027 に答える