Подтвердить что ты не робот

Какие-нибудь умные способы обработки контекста в веб-приложении?

В Java веб-приложения включены в WAR. По умолчанию многие контейнеры сервлетов будут использовать имя WAR в качестве имени контекста для приложения.

Таким образом, myapp.war развертывается в http://example.com/myapp.

Проблема в том, что webapp считает, что его "корень" - это "корень" или просто "/", тогда как HTML рассмотрит корень вашего приложения как "/myapp".

В API-интерфейсе Servlet и JSP есть средства для управления этим. Например, если в сервлете вы выполните: response.sendRedirect( "/mypage.jsp" ), контейнер добавит контекст и создаст URL-адрес: http://example.com/myapp/mypage.jsp".

Однако вы не можете сделать это, скажем, с тегом IMG в HTML. Если вы делаете < img src="/myimage.gif "/" > , вы, скорее всего, получите 404, потому что то, что вы действительно хотели, было "/myapp/myimage.gif".

Многие фреймворки имеют теги JSP, которые также знакомы с контекстом, и есть разные способы создания правильных URL-адресов в JSP (ни один из них не особенно элегантен).

Это проблема для кодировщиков, чтобы перейти от того, когда использовать URL-адрес приложения "Относительный", по сравнению с абсолютным URL-адресом.

Наконец, есть проблема с кодом Javascript, который должен создавать URL-адреса "на лету" и встроенными URL-адресами в CSS (для фоновых изображений и т.п.).

Мне любопытно, какие методы используют другие, чтобы смягчить и обойти эту проблему. Многие просто punt и жестко кодируют его, либо в корне сервера, либо в любом контексте, который они используют. Я уже знаю этот ответ, это не то, что я ищу.

Чем вы занимаетесь?

4b9b3361

Ответ 1

Вы можете использовать JSTL для создания URL-адресов.

Например, <c:url value="/images/header.jpg" /> будет префикс корня контекста.

С CSS это обычно не проблема для меня.

У меня есть корневая структура в Интернете, как это:

/CSS
/изображений

В CSS файле вам просто нужно использовать относительные URL-адреса (../images/header.jpg), и ему не нужно знать о корне контекста.

Что касается JavaScript, то для меня работает какой-то общий JavaScript в заголовке страницы:

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

Тогда вы можете использовать корень контекста во всех своих сценариях (или вы можете определить функцию для создания путей - может быть немного более гибкой).

Очевидно, что все это зависит от использования JSP и JSTL, но я использую JSF с Facelets, и связанные с ним методы похожи - единственная реальная разница заключается в том, что корневой контекст становится другим.

Ответ 2

Для HTML-страниц я просто установил тег HTML <base>. Каждое относительное звено (т.е. Не начинается со схемы или /) будет относиться к нему. Нет чистого способа сразу его схватить на 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>

Это, в свою очередь, является предостережением: привязки (URL #identifier) также будут относиться к базовому пути. Если у вас есть какой-либо из них, вы хотели бы сделать это относительно URL-адреса запроса (URI). Итак, измените, например,

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

к

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

В JS вы можете просто получить доступ к элементу <base> из DOM, когда хотите конвертировать относительный URL-адрес в абсолютный URL-адрес.

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');

См. также:

Ответ 3

API Servlet и JSP имеют чтобы помочь справиться с этим. Для Например, если в сервлете вы выполните: response.sendRedirect( "/mypage.jsp" ), контейнер добавит контекст и создать URL-адрес: http://example.com/myapp/mypage.jsp".

А, может быть, может и нет - это зависит от вашего контейнера и спецификации сервлета!

От Servlet 2.3: Новые функции, выставленные:

И, наконец, после продолжительных дебатов группа экспертов, Servlet API 2.3 выяснилось раз и навсегда точно что происходит на вызов res.sendRedirect( "/index.html" ) для сервлета, выполняющегося в пределах non-root context. Проблема в том, что API сервлета 2.2 требует неполного путь, например "/index.html" переведенный контейнером сервлета в полный путь, но не говорит как обрабатываются контекстные пути. Если сервлет делает вызов в контекст на пути "/contextpath", следует перевести URI переадресации относительно корня контейнера (http://server:port/index.html) или контекстный корень (http://server:port/contextpath/index.html)? Для максимальной переносимости необходимо определить поведение; после длительных дебатов эксперты решил перевести по отношению к контейнерный корень. Для тех, кто хочет контекст, вы можете вывод из getContextPath() на ваш URI.

Так нет, с 2.3 ваши пути не автоматически переводятся, чтобы включить путь к контексту.

Ответ 4

Я согласен с tardate. Я также обратил внимание на фильтры и нашел решение перед проектом UrlRewriteFilter. Простая конфигурация, например:

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

помогает пересылать все запросы на путь */resources к /resources pass (включая префикс пути к контексту). Поэтому я могу просто поместить все мои изображения и CSS в папку ресурсы и продолжать использовать относительные URL-адреса в своих стилях для фоновых изображений и других случаев.

Ответ 5

Я использовал вспомогательные классы для создания тегов img и т.д. Этот класс-помощник заботится о префиксах пути с помощью application contextPath. (Это работает, но мне это не очень нравится. Если у кого-то есть лучшие альтернативы, расскажите.)

Для путей в css файлах и т.д. Я использую Ant build script, который использует site.production.css для site.css в производственной среде и site.development.css в разработке encironment.

В качестве альтернативы я иногда использую Ant script, который заменяет токены @token @ соответствующими данными для разных окружений. В этом случае @contextPAth @token будет заменен на правильный путь контекста.

Ответ 6

Один из вариантов - использовать "плоскую" структуру приложения и относительные URL-адреса, когда это возможно.

Под "плоской" я подразумеваю, что под вашим корнем приложения нет подкаталогов, может быть, всего несколько каталогов для статического контента как "images/". Все ваши JSP файлы, URL-адреса действий, сервлеты идут прямо под корнем.

Это не полностью решает вашу проблему, но значительно упрощает ее.

Ответ 7

Вилмантас сказал здесь правильное слово: относительные URL.

Все, что вам нужно сделать в IMG, это использовать

<img src="myimage.gif"/>

вместо

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

и это будет относиться к контексту приложения (поскольку браузер интерпретирует URL-адрес для перехода)

Ответ 8

За исключением особых случаев, я бы рекомендовал не использовать абсолютные URL-адреса таким образом. Когда-либо. Абсолютные URL-адреса хороши, когда другой webapp указывает на что-то в вашем webapp. Внутренне - когда один ресурс указывает на второй ресурс в том же контексте - ресурс должен знать, где он живет, поэтому он должен иметь возможность выражать относительный путь ко второму ресурсу.

Конечно, вы будете писать модульные компоненты, которые не знают ресурс, включающий их. Например:

/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() %> для создания абсолютного пути.

Ответ 9

Вы можете использовать request.getContextPath() для создания абсолютных URL-адресов, которые не жестко закодированы в конкретном контексте. Как указывалось ранее, для JavaScript вы просто устанавливаете переменную в верхней части своего JSP (или предпочтительно в шаблоне) и префикс в качестве контекста.

Это не работает для замены изображений CSS, если вы не хотите динамически генерировать CSS файл, что может вызвать другие проблемы. Но так как вы знаете, где ваш CSS файл относится к вашим изображениям, вы можете уйти с относительными URL-адресами.

По какой-то причине у меня возникли проблемы с обработкой относительных URL-адресов IE и пришлось вернуться к использованию выражений с переменной JavaScript, установленной в контексте. Я просто разделил свои замены изображений IE на свой собственный файл и использовал макросы IE, чтобы вытащить правильные. Это было неважно, потому что я уже должен был это делать, чтобы иметь дело с прозрачными PNG. Это не очень, но это работает.

Ответ 10

Я использовал большинство этих методов (кроме архитектуры XSLT).

Я думаю, что проблема (и консенсус) проблемы связана с сайтом с потенциально несколькими каталогами.

Если ваша глубина вашего каталога (из-за отсутствия лучшего термина) является постоянной, то вы можете полагаться на относительные URL-адреса в таких вещах, как CSS.

Разум, макет не обязательно должен быть полностью плоским, просто согласованным.

Например, мы выполнили иерархии, такие как /css,/js,/common,/admin,/user. Размещение соответствующих страниц и ресурсов в соответствующих каталогах. Наличие такой структуры очень хорошо работает с аутентификацией на основе контейнеров.

Я также сопоставил *.css и *.js с сервлетами JSP и сделал их динамическими, чтобы я мог создавать их на лету.

Я просто надеялся, что есть что-то еще, что я, возможно, пропустил.

Ответ 11

Я ни в коем случае не утверждаю, что следующая элегантная проблема. На самом деле, оглядываясь назад, я бы не стал рекомендовать этот вопрос с учетом (наиболее вероятного) удара производительности.

Наши JSP-приложения для веб-приложений были строго XML-данными. Затем эти необработанные данные были отправлены в XSL (на стороне сервера), которые применяли правильные теги CSS и выплевывали XHTML.

У нас был единственный template.xsl, который был бы унаследован несколькими XSL файлами, которые мы использовали для разных компонентов веб-сайта. Наши пути были определены в файле XSL, называемом 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>

Внутренняя ссылка будет в 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 передавался в каждый файл с помощью ${applicationScope.contextPath} Идея, лежащая в основе использования XML, а не просто жесткого кодирования в файле JSP/Java, мы не хотели перекомпилировать.

Опять же, решение не совсем хорошее... но мы использовали его один раз!

Изменить. На самом деле сложность в нашей проблеме возникла из-за того, что мы не могли использовать JSP для всего нашего представления. Почему бы кто-то просто не использовал ${applicationScope.contextPath} для извлечения контекстного пути? Тогда это сработало хорошо.

Ответ 12

При создании сайта с нуля я сторонник @Will - нацелен на последовательную и предсказуемую структуру URL-адресов, чтобы вы могли придерживаться относительных ссылок.

Но все может стать действительно беспорядочным, если вы обновляете сайт, который изначально был создан для работы непосредственно под корнем сайта "/" (довольно распространенный для простых сайтов JSP) до формального Java EE (где корень контекста будет каким-то образом под корнем).

Это может означать много изменений кода.

Если вы хотите избежать или отложить изменения кода, но все же обеспечить правильную привязку корневого контекста, метод, который я тестировал, - использовать фильтры сервлетов. Фильтр можно отбросить в существующий proejct, не меняя ничего (кроме web.xml), и переназначит ссылки на url в исходящем HTML на правильный путь, а также обеспечит правильную ссылку перенаправления.

Пример сайта и полезного кода, доступных здесь: EnforceContextRootFilter-1.0-src.zip NB: фактические правила сопоставления реализованы как регулярные выражения в классе сервлета и обеспечивают довольно общий доступ - но вам может потребоваться изменить для определенных обстоятельств.

btw, я искал немного другой вопрос, чтобы адресовать перенос существующей базы кода с "/" на неконтекстный контекстный путь

Ответ 13

Я склонен писать свойство как часть моей основной библиотеки 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>

Теперь, когда я инициализировал контекст, я могу использовать getUrl(path) из любого места (файлы js или внутри jsp/html), который вернет абсолютный путь для данной входной строки в контексте.

Обратите внимание, что следующее эквивалентно преднамеренно. getUrl всегда будет возвращать абсолютный путь, поскольку относительный путь не обязательно должен знать контекст в первую очередь.

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

Ответ 14

Вот лучший способ: Фильтр перенаправления контекста Фильтр должен быть применен в точке предварительного соответствия и, таким образом, использовать аннотацию @PreMatching.

Фильтры, реализующие этот интерфейс, должны быть аннотированы с помощью @Provider, который будет обнаружен во время выполнения JAX-RS. Экземпляры фильтра запросов контейнера также могут быть обнаружены и связаны динамически с определенными методами ресурсов.

Объяснение с примером кода:

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