在JSP中添加外部资源(CSS/JavaScript /图像等)

Vis*_*and 22 jsp assets jstl el

我在项目中添加了一个外部CSS样式表,并放在Eclipse项目的WEB-CONTENTS文件夹中.当我在Tomcat上部署它时,没有应用样式表.当我在Chrome中调试并打开它时,它给了我404 file not found错误.为什么这样以及如何解决?

这是代码:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>joined now </title>

<link href="globalCSS.css" rel="stylesheet" type="text/css"/>

</head>
<body>
<div>this is at the top</div>
<c:import url="header.jsp" />
<c:import url="navigationBar.jsp" />  
<c:import url="leftpane.jsp" /> 
<c:import url="mainContent.jsp" /> 
<c:import url="rightpane.jsp" />
<c:import url="footer.jsp" />  
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

inf*_*k01 37

您收到404 File Not Found错误的原因是,作为href属性值的CSS 路径缺少上下文路径.

HTTP请求URL包含以下部分:

http://[host]:[port][request-path]?[query-string]
Run Code Online (Sandbox Code Playgroud)

请求路径是进一步由下列元素组成:

  • 上下文路径:正斜杠(/)与servlet Web应用程序的上下文根的串联.例:http://host[:port]/context-root[/url-pattern]

  • Servlet路径:与激活此请求的组件别名对应的路径部分.此路径以正斜杠(/)开头.

  • 路径信息:请求路径中不属于上下文路径或servlet路径的部分.

在这里阅读更多.


解决方案

您的问题有几种解决方案,其中一些是:

1)使用<c:url>来自JSTL的标签

在我的Java Web应用程序中,我通常在定义CSS/JavaScript/image和其他静态资源的路径时使用JSTL中的<c:url>标记.通过这样做,您可以确保始终相对于应用程序上下文(上下文路径)引用这些资源.

如果你说,你的CSS位于WebContent文件夹中,那么这应该工作:

<link type="text/css" rel="stylesheet" href="<c:url value="/globalCSS.css" />" />
Run Code Online (Sandbox Code Playgroud)

它的工作原理在" JavaServer Pages™标准标记库 "1.2版规范第7.5章(强调我的)中进行了解释:

7.5 <c:url>
使用适当的重写规则构建URL.
...
URL必须是以方案开头的绝对URL(例如"http:// server/context/page.jsp")或JSP.2.2.1中的JSP 1.2定义的相对URL"相对URL规范".因此,实现必须将上下文路径添加到以斜杠开头的URL(例如"/page2.jsp"),以便客户端浏览器可以正确解释这些URL.

注意
不要忘记在JSP中使用Taglib指令以便能够引用JSTL标记.另请参阅此处的示例JSP页面.


2)使用JSP表达式语言和隐式对象

一种解决方案是使用表达式语言(EL)添加应用程序上下文:

<link type="text/css" rel="stylesheet" href="${pageContext.request.contextPath}/globalCSS.css" />
Run Code Online (Sandbox Code Playgroud)

这里我们从请求对象中检索了上下文路径.为了访问请求对象,我们使用了pageContext 隐式对象.


3)使用<c:set>来自JSTL的标签

免责声明
此解决方案的想法取自此处.

要使访问上下文路径比解决方案№2更紧凑,您可以首先使用JSTL <c:set>标记,该标记在任何JSP范围(页面,请求,会话)中设置 EL变量的值或EL变量的属性或应用程序)以供以后访问.

<c:set var="root" value="${pageContext.request.contextPath}"/>
...
<link type="text/css" rel="stylesheet" href="${root}/globalCSS.css" />
Run Code Online (Sandbox Code Playgroud)

重要说明
默认情况下,为了以这种方式设置变量,必须至少访问包含此set标记的JSP 一次(包括在使用scope属性设置应用程序范围中的值的情况下),使用此之前新变量.例如,您可以在需要此变量的位置使用多个 JSP文件.所以,你必须醚)设置了新的变量保持上下文路径的应用范围,在其他JSP文件中使用这个变量之前先访问此JSP,或b)设置此上下文路径在EVERY JSP文件存储变量,你需要访问它.<c:set var="foo" value="bar" scope="application" />


4)使用ServletContextListener

使访问上下文路径更加紧凑的更有效方法是设置一个变量,该变量将保存上下文路径并使用Listener将其存储在应用程序范围中.此解决方案类似于解决方案№3,但好处是现在变量保持上下文路径在Web应用程序的开头设置,并且可在应用程序范围内使用,无需其他步骤.

我们需要一个实现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) {}

}
Run Code Online (Sandbox Code Playgroud)

现在在JSP中我们可以使用EL访问这个全局变量:

<link type="text/css" rel="stylesheet" href="${ctx}/globalCSS.css" />
Run Code Online (Sandbox Code Playgroud)

注意
@ ServListener注释自Servlet 3.0版起可用.如果使用支持旧Servlet规范的servlet容器或应用程序服务器,请删除@WebServlet批注,而是在部署描述符(web.xml)中配置监听器.以下是支持最大Servlet版本2.5的容器的web.xml文件示例(为简洁起见,省略了其他配置):

<?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>
Run Code Online (Sandbox Code Playgroud)


5)使用scriptlet

正如用户@gavenkoa建议那样,你也可以使用这样的scriptlet:

<%= request.getContextPath() %>
Run Code Online (Sandbox Code Playgroud)

对于这么小的事情,它可能是好的,请注意,通常不鼓励在JSP中使用scriptlet.


结论

我个人更喜欢第一种解决方案(大多数时候在我以前的项目中使用它)或第二种解决方案,因为它们最清晰,直观和明确(恕我直言).但是你选择最适合自己的东西.


其他想法

您可以将Web应用程序部署为默认应用程序(即在默认根上下文中),因此可以在不指定上下文路径的情况下访问它.有关详细信息,请阅读此处的"更新"部分.