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

22

我在Eclipse的项目中添加了一个外部CSS样式表,并将其放置在项目的WEB-CONTENTS文件夹中。当我将其部署到Tomcat上时,样式表未应用。当我在Chrome中进行调试并打开它时,它给了我“404文件未找到”的错误提示。为什么会出现这种情况,如何解决?

以下是代码:

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

你用来加载CSS文件的URL显然是不正确的。请发布你的HTML代码并告诉我们用于显示HTML页面的URL。 - JB Nizet
这些在工作区项目中的路径是什么? - nitind
1
CSS文件与访问它的JSP页面在同一个文件夹中,即WEB-CONTENTS文件夹。因此,我认为路径不是问题所在。 - Vishal Anand
密切相关:https://dev59.com/0HA65IYBdhLWcg3wvhXi - BalusC
2个回答

39
你收到 404 文件未找到 错误的原因是,作为 href 属性值给出的 CSS 路径缺少上下文路径
HTTP 请求 URL 包含以下部分:
http://[host]:[port][request-path]?[query-string]

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

  • 上下文路径:由斜杠(/)和servlet web应用程序的上下文根连接而成。例如:http://host[:port]/context-root[/url-pattern]

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

  • 路径信息:请求路径中不是上下文路径或servlet路径的部分。

这里阅读更多信息。


解决方案

有几种解决方案可供选择,以下是其中一些:

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

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

如果你说,你的CSS位于WebContent文件夹内,则应该可以这样做:

<link type="text/css" rel="stylesheet" href="<c:url value="/globalCSS.css" />" />

它能够工作的原因在于“JavaServer Pages™ Standard Tag Library” 1.2 版本 specification 第7.5章中有解释(重点在于我):

7.5 <c:url>
构建一个应用了适当重写规则的 URL。
...
URL 必须是以协议开头的绝对 URL(例如,“http:// server/context/page.jsp”),或者是由 JSP 1.2 在 JSP.2.2.1 “相对 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" />

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


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

免责声明
这个解决方案的想法来自这里

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

<c:set var="root" value="${pageContext.request.contextPath}"/>
...
<link type="text/css" rel="stylesheet" href="${root}/globalCSS.css" />

重要提示
默认情况下,为了以这种方式设置变量,包含此set标记的JSP必须至少访问一次(包括在使用scope属性将值设置在application范围内时,如<c:set var="foo" value="bar" scope="application" />),使用这个新变量之前。例如,您可能有多个需要此变量的JSP文件。因此,您必须要么a)同时在application范围内设置持有上下文路径的新变量,并首先访问此JSP,然后再在其他JSP文件中使用此变量,或者b)在每个需要访问它的JSP文件中设置此持有上下文路径的变量。


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) {}

}

现在在JSP中,我们可以使用EL访问这个全局变量:
<link type="text/css" rel="stylesheet" href="${ctx}/globalCSS.css" />

注意
@WebListener注解可用于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>


5) 使用脚本片段

如用户 @gavenkoa 建议 的那样,您也可以像这样使用 脚本片段

<%= request.getContextPath() %>

对于这样一件小事,可能是可以的,只要注意通常不建议在JSP中使用脚本片段


结论

我个人更喜欢第一种解决方案(在我的以前的项目中大部分时间都使用它)或第二种,因为它们最清晰、直观和明确(在我看来)。但你可以选择适合你自己的。


其他想法

您可以将Web应用程序部署为默认应用程序(即在默认根上下文中),因此可以无需指定上下文路径访问它。有关更多信息,请阅读“更新”部分此处


2
使用以下代码可以解决这个问题......如果您使用本地主机服务器运行文件,则可以通过以下Jsp页面代码解决此问题。将此代码放置在jsp文件的Head标签之间即可。
<style type="text/css">
    <%@include file="css/style.css" %>
</style>
<script type="text/javascript">
    <%@include file="js/script.js" %>
</script>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接