Domanda

In Java, web apps sono in bundle nelle Guerre.Per impostazione predefinita, molti servlet container utilizzare la GUERRA come nome il nome del contesto per l'applicazione.

Così myapp.la guerra viene distribuito http://example.com/myapp.

Il problema è che la webapp considera la sua "radice" di essere, "root", o semplicemente "/", mentre l'HTML in considerazione il root della vostra applicazione "/myapp".

La Servlet API e JSP sono strutture per aiutare a gestire questo.Per esempio, se in una servlet, puoi fare:risposta.sendRedirect("/mypage.jsp"), il contenitore viene anteposto il contesto e creare l'url: http://example.com/myapp/mypage.jsp".

Tuttavia, non si può fare con, ad esempio, il tag IMG in formato HTML.Se si <img src="/myimage.gif" /> è probabile ottenere un 404, perché quello che si voleva davvero era "/myapp/myimage.gif".

Molti quadri sono JSP che sono sensibili al contesto, e ci sono diversi modi di fare le giuste Url JSP (nessuno in particolare elegantemente).

È un nitty problema per i codificatori a saltare fuori quando utilizzare un "App Relativa" url vs un url assoluto.

Infine, c'è un problema di codice Javascript che ha bisogno di creare gli Url al volo, e gli Url incorporati all'interno di CSS (per le immagini di sfondo e simili).

Sono curioso di sapere quali tecniche utilizzare altri per ridurre e risolvere questo problema.Molti semplicemente punt e codificare, sia per il root del server o qualunque sia il contesto che capita di essere utilizzando.So già che la risposta, che non è quello che sto cercando.

Che cosa puoi fare?

È stato utile?

Soluzione

Puoi usare JSTL per creare URL.

Ad esempio, <c:url value="/images/header.jpg" /> anteporrà la radice del contesto.

Con i CSS, questo di solito non è un problema per me.

Ho una struttura di root web come questa:

/ css
/ images

Nel file CSS, devi solo usare gli URL relativi (../images/header.jpg) e non è necessario essere a conoscenza della radice del contesto.

Per quanto riguarda JavaScript, ciò che funziona per me è includere alcuni JavaScript comuni nell'intestazione della pagina in questo modo:

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

Quindi puoi usare la root di contesto in tutti i tuoi script (oppure puoi definire una funzione per costruire percorsi - potrebbe essere un po 'più flessibile).

Ovviamente tutto dipende dal tuo utilizzo di JSP e JSTL, ma io uso JSF con Facelets e le tecniche coinvolte sono simili - l'unica vera differenza è ottenere il root del contesto in modo diverso.

Altri suggerimenti

Per le pagine HTML, ho appena impostato il tag HTML <base>. Ogni collegamento relativo (ovvero non iniziando con uno schema o /) diventerà relativo ad esso. Non esiste un modo pulito per prenderlo immediatamente entro HttpServletRequest, quindi qui abbiamo bisogno di un piccolo aiuto di 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>

Questo ha a sua volta un avvertimento: le ancore (gli #identifier URL) diventeranno relative anche al percorso di base. Se ne hai uno, preferisci invece renderlo relativo all'URL di richiesta (URI). Quindi, cambia come

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

a

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

In JS, puoi semplicemente accedere all'elemento ../ dal DOM ogni volta che desideri convertire un URL relativo in un URL assoluto.

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

O se fai jQuery

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

Nei CSS, gli URL delle immagini sono relativi all'URL del foglio di stile stesso. Quindi, basta rilasciare le immagini in una cartella relativa al foglio di stile stesso. Per es.

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

e fai riferimento come segue

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

Se preferisci rilasciare le immagini in alcune cartelle allo stesso livello della cartella CSS

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

quindi usa <=> per andare alla cartella principale comune

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

Vedi anche:

Sono d'accordo con tardate . Ho anche prestato la mia attenzione ai filtri e ho trovato la soluzione di fronte al progetto UrlRewriteFilter . La semplice configurazione come segue:

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

aiuta a inoltrare tutte le richieste per * / risorse percorso a / risorse passa (incluso prefisso percorso contesto). Quindi posso semplicemente mettere tutte le mie immagini e CSS nella cartella risorse e continuare a utilizzare gli URL relativi nei miei stili per immagini di sfondo e altri casi.

  

L'API Servlet e JSP hanno   strutture per aiutare a gestire questo. Per   esempio, se, in un servlet, fai:   response.sendRedirect (quot &; & /mypage.jsp quot;),   il contenitore anteporrà il contesto   e crea l'URL:    http://example.com/myapp/mypage.jsp ".

Ah, forse, forse no - dipende dal contenitore e dalle specifiche del servlet!

Da Servlet 2.3: Nuove funzionalità esposte :

  

E infine, dopo un lungo dibattito di   un gruppo di esperti, Servlet API 2.3   ha chiarito una volta per tutte esattamente   cosa succede su a   res.sendRedirect (" /index.html ") chiamata   per un servlet in esecuzione all'interno di a   contesto non root. Il problema è questo   Servlet API 2.2 richiede un incompleto   percorso come " /index.html " essere   tradotto dal contenitore servlet   in un percorso completo, ma non lo dice   come vengono gestiti i percorsi di contesto. Se la   servlet che effettua la chiamata è in a   contesto nel percorso " / contextpath, "   dovrebbe tradurre l'URI di reindirizzamento   rispetto alla radice del contenitore   ( http: // server: port / index.html ) o il   root di contesto   ( http: // server: port / contextpath / index.html )?   Per la massima portabilità, lo è   imperativo per definire il comportamento;   dopo un lungo dibattito, gli esperti   scelto di tradurre in relazione al   radice del contenitore. Per chi vuole   relativo al contesto, è possibile anteporre a   output da getContextPath () sul tuo   URI.

Quindi no, con 2.3 i tuoi percorsi sono non tradotti automaticamente per includere il percorso di contesto.

Ho usato classi helper per generare tag img ecc. Questa classe helper si occupa di percorsi di prefisso con il contextPath dell'applicazione. (Funziona, ma non mi piace davvero. Se qualcuno ha alternative migliori, per favore, dillo.)

Per i percorsi nei file CSS ecc. Uso uno Script di compilazione Ant che utilizza un site.production.css per site.css nell'ambiente di produzione e site.development.css nell'incentivazione dello sviluppo.

In alternativa, a volte uso uno script Ant che sostituisce i token @ token @ con dati adeguati per diversi ambienti. In questo caso @ contextPAth @ token verrebbe sostituito con il percorso di contesto corretto.

Un'opzione è usare " flat " struttura dell'applicazione e relativi URL, ove possibile.

Per " flat " Voglio dire che non ci sono sottodirectory nella root dell'applicazione, forse solo poche directory per contenuti statici come & Quot; images / & Quot ;. Tutti i tuoi JSP, URL di azione, servlet vanno direttamente sotto la radice.

Questo non risolve completamente il tuo problema ma lo semplifica notevolmente.

Vilmantas ha detto la parola giusta qui: URL relativi.

Tutto ciò che devi fare nella tua IMG è usare

<img src="myimage.gif"/>

anziché

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

e sarà relativo al contesto dell'app (poiché il browser sta interpretando l'URL per andare a)

Tranne casi speciali, ti consiglio di non utilizzare URL assoluti in questo modo. Mai. Gli URL assoluti sono utili quando un'altra webapp punta a qualcosa nella tua webapp. Internamente - quando una risorsa punta a una seconda risorsa nello stesso contesto - la risorsa dovrebbe sapere dove abita, quindi dovrebbe essere in grado di esprimere un percorso relativo alla seconda risorsa.

Naturalmente, scriverai componenti modulari, che non conoscono la risorsa che li include. Ad esempio:

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

Quindi, come fa email.jsp a conoscere il percorso relativo di sendmail.jsp? Chiaramente il collegamento si interromperà su /myapp/browse/profile.jsp o si interromperà su /myapp/home.jsp. La risposta è: mantieni tutti i tuoi URL nello stesso spazio piano percorso file. Cioè, ogni URL non dovrebbe avere barre dopo /myapp/.

Questo è abbastanza facile da realizzare, a patto che tu abbia una sorta di mappatura tra gli URL e i file effettivi che generano il contenuto. (ad es. in primavera, utilizzare DispatcherServlet per mappare gli URL ai file JSP o alle visualizzazioni.)

Ci sono casi speciali. per esempio. se stai scrivendo un'applicazione sul lato browser in Javascript, diventa più difficile mantenere uno spazio piano per i file. In quel caso, o in altri casi speciali, o solo se hai una preferenza personale, non è davvero un grosso problema usare <%= request.getContextPath() %> per creare un percorso assoluto.

È possibile utilizzare request.getContextPath () per creare URL assoluti che non sono codificati in un contesto specifico. Come indicato in una risposta precedente, per JavaScript hai appena impostato una variabile nella parte superiore del tuo JSP (o preferibilmente in un modello) e lo aggiungi come contesto.

Ciò non funziona per la sostituzione di immagini CSS a meno che non si desideri generare dinamicamente un file CSS, che può causare altri problemi. Ma poiché sai dove si trova il tuo file CSS in relazione alle tue immagini, puoi scappare con URL relativi.

Per qualche motivo, ho avuto problemi con IE nella gestione degli URL relativi e ho dovuto ricorrere all'utilizzo delle espressioni con una variabile JavaScript impostata sul contesto. Ho appena diviso le mie sostituzioni di immagini IE nel loro file e ho usato le macro IE per estrarre quelle corrette. Non è stato un grosso problema perché dovevo già farlo per gestire PNG trasparenti comunque. Non è carino, ma funziona.

Ho usato la maggior parte di queste tecniche (salvare il XSLT architettura).

Penso che il punto cruciale (e il consenso) il problema è avere un sito potenzialmente più directory.

Se la directory di profondità (per mancanza di un termine migliore) è costante, quindi si può contare su un url relativo, in cose come CSS.

Mente, il formato non deve essere completamente piatta, poco coerente.

Per esempio, abbiamo fatto delle gerarchie come /css /js /common /admin /utente.Mettendo pagine e risorse nella giusta directory.Avere una struttura come questa funziona molto bene con Contenitore autenticazione di base.

Ho mappato anche *.css e *.js JSP, servlet e li dinamico, in modo che posso costruire in tempo reale.

Stavo sperando ci fosse qualcos'altro che potrebbe avere perso.

I per no significa affermare che quanto segue è un problema elegante. In effetti, con il senno di poi, non consiglierei questo problema dato il (probabilmente) successo delle prestazioni.

I JSP della nostra app Web erano dati grezzi strettamente XML. Questi dati grezzi sono stati quindi inviati in un XSL (lato server) che applicava i tag CSS corretti e sputava l'XHTML.

Avevamo un unico template.xsl che sarebbe stato ereditato dai molteplici file XSL che avevamo per i diversi componenti del sito web. I nostri percorsi sono stati tutti definiti in un file XSL chiamato 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 collegamento interno sarebbe nell'XML come segue:

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

Questo verrebbe elaborato dalla nostra 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 è stato passato su ogni file con ${applicationScope.contextPath} L'idea dietro di noi usando XML invece di codificarlo in un file JSP / Java era che non volevamo ricompilare.

Ancora una volta, la soluzione non è affatto buona ... ma l'abbiamo usata una volta!

Modifica : in realtà, la complessità del nostro problema è emersa perché non siamo stati in grado di utilizzare i JSP per l'intera vista. Perché qualcuno non dovrebbe semplicemente usare <=> per recuperare il percorso contestuale? Ha funzionato bene per noi allora.

Quando creo un sito da zero, mi affianco a @Will - mirare a una struttura url coerente e prevedibile in modo da poter rimanere con i relativi riferimenti.

Ma le cose possono diventare davvero complicate se stai aggiornando un sito che è stato originariamente creato per funzionare direttamente sotto la radice del sito " / " (abbastanza comune per i semplici siti JSP) al packaging formale Java EE (dove la root di contesto sarà un percorso sotto la radice).

Ciò può significare molte modifiche al codice.

Se si desidera evitare o posticipare le modifiche al codice, ma garantire comunque il corretto riferimento alla root di contesto, una tecnica che ho testato consiste nell'utilizzare i filtri servlet. Il filtro può essere inserito in un progetto esistente senza modificare nulla (tranne web.xml) e rimappa tutti i riferimenti url nell'HTML in uscita sul percorso corretto e garantisce inoltre che i reindirizzamenti siano correttamente referenziati.

Un sito di esempio e un codice utilizzabile disponibili qui: EnforceContextRootFilter-1.0-src.zip NB: le regole di mappatura effettive sono implementate come regex nella classe servlet e forniscono un catch-all piuttosto generale - ma potrebbe essere necessario modificare per circostanze particolari.

a proposito, ho formulato una domanda leggermente diversa da affrontare migrazione della base di codice esistente da " / " verso un percorso di contesto non root

Tendo a scrivere una proprietà come parte della mia libreria JavaScript principale all'interno di my. Non penso sia perfetto, ma penso che sia il migliore che sono riuscito a ottenere.

Prima di tutto, ho un modulo che fa parte del mio core dell'app che è sempre disponibile

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

Uso quindi i riquadri apache con un'intestazione comune che contiene sempre quanto segue:

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

Ora che ho inizializzato il contesto, posso usare getUrl(path) da qualsiasi luogo (file js o all'interno di jsp / html) che restituirà un percorso assoluto per la stringa di input specificata nel contesto.

Si noti che i seguenti sono entrambi intenzionalmente equivalenti. getUrl restituirà sempre un percorso assoluto poiché un percorso relativo non ha bisogno che tu conosca il contesto in primo luogo.

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

Ecco il modo migliore: Filtro di reindirizzamento del contesto Il filtro deve essere applicato nel punto di estensione pre-partita e quindi utilizzare l'annotazione @PreMatching.

I filtri che implementano questa interfaccia devono essere annotati con @Provider per essere scoperti dal runtime JAX-RS. Le istanze di filtro richieste contenitore possono anche essere scoperte e associate dinamicamente a metodi di risorse particolari.

Spiegato con il codice di esempio:

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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top