Любые умные способы обработки контекста в веб-приложении? - PullRequest
39 голосов
/ 24 сентября 2008

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

Таким образом myapp.war развернут на http://example.com/myapp.

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

».

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

Однако вы не можете сделать это, скажем, с помощью тега IMG в HTML. Если вы сделаете image, скорее всего, вы получите 404, потому что вы действительно хотели "/myapp/myimage.gif".

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

Для программистов это непростая проблема: когда нужно использовать URL-адрес App Relative против абсолютного URL-адреса.

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

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

Что ты делаешь?

Ответы [ 14 ]

24 голосов
/ 24 сентября 2008

Вы можете использовать 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 и применяемые методы схожи - единственное реальное отличие - это получение корневого контекста другим способом.

8 голосов
/ 10 февраля 2011

Для страниц 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');

Смотри также:

4 голосов
/ 10 февраля 2011

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

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

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

3 голосов
/ 04 октября 2008

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

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

С Сервлет 2.3: Доступны новые функции :

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

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

1 голос
/ 26 сентября 2008

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

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

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

Имейте в виду, макет не должен быть абсолютно плоским, просто последовательным.

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

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

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

1 голос
/ 25 сентября 2008

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

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

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

1 голос
/ 24 сентября 2008

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

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

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

1 голос
/ 24 сентября 2008

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

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

<img src="myimage.gif"/>

вместо

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

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

1 голос
/ 24 сентября 2008

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

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

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

1 голос
/ 24 сентября 2008

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

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

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

...