什么是 WEB-INF?
WEB-INF (Web Application) 目录是 Java Web 应用程序中的一个特殊目录,它遵循 Java Servlet 规范,是 Web 应用程序的标准目录结构的一部分。

核心特点:
- 对客户端不可直接访问:这是
WEB-INF最重要、最核心的特点,浏览器(客户端)无法通过 URL 直接访问WEB-INF目录及其下的任何资源,如果你有一个文件WEB-INF/config.properties,用户在浏览器中输入http://yourdomain.com/your-app/WEB-INF/config.properties是无法访问到这个文件的。 - 存放核心配置和资源:这个目录用于存放那些不应该被外界直接访问,但被服务器端代码(如 Servlet, Filter, JSP)所必需的文件。
- 受服务器保护:Web 服务器(如 Tomcat, Jetty, JBoss)会确保所有对
WEB-INF的直接访问请求都被拒绝。
WEB-INF 目录下的常见子目录和文件
一个典型的 WEB-INF 目录结构如下:
your-web-app/
├── index.html
├── images/
│ └── logo.png
├── css/
│ └── style.css
├── js/
│ └── app.js
└── WEB-INF/ <-- 根目录下的 WEB-INF
├── web.xml <-- 部署描述符(Servlet 3.0 以前是必须的)
├── classes/ <-- 存放编译后的 .class 文件(Java 源代码在 src 目录下)
│ ├── com/
│ │ └── example/
│ │ └── MyServlet.class
│ └── META-INF/
│ └── MANIFEST.MF
└── lib/ <-- 存放第三方依赖的 JAR 包
├── jackson-core-2.13.0.jar
└── commons-lang3-3.12.0.jar
详解:
-
web.xml(Web Application Deployment Descriptor)- 作用:Web 应用的配置文件,它定义了 Servlet、Filter、Listener、Servlet 映射、欢迎页面、错误页面等。
- 重要性:在 Servlet 3.0 规范之前,
web.xml是配置 Web 应用的唯一方式,从 Servlet 3.0 开始,引入了注解(如@WebServlet)和编程式配置,web.xml变为可选,但很多老项目或复杂配置仍在使用它。
-
classes/目录- 作用:存放编译后的 Java 字节码文件(
.class文件)。 - 类加载路径:这个目录是 Web 应用的根类路径(Root Classpath),服务器会自动加载此目录下的所有类。
- 注意:如果你的源代码在
src目录下,那么在构建项目(如使用 Maven 或 Gradle)时,编译后的.class文件会被自动复制到WEB-INF/classes目录下。
- 作用:存放编译后的 Java 字节码文件(
-
lib/目录
(图片来源网络,侵删)- 作用:存放第三方库的 JAR 包。
- 类加载路径:此目录下的所有 JAR 包也会被 Web 应用加载。
lib目录下的 JAR 优先级高于classes目录。 - 依赖管理:在现代项目中(如 Maven, Gradle),你通常不需要手动将 JAR 包复制到这里,构建工具会自动处理依赖,并将其打包到最终的 WAR 文件中的
WEB-INF/lib目录。
-
lib/和classes/的区别:classes/存放项目自己编写的代码。lib/存放外部的、第三方的库。- 两者共同构成了 Web 应用的类加载路径,但
lib中的 JAR 会被优先加载。
为什么要把资源放在 WEB-INF 下?(主要用途)
-
安全性
- 这是最主要的原因,数据库配置文件(如
db.properties)、Spring 的配置文件(如applicationContext.xml)、日志配置文件等包含了敏感信息,绝不能被外部用户直接访问,将它们放在WEB-INF下,可以确保只有服务器端的 Java 代码才能读取,而浏览器无法通过 URL 直接获取。
- 这是最主要的原因,数据库配置文件(如
-
保护核心资源
- 有些 JSP 页面或 HTML 页面可能只应通过特定流程(如登录后)才能访问,或者作为内部模板使用,将它们放在
WEB-INF下,可以防止用户直接通过 URL 访问,只能通过服务器端跳转(如RequestDispatcher.forward())来展示。
- 有些 JSP 页面或 HTML 页面可能只应通过特定流程(如登录后)才能访问,或者作为内部模板使用,将它们放在
-
作为应用的私有目录
(图片来源网络,侵删)WEB-INF是 Web 应用的私有空间,应用可以在此目录下创建自己的临时文件、缓存文件等,而不用担心被外部干扰或直接访问。
如何在 Java 代码中访问 WEB-INF 下的资源?
由于 WEB-INF 对外不可见,你不能使用普通的文件路径来访问,必须使用 Servlet API 提供的方法。
使用 ServletContext.getResourceAsStream()
这是最推荐、最标准的方法。ServletContext 对象代表了整个 Web 应用,它可以用来获取应用内的任何资源。
场景:读取配置文件(如 config.properties)。
假设文件路径:WEB-INF/config/config.properties
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServlet;
import java.io.InputStream;
import java.util.Properties;
public class MyConfigLoader extends HttpServlet {
public void loadConfig() {
// 1. 获取 ServletContext 对象
ServletContext context = getServletContext();
// 2. 使用 getResourceAsStream 获取文件的输入流
// 路径必须以 "/" 开头,表示从 Web 应用的根目录开始
String path = "/WEB-INF/config/config.properties";
InputStream inputStream = context.getResourceAsStream(path);
if (inputStream != null) {
try {
Properties props = new Properties();
props.load(inputStream);
// 读取配置项
String dbUrl = props.getProperty("db.url");
String dbUser = props.getProperty("db.user");
System.out.println("Database URL: " + dbUrl);
System.out.println("Database User: " + dbUser);
} catch (Exception e) {
e.printStackTrace();
} finally {
// 3. 关闭流
try {
if (inputStream != null) {
inputStream.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
} else {
System.err.println("Config file not found at: " + path);
}
}
}
关键点:
context.getResourceAsStream("/WEB-INF/..."):路径必须以 开头,它相对于 Web 应用的根目录。- 这个方法返回的是一个
InputStream,非常适合读取文本、XML、属性文件等配置资源。 - 它不能直接获取文件的绝对路径(如
C:\tomcat\webapps\app\WEB-INF\...),因为 Web 应用可能被打包成 WAR 文件,路径是虚拟的。
使用 ServletContext.getRealPath() 结合 RequestDispatcher
场景:你想将一个位于 WEB-INF 下的 JSP 页面(如 WEB-INF/views/dashboard.jsp)转发给客户端显示。
你不能直接 new File("/WEB-INF/views/dashboard.jsp"),因为路径不对,你需要先获取其服务器上的真实路径,然后转发。
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class DashboardServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1. 获取 WEB-INF 下 JSP 文件的虚拟路径
String jspPath = "/WEB-INF/views/dashboard.jsp";
// 2. 使用 RequestDispatcher 进行服务器端转发
// 这是访问 WEB-INF 下 JSP 的标准方式!
RequestDispatcher dispatcher = request.getRequestDispatcher(jspPath);
// 可以在转发前向 request 中添加一些数据
request.setAttribute("username", "John Doe");
// 3. 执行转发
dispatcher.forward(request, response);
}
}
关键点:
request.getRequestDispatcher("/WEB-INF/..."):这是访问WEB-INF下 JSP 页面的唯一正确方式。RequestDispatcher.forward()是在服务器端完成的,浏览器地址栏的 URL 不会改变,仍然是请求DashboardServlet的 URL。- 不要尝试用
getRealPath()来读取 JSP 内容或进行文件操作,它的主要用途是获取文件的物理路径(用于文件上传后保存),但对于WEB-INF下的资源,forward是首选。
路径总结
| 访问方式 | 路径示例 | 说明 |
|---|---|---|
| 浏览器 URL 直接访问 | http://.../index.html |
index.html 在 Web 根目录下,可以访问。 |
http://.../WEB-INF/web.xml |
错误,无法访问,会被服务器拒绝。 | |
ServletContext.getResourceAsStream() |
context.getResourceAsStream("/WEB-INF/config.properties") |
正确,用于读取配置文件等资源,返回 InputStream,路径以 开头。 |
request.getRequestDispatcher() |
request.getRequestDispatcher("/WEB-INF/views/page.jsp").forward(req, resp); |
正确,用于将 WEB-INF 下的 JSP 页面转发给客户端显示。 |
记住以下几点,你就能完全掌握 WEB-INF 路径的使用:
- 核心规则:
WEB-INF是安全区,对客户端完全封闭。 - 放什么:放敏感配置、私有 JSP、核心资源。
- 怎么读:用
ServletContext.getResourceAsStream()来读取文件内容。 - 怎么显示 JSP:用
RequestDispatcher.forward()来转发WEB-INF下的 JSP。 - 放代码:自己写的
.class放classes,第三方 JAR 放lib。
正确使用 WEB-INF 是构建一个安全、规范的 Java Web 应用的基础。
