Ответ 1
Причина, по которой вы получаете ошибку 404 File Not Found
, заключается в том, что в вашем пути к CSS, указанному как значение атрибуту href
, отсутствует путь контекста.
URL-адрес HTTP-запроса содержит следующие части:
http://[host]:[port][request-path]?[query-string]
Путь запроса также состоит из следующих элементов:
-
Контекстный путь: конкатенация косой черты (/) с контекст root веб-приложения сервлета. Пример:
http://host[:port]/context-root[/url-pattern]
-
Путь сервлета: раздел пути, соответствующий компоненту псевдоним, который активировал этот запрос. Этот путь начинается с форварда slash (/).
-
Информация о пути: часть пути запроса, которая не является частью путь контекста или путь сервлета.
Подробнее здесь.
Решение
Есть несколько решений вашей проблемы, вот некоторые из них:
1) Использование тега <c:url>
из JSTL
В моих веб-приложениях Java я обычно использовал <c:url>
тег JSTL при определении пути к CSS/JavaScript/image и другим статическим ресурсам. Поступая таким образом, вы можете быть уверены, что эти ресурсы ссылаются на всегда относительно контекста приложения (путь контекста).
Если вы скажете, что ваш CSS находится внутри папки WebContent, тогда это должно работать:
<link type="text/css" rel="stylesheet" href="<c:url value="/globalCSS.css" />" />
Причина, по которой это работает, объясняется в "Стандартной библиотеке тегов JavaServer Pages ™" версии 1.2 спецификация, глава 7.5 (акцент мой):
7,5 < c: url >
Создает URL-адрес с соответствующими правилами перезаписи.
...
URL должен быть абсолютным URL-адресом начиная со схемы (например, "http://server/context/page.jsp" ) или относительный URL-адрес, определенный JSP 1.2 в JSP.2.2.1 "Относительный URL-адрес Спецификация". Как следствие, реализация должна добавить контекстный путь к URL-адресу, который начинается с косой черты (например, "/page2.jsp" ), поэтому что такие URL-адреса могут быть правильно интерпретированы клиентским браузером.
Примечание
Не забудьте использовать директиву Taglib в своем JSP, чтобы иметь возможность ссылаться на теги JSTL. Также см. Пример JSP-страницы здесь.
2) Использование языка выражения JSP и неявных объектов
Альтернативное решение использует Язык выражений (EL) для добавления контекста приложения:
<link type="text/css" rel="stylesheet" href="${pageContext.request.contextPath}/globalCSS.css" />
Здесь мы получили путь к контексту из объекта запроса. А для доступа к объекту запроса мы использовали pageContext неявный объект.
3) Использование тега <c:set>
из JSTL
ОТКАЗ
Идея этого решения была взята из здесь.
Чтобы сделать доступ к контекстному пути более компактным, чем в решении №2, вы можете сначала использовать тег JaTL <c:set>
, который устанавливает значение переменной EL или свойство переменной EL в любой из областей JSP (страница, запрос, сеанс или приложение) для последующего доступа.
<c:set var="root" value="${pageContext.request.contextPath}"/>
...
<link type="text/css" rel="stylesheet" href="${root}/globalCSS.css" />
ВАЖНОЕ ЗАМЕЧАНИЕ
По умолчанию для того, чтобы установить такую переменную, JSP, который содержит этот тег, должен иметь доступ хотя бы один раз (в том числе в случае установки значения в области приложения с использованием атрибута scope, например <c:set var="foo" value="bar" scope="application" />
), до, используя эту новую переменную. Например, вы можете иметь несколько JSP файлов, где вам нужна эта переменная. Таким образом, вы должны использовать эфир a) и установить новую переменную, содержащую контекст контекста в области приложения И сначала получить этот JSP, прежде чем использовать эту переменную в других JSP файлах, или b) установить эту переменную хранения контекста в КАЖДЫЙ JSP файл, где вам нужно получить доступ к нему.
4) Использование ServletContextListener
Более эффективный способ сделать доступ к контекстному пути более компактным - это установить переменную, которая будет удерживать путь контекста и хранить его в приложении с помощью прослушиватель. Это решение похоже на решение №3, но преимущество заключается в том, что теперь путь контекста переноса переменных устанавливается в началевеб-приложения и доступно для широкого применения, нет необходимости в дополнительных шагах.
Нам нужен класс, который реализует интерфейс ServletContextListener. Вот пример такого класса:
package com.example.listener;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class AppContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent event) {
ServletContext sc = event.getServletContext();
sc.setAttribute("ctx", sc.getContextPath());
}
@Override
public void contextDestroyed(ServletContextEvent event) {}
}
Теперь в JSP мы можем получить доступ к этой глобальной переменной, используя EL:
<link type="text/css" rel="stylesheet" href="${ctx}/globalCSS.css" />
Примечание
@WebListener аннотация доступна с сервлета версии 3.0. Если вы используете контейнер сервлетов или сервер приложений, который поддерживает более старые спецификации сервлета, удалите аннотацию @WebServlet и вместо этого настройте прослушиватель в дескрипторе развертывания (web.xml). Ниже приведен пример файла web.xml для контейнера, который поддерживает максимальную версию сервлета 2.5 (для краткости опущены другие конфигурации):
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
...
<listener>
<listener-class>com.example.listener.AppContextListener</listener-class>
</listener>
...
</webapp>
5) Использование сценариев
Как предлагаемый пользователем @gavenkoa вы также можете использовать scriptlets следующим образом:
<%= request.getContextPath() %>
Для такой маленькой вещи, вероятно, хорошо, просто обратите внимание, что обычно использование сценариев в JSP не рекомендуется.
Заключение
Я лично предпочитаю эфир первым решением (чаще всего использовал его в моих предыдущих проектах) или второй, поскольку они наиболее ясны, интуитивно понятны и недвусмысленны (IMHO). Но вы выбираете то, что вам больше всего подходит.
Другие мысли
Вы можете развернуть свое веб-приложение в качестве приложения по умолчанию (т.е. в корневом контексте по умолчанию), поэтому к нему можно получить доступ без указания пути к контексту. Подробнее читайте в разделе "Обновить" здесь.