Question

En Java, les applications Web sont intégrées aux fichiers WAR. Par défaut, de nombreux conteneurs de servlets utiliseront le nom WAR comme nom de contexte pour l'application.

Ainsi, myapp.war est déployé sur http://example.com/myapp .

Le problème est que l'application Web considère son " racine " pour être bien & "; racine &"; ou simplement & "; &"; alors que HTML considérerait la racine de votre application comme & "; / monapp < !> quot;.

L'API Servlet et JSP disposent d'installations permettant de gérer cela. Par exemple, si, dans une servlet, vous effectuez les actions suivantes: response.sendRedirect (& Quot; /mypage.jsp & Quot;)), le conteneur s'ajoute au contexte et crée l'url: http://example.com/myapp/mypage.jsp &";.

Cependant, vous ne pouvez pas faire cela avec, disons, la balise IMG en HTML. Si vous le faites & Lt; img src = & "; /Myimage.gif &"; / & Gt; vous obtiendrez probablement un 404, car ce que vous vouliez vraiment, c'était & «; / myapp/monimage.gif &>;

.

De nombreux frameworks ont également des balises JSP sensibles au contexte, et il existe différentes façons de créer des URL correctes dans JSP (aucune particulièrement élégante).

C’est un problème de taille pour les codeurs de savoir comment utiliser un & "App Relative &"; URL, vs une URL absolue.

Enfin, il y a le problème du code Javascript qui doit créer des URL à la volée et des URL incorporées dans CSS (pour les images d'arrière-plan, etc.).

Je suis curieux de savoir quelles techniques les autres utilisent pour atténuer et résoudre ce problème. Beaucoup simplement frappent et codent en dur, soit à la racine du serveur, soit au contexte qu’ils utilisent. Je connais déjà cette réponse, ce n’est pas ce que je cherche.

Que faites-vous?

Était-ce utile?

La solution

Vous pouvez utiliser JSTL pour créer des URL.

Par exemple, <c:url value="/images/header.jpg" /> préfixera la racine de contexte.

Avec CSS, ce n'est généralement pas un problème pour moi.

J'ai une structure racine Web semblable à celle-ci:

/ css
/ images

Dans le fichier CSS, il vous suffit ensuite d'utiliser des URL relatives (../images/header.jpg), sans qu'il soit nécessaire de connaître la racine du contexte.

Pour ce qui est de JavaScript, ce qui fonctionne pour moi, c’est d’inclure du code JavaScript commun dans l’en-tête de page, comme suit:

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

Ensuite, vous pouvez utiliser la racine de contexte dans tous vos scripts (ou définir une fonction pour créer des chemins - peut-être un peu plus flexible).

Évidemment, tout dépend de l'utilisation des fichiers JSP et JSTL, mais j'utilise JSF avec Facelets et les techniques utilisées sont similaires. La seule différence réelle est d'obtenir la racine de contexte de manière différente.

Autres conseils

Pour les pages HTML, je viens de définir la balise HTML <base>. Chaque lien relatif (c'est-à-dire ne commençant pas par un schéma ou /) deviendra relatif à celui-ci. Il n'y a pas de moyen propre de le récupérer immédiatement par HttpServletRequest, nous avons donc besoin de peu d'aide de JSTL ici.

<%@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>

Cela a toutefois une mise en garde: les ancres (les #identifier URL) deviendront également relatives au chemin de base. Si vous en avez, vous souhaitez plutôt le rendre relatif à l'URL de la demande (URI). Alors, changez comme

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

à

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

Dans JS, vous pouvez simplement accéder à l'élément ../ à partir du DOM chaque fois que vous souhaitez convertir une URL relative en une URL absolue.

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

Ou si vous faites jQuery

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

En CSS, les URL de l'image sont relatives à l'URL de la feuille de style elle-même. Il suffit donc de déposer les images dans un dossier relatif à la feuille de style elle-même. Ex.

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

et les référencer comme suit

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

Si vous préférez déposer les images dans un dossier du même niveau que le dossier CSS

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

utilisez ensuite <=> pour accéder au dossier parent commun

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

Voir aussi:

Je suis d'accord avec retardate . J'ai également porté mon attention sur les filtres et j'ai trouvé la solution face au projet UrlRewriteFilter . La configuration simple ressemble à ce qui suit:

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

permet de transférer toutes les demandes de * / resources path à / resources pass (y compris le préfixe de chemin de contexte). Je peux donc simplement placer tous mes images et CSS dans le dossier ressources et continuer à utiliser des URL relatives dans mes styles pour les images d'arrière-plan et autres cas.

  

L'API Servlet et JSP ont   installations pour aider à gérer cela. Pour   Par exemple, si, dans une servlet, vous faites:   response.sendRedirect (& "; /mypage.jsp &";),   le conteneur préfixera le contexte   et créez l'URL:    http://example.com/myapp/mypage.jsp & ";

Ah, peut-être, peut-être que non - cela dépend de votre conteneur et des spécifications de servlet!

De Servlet 2.3: nouvelles fonctionnalités exposées :

  

Et enfin, après un long débat de   un groupe d'experts, API Servlet 2.3   a clarifié une fois pour toutes exactement   ce qui se passe sur un   res.sendRedirect (" /index.html ") appelle   pour un servlet s'exécutant dans un   contexte non racine. Le problème est que   Servlet API 2.2 nécessite une version incomplète   chemin comme " / index.html " être   traduit par le conteneur de servlet   dans un chemin complet, mais ne dit pas   comment les chemins de contexte sont gérés. Si la   la servlet faisant l'appel est dans un   contexte au chemin & "; / contextpath, &";   l'URI de redirection doit-il être traduit?   par rapport à la racine du conteneur   ( http: // serveur: port / index.html ) ou   racine de contexte   ( http: // serveur: port / contextpath / index.html )?   Pour une portabilité maximale, c'est   impératif de définir le comportement;   après un long débat, les experts   a choisi de traduire par rapport à la   conteneur racine. Pour ceux qui veulent   contexte relatif, vous pouvez ajouter le   sortie de getContextPath () vers votre   URI.

Donc non, avec la version 2.3, vos chemins sont non automatiquement traduits pour inclure le chemin du contexte.

J'ai utilisé des classes auxiliaires pour générer des balises img, etc. Cette classe auxiliaire prend en charge les chemins de préfixage avec le chemin de chemin de contexte de l'application. (Cela fonctionne, mais je ne l’aime pas vraiment. Si quelqu'un a de meilleures alternatives, dites-le-moi.)

Pour les chemins dans les fichiers css, etc. J'utilise un script de génération Ant qui utilise un site.production.css pour site.css dans un environnement de production et un site.development.css dans un environnement de développement.

Alternativement, j'utilise parfois un script Ant qui remplace les jetons @token @ par les données appropriées pour différents environnements. Dans ce cas, @ contextPAth @ token serait remplacé par le chemin de contexte correct.

Une option consiste à utiliser & "flat &"; structure de l’application et URL relatives dans la mesure du possible.

Par " plat " Je veux dire qu'il n'y a pas de sous-répertoires sous la racine de votre application, peut-être que quelques répertoires pour le contenu statique tels que & "; Images / &"; Toutes vos JSP, vos URL d'action et vos servlets vont directement sous la racine.

Cela ne résout pas complètement votre problème mais le simplifie grandement.

Vilmantas a dit le mot juste ici: URL relatives.

Tout ce que vous devez faire dans votre IMG est d’utiliser

<img src="myimage.gif"/>

au lieu de

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

et ce sera relatif au contexte de l'application (le navigateur interprétant l'URL à laquelle accéder)

Sauf cas particulier, je vous déconseille d'utiliser les URL absolues de cette façon. Déjà. Les URL absolues sont utiles lorsque une autre application Web pointe sur un élément de votre application Web. En interne - lorsqu'une ressource pointe vers une deuxième ressource dans le même contexte - la ressource doit savoir où elle réside et pouvoir ainsi exprimer un chemin relatif vers la deuxième ressource.

Bien sûr, vous allez écrire des composants modulaires, qui ne connaissent pas la ressource qui les inclut. Par exemple:

/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" />

Alors, comment email.jsp connaît-il le chemin relatif de sendmail.jsp? Clairement, le lien sera rompu soit sur /myapp/browse/profile.jsp, soit sur /myapp/home.jsp. La réponse est: conservez toutes vos URL dans le même espace de chemin de fichier plat. Autrement dit, chaque URL ne devrait pas avoir de barre oblique après /myapp/.

Ceci est assez facile à réaliser, tant que vous avez une sorte de mappage entre les URL et les fichiers qui génèrent le contenu. (par exemple, au printemps, utilisez DispatcherServlet pour mapper des URL vers des fichiers JSP ou des vues.)

Il existe des cas spéciaux. par exemple. Si vous écrivez une application côté navigateur en Javascript, il devient plus difficile de conserver un espace de chemin de fichier plat. Dans ce cas, ou dans des cas particuliers, ou simplement si vous avez une préférence personnelle, utiliser <%= request.getContextPath() %> pour créer un chemin absolu n’est pas si grave.

Vous pouvez utiliser request.getContextPath () pour créer des URL absolues qui ne sont pas codées en dur dans un contexte spécifique. Comme indiqué précédemment, pour JavaScript, vous venez de définir une variable en haut de votre JSP (ou de préférence dans un modèle) et de le préfixer en tant que contexte.

Cela ne fonctionne pas pour le remplacement d'image CSS à moins que vous ne souhaitiez générer dynamiquement un fichier CSS, ce qui peut entraîner d'autres problèmes. Mais puisque vous savez où se trouve votre fichier CSS par rapport à vos images, vous pouvez vous en tirer avec des URL relatives.

Pour une raison quelconque, j'ai eu des problèmes avec la gestion par IE des URL relatives et j'ai dû revenir à l'utilisation d'expressions avec une variable JavaScript définie dans le contexte. Je viens de scinder mes images de remplacement IE dans leur propre fichier et d’utiliser les macros IE pour extraire les correctes. Ce n'était pas un gros problème parce que je devais déjà le faire pour traiter les PNG transparents de toute façon. Ce n'est pas joli, mais ça marche.

J'ai utilisé la plupart de ces techniques (enregistrer l'architecture XSLT).

Je pense que le problème (et le consensus) du problème est d'avoir un site avec potentiellement plusieurs annuaires.

Si la profondeur de votre répertoire (faute d'un meilleur terme) est constante, vous pouvez vous fier aux URL relatives dans des choses comme CSS.

Attention, la mise en page ne doit pas nécessairement être complètement plate, mais cohérente.

Par exemple, nous avons créé des hiérarchies telles que / css, / js, / common, / admin, / user. Mettre les pages et les ressources appropriées dans les répertoires appropriés. Avoir une structure comme celle-ci fonctionne très bien avec l'authentification par conteneur.

J'ai également mappé * .css et * .js sur le servlet JSP et je les ai rendus dynamiques pour que je puisse les construire à la volée.

J'espérais juste qu'il y avait quelque chose d'autre que j'ai peut-être manqué.

Je par non signifie que ce qui suit est une question élégante. En fait, avec le recul, je ne recommanderais pas ce problème étant donné les performances (les plus probables).

Les fichiers JSP de nos applications Web étaient exclusivement des données brutes XML. Ces données brutes étaient ensuite envoyées dans un fichier XSL (côté serveur) qui appliquait les balises CSS appropriées et crachait le fichier XHTML.

Nous avions un seul fichier template.xsl qui serait hérité des multiples fichiers XSL que nous avions pour différents composants du site Web. Nos chemins ont tous été définis dans un fichier XSL appelé paths.xml:

<?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>

Un lien interne se trouverait dans le fichier XML comme suit:

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

Ceci serait traité par notre 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 a été passé sur chaque fichier avec ${applicationScope.contextPath} L'idée derrière l'utilisation de XML au lieu de simplement le coder en dur dans un fichier JSP / Java était que nous ne voulions pas avoir à recompiler.

Encore une fois, la solution n'est pas bonne du tout ... mais nous ne l'avons utilisée qu'une fois!

Modifier : en réalité, la complexité de notre problème est due à l'impossibilité d'utiliser les JSP pour l'ensemble de notre affichage. Pourquoi quelqu'un n'utiliserait-il pas simplement <=> pour récupérer le chemin de contexte? Cela a bien fonctionné pour nous alors.

Lors de la création d'un site à partir de rien, je me range de @Will - visez une structure d'URL cohérente et prévisible afin que vous puissiez vous en tenir aux références relatives.

Toutefois, la mise à jour d'un site conçu à l'origine pour fonctionner directement sous la racine du site " / " peut devenir très compliquée. (assez commun pour les sites JSP simples) à l'emballage Java EE officiel (où la racine de contexte sera un chemin sous la racine).

Cela peut signifier beaucoup de changements de code.

Si vous souhaitez éviter ou différer les modifications de code tout en garantissant un référencement correct de la racine de contexte, une technique que j'ai testée consiste à utiliser des filtres de servlet. Le filtre peut être déposé dans un projet existant sans rien changer (sauf web.xml), et remappera toutes les références d'URL dans le code HTML sortant au chemin correct et s'assurera également que les redirections sont correctement référencées.

Un exemple de site et de code utilisable est disponible ici: EnforceContextRootFilter-1.0-src.zip NB: les règles de mappage réelles sont implémentées en tant que regex dans la classe servlet et fournissent un assez général fourre-tout - mais vous devrez peut-être modifier pour des circonstances particulières.

Au fait, j'ai posé une question légèrement différente pour répondre à migration de la base de code existante de " / " vers un chemin de contexte non racine

J'ai tendance à écrire une propriété dans le cadre de ma bibliothèque JavaScript principale. Je ne pense pas que ce soit parfait, mais je pense que c’est le meilleur que j’ai réussi à atteindre.

Tout d’abord, j’ai un module qui fait toujours partie de mon cœur d’application qui est toujours disponible

(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 || {});

J'utilise ensuite les tuiles Apache avec un en-tête commun qui contient toujours les éléments suivants:

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

Maintenant que j'ai initialisé le contexte, je peux utiliser getUrl(path) de n'importe où (fichiers js ou au sein de jsp / html) pour renvoyer un chemin absolu pour la chaîne d'entrée donnée dans le contexte.

Notez que les éléments suivants sont les deux équivalents intentionnellement. getUrl renverra toujours un chemin absolu car un chemin relatif n'a pas besoin de connaître le contexte en premier lieu.

var path = APP.getUrl("/some/path");
var path2 = APP.getUrl("some/path");

Voici le meilleur moyen: Filtre de redirection de contexte Le filtre doit être appliqué au point d'extension antérieur à la correspondance et utiliser donc l'annotation @PreMatching.

Les filtres implémentant cette interface doivent être annotés avec @Provider pour être découverts par le moteur d'exécution JAX-RS. Les instances de filtre de requête de conteneur peuvent également être découvertes et liées dynamiquement à des méthodes de ressources particulières.

Expliqué avec l'exemple de code:

http://writeulearn.com/java-filters/

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top