Pregunta

En Java, las aplicaciones web están incluidas en WAR.De forma predeterminada, muchos contenedores de servlets utilizarán el nombre WAR como nombre de contexto para la aplicación.

Por lo tanto, myapp.war se implementa en http://ejemplo.com/miaplicación.

El problema es que la aplicación web considera que su "raíz" es, bueno, "raíz", o simplemente "/", mientras que HTML consideraría que la raíz de su aplicación es "/miaplicación".

La API de Servlet y JSP tienen funciones para ayudar a gestionar esto.Por ejemplo, si en un servlet haces:Response.sendRedirect("/mypage.jsp"), el contenedor antepondrá el contexto y creará la URL: http://ejemplo.com/miaplicación/mipágina.jsp".

Sin embargo, no puedes hacer eso con, digamos, la etiqueta IMG en HTML.Si haces <img src="/myimage.gif"/> probablemente obtendrás un 404, porque lo que realmente querías era "/myapp/myimage.gif".

Muchos marcos tienen etiquetas JSP que también tienen en cuenta el contexto, y hay diferentes formas de crear URL correctas dentro de JSP (ninguna particularmente elegante).

Es un problema esencial para los programadores decidir cuándo usar una URL "relativa a la aplicación", frente a una URL absoluta.

Finalmente, está la cuestión del código Javascript que necesita crear URL sobre la marcha y URL incrustadas en CSS (para imágenes de fondo y similares).

Tengo curiosidad por saber qué técnicas utilizan otros para mitigar y solucionar este problema.Muchos simplemente lo codifican y codifican, ya sea en la raíz del servidor o en cualquier contexto que estén usando.Ya sé esa respuesta, eso no es lo que estoy buscando.

¿A qué te dedicas?

¿Fue útil?

Solución

Puede utilizar JSTL para crear URL.

Por ejemplo, <c:url value="/images/header.jpg" /> antepondrá la raíz del contexto.

Con CSS, esto no suele ser un problema para mí.

Tengo una estructura raíz web como esta:

/css
/imagenes

En el archivo CSS, solo necesita usar URL relativas (../images/header.jpg) y no es necesario tener en cuenta la raíz del contexto.

En cuanto a JavaScript, lo que me funciona es incluir JavaScript común en el encabezado de la página como este:

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

Luego puede usar la raíz de contexto en todos sus scripts (o puede definir una función para crear rutas; puede ser un poco más flexible).

Obviamente, todo esto depende del uso de JSP y JSTL, pero yo uso JSF con Facelets y las técnicas involucradas son similares; la única diferencia real es obtener la raíz de contexto de una manera diferente.

Otros consejos

Para páginas HTML, simplemente configuro el HTML <base> etiqueta.Cada vínculo relativo (es decir,no comenzar con esquema o /) se volverá relativo a él.No hay una manera limpia de agarrarlo inmediatamente HttpServletRequest, por lo que necesitamos un poco de ayuda de JSTL aquí.

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

Sin embargo, esto tiene a su vez una advertencia:anclas (las #identifier Las URL) también serán relativas a la ruta base.Si tiene alguno de ellos, le gustaría hacerlo relativo a la URL de solicitud (URI).Entonces, cambia como

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

a

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

En JS, puedes simplemente acceder al <base> elemento del DOM siempre que desee convertir una URL relativa en una URL absoluta.

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

O si haces jQuery

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

En CSS, las URL de las imágenes son relativas a la URL de la propia hoja de estilo.Entonces, simplemente suelte las imágenes en alguna carpeta relativa a la propia hoja de estilo.P.ej.

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

y referenciarlos de la siguiente manera

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

Si prefiere colocar las imágenes en alguna carpeta al mismo nivel que la carpeta CSS

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

entonces usa ../ para ir a la carpeta principal común

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

Ver también:

estoy de acuerdo con tardar.También presté atención a los filtros y encontré la solución de cara al proyecto. Filtro de reescritura de URL.La configuración simple como la siguiente:

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

ayuda a reenviar todas las solicitudes de */ruta de recursos al paso de /recursos (incluido el prefijo de ruta de contexto).Entonces puedo simplemente poner todos mis imágenes y CSS archivos bajo recursos carpeta y continuar usando URL relativas en mis estilos para imágenes de fondo y otros casos.

La API de Servlet y JSP tienen instalaciones para ayudar a administrar esto.Por ejemplo, si, en un servlet, lo hace:Response.sendedirect ("/mypage.jsp"), el contenedor prefabricará el contexto y creará la URL: http://ejemplo.com/miaplicación/mipágina.jsp".

Ah, tal vez, tal vez no, ¡depende de su contenedor y de la especificación del servlet!

De Servlet 2.3:Nuevas características expuestas:

Y finalmente, después de un largo debate de un grupo de expertos, Servlet API 2.3 ha aclarado de una vez por todas exactamente lo que sucede en un res.El problema es que Servlet API 2.2 requiere una ruta incompleta como "/index.html" para ser traducida por el contenedor Servlet a una ruta completa, pero no dice cómo se manejan las rutas de contexto.Si el servlet que realiza la llamada está en un contexto en la ruta "/ContextPath", si el URI de redirigir se traduce en relación con la raíz del contenedor (http://servidor:puerto/index.html) o la raíz de contexto (http://servidor:puerto/contextpath/index.html)?Para la máxima portabilidad, es imperativo definir el comportamiento;Después de un largo debate, los expertos optaron por traducir en relación con la raíz del contenedor.Para aquellos que desean contexto relativo, puede prepender el resultado de getContextPath () a su URI.

Entonces no, con 2.3 tus caminos son no traducido automáticamente para incluir la ruta de contexto.

he usado clases de ayuda para generar etiquetas img, etc.Esta clase de ayuda se encarga de prefijando rutas con la ruta contextual de la aplicación.(Esto funciona, pero no me gusta mucho.Si alguien tiene alguna alternativa mejor, por favor dígala).

Para rutas en archivos css, etc.yo uso un Script de construcción de hormigas que utiliza site.production.css para site.css en el entorno de producción y site.development.css en el entorno de desarrollo.

Alternativamente, a veces uso un script Ant que reemplaza @token@ tokens con datos adecuados para diferentes entornos.En este caso, el token @contextPAth@ se reemplazaría con la ruta de contexto correcta.

Una opción es utilizar una estructura de aplicación "plana" y URL relativas siempre que sea posible.

Por "plano" quiero decir que no hay subdirectorios bajo la raíz de su aplicación, tal vez solo unos pocos directorios para contenido estático como "imágenes/".Todos sus JSP, URL de acción y servlets van directamente debajo de la raíz.

Esto no resuelve completamente su problema pero lo simplifica enormemente.

Vilmantas dijo aquí la palabra correcta:URL relativas.

Todo lo que necesitas hacer en tu IMG es usar

<img src="myimage.gif"/>

en lugar de

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

y será relativo al contexto de la aplicación (ya que el navegador interpreta la URL a la que ir)

Excepto en casos especiales, no recomendaría utilizar URL absolutas de esta manera.Alguna vez.Las URL absolutas son buenas para cuando otra aplicación web está apuntando a algo en su aplicación web.Internamente, cuando un recurso apunta a un segundo recurso en el mismo contexto, el recurso debe saber dónde vive, por lo que debería poder expresar una ruta relativa al segundo recurso.

Por supuesto, escribirá componentes modulares, que no conocen el recurso que los incluye.Por ejemplo:

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

Entonces, ¿cómo email.jsp conocer el camino relativo de sendmail.jsp?Claramente el enlace se romperá en cualquiera de los dos casos. /myapp/browse/profile.jsp o se romperá /myapp/home.jsp .La respuesta es: mantenga todas sus URL en el mismo espacio plano de ruta de archivo.Es decir, cada URL no debe tener barras después /myapp/ .

Esto es bastante fácil de lograr, siempre y cuando tengas algún tipo de mapeo entre las URL y los archivos reales que generan el contenido.(p.ej.en Spring, use DispatcherServlet para asignar URL a archivos JSP o vistas).

Hay casos especiales.p.ej.Si estás escribiendo una aplicación del lado del navegador en Javascript, entonces será más difícil mantener un espacio de ruta de archivo plano.En ese caso, o en otros casos especiales, o simplemente si tiene una preferencia personal, no es gran cosa usarlo <%= request.getContextPath() %> para crear un camino absoluto.

Puede utilizar request.getContextPath() para crear URL absolutas que no estén codificadas para un contexto específico.Como indicó una respuesta anterior, para JavaScript simplemente establece una variable en la parte superior de su JSP (o preferiblemente en una plantilla) y le pone un prefijo como contexto.

Eso no funciona para el reemplazo de imágenes CSS a menos que desee generar dinámicamente un archivo CSS, lo que puede causar otros problemas.Pero como sabes dónde está tu archivo CSS en relación con tus imágenes, puedes salirte con la tuya con URL relativas.

Por alguna razón, tuve problemas con IE para manejar URL relativas y tuve que recurrir al uso de expresiones con una variable de JavaScript configurada en el contexto.Simplemente dividí mis reemplazos de imágenes de IE en su propio archivo y usé macros de IE para extraer las correctas.No fue un gran problema porque de todos modos ya tenía que hacer eso para lidiar con archivos PNG transparentes.No es bonito, pero funciona.

He utilizado la mayoría de estas técnicas (guarde la arquitectura XSLT).

Creo que el quid (y el consenso) del problema es tener un sitio con potencialmente múltiples directorios.

Si la profundidad de su directorio (a falta de un término mejor) es constante, entonces puede confiar en URL relativas en cosas como CSS.

Tenga en cuenta que el diseño no tiene que ser completamente plano, sólo coherente.

Por ejemplo, hemos creado jerarquías como /css, /js, /common, /admin, /user.Colocar páginas y recursos apropiados en los directorios adecuados.Tener una estructura como esta funciona muy bien con la autenticación basada en contenedores.

También asigne *.css y *.js al servlet JSP y los hice dinámicos para poder compilarlos sobre la marcha.

Sólo esperaba que hubiera algo más que me hubiera perdido.

yo por No Significa afirmar que lo siguiente es un tema elegante.De hecho, en retrospectiva, no recomendaría este problema dado el (muy probable) impacto en el rendimiento.

Los JSP de nuestra aplicación web eran estrictamente datos sin procesar XML.Estos datos sin procesar luego se enviaron a un XSL (del lado del servidor) que aplicó las etiquetas CSS correctas y escupió el XHTML.

Teníamos un único template.xsl que sería heredado por los múltiples archivos XSL que teníamos para los diferentes componentes del sitio web.Todas nuestras rutas se definieron en un archivo XSL llamado 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 enlace interno estaría en el XML de la siguiente manera:

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

Esto sería procesado por nuestro 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 se pasó a cada archivo con ${applicationScope.contextPath} La idea detrás de nosotros usando XML en lugar de simplemente codificarlo en un archivo JSP/Java era que no queríamos tener que volver a compilarlo.

Una vez más, la solución no es nada buena... ¡pero la usamos una vez!

Editar:En realidad, la complejidad de nuestro problema surgió porque no pudimos usar JSP para toda nuestra vista.¿Por qué alguien simplemente no usaría ${applicationScope.contextPath} para recuperar la ruta de contexto?Entonces nos funcionó bien.

Al crear un sitio desde cero, me pongo del lado de @Will: busque una estructura de URL consistente y predecible para que pueda ceñirse a referencias relativas.

Pero las cosas pueden complicarse mucho si actualiza un sitio que fue creado originalmente para funcionar directamente bajo la raíz del sitio "/" (bastante común para sitios JSP simples) a formato formal. JavaEE empaquetado (donde la raíz de contexto será alguna ruta debajo de la raíz).

Eso puede significar muchos cambios de código.

Si desea evitar o posponer los cambios de código, pero aún así garantizar una referencia correcta a la raíz del contexto, una técnica que he probado es utilizar filtros de servlet.El filtro se puede colocar en un proyecto existente sin cambiar nada (excepto web.xml) y reasignará cualquier referencia de URL en el HTML saliente a la ruta correcta y también garantizará que se haga referencia correctamente a las redirecciones.

Un sitio de ejemplo y código utilizable disponibles aquí: EnforceContextRootFilter-1.0-src.zip NÓTESE BIEN:Las reglas de mapeo reales se implementan como expresiones regulares en la clase de servlet y proporcionan un comodín bastante general, pero es posible que deba modificarlas para circunstancias particulares.

Por cierto, bifurqué una pregunta ligeramente diferente para abordar migrar la base de código existente de "/" a una ruta de contexto no raíz

Tiendo a escribir una propiedad como parte de mi biblioteca principal de JavaScript dentro de mi.No creo que sea perfecto pero creo que es lo mejor que he logrado lograr.

En primer lugar, tengo un módulo que forma parte del núcleo de mi aplicación y que siempre está 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 || {});

Luego uso mosaicos de Apache con un encabezado común que siempre contiene lo siguiente:

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

Ahora que he inicializado el contexto que puedo usar getUrl(path) desde cualquier lugar (archivos js o dentro de jsp/html) que devolverá una ruta absoluta para la cadena de entrada dada dentro del contexto.

Tenga en cuenta que los siguientes son equivalentes intencionalmente. getUrl siempre devolverá una ruta absoluta ya que una ruta relativa no necesita que conozcas el contexto en primer lugar.

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

Esta es la mejor manera:El filtro de redirección de contexto debe aplicarse en el punto de extensión previo al partido y, por lo tanto, usar anotación @prematching.

Los filtros que implementan esta interfaz deben anotarse con @Provider para que el tiempo de ejecución JAX-RS los descubra.Las instancias de filtro de solicitudes de contenedor también se pueden descubrir y vincular dinámicamente a métodos de recursos particulares.

Explicado con código de muestra:

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top