4.3 Web 应用描述符 (web.xml) 第四章:Web 应用部署 - 4.3 Web 应用描述符 (web.xml) 详解 在 Tomcat 等 Servlet 容器中, 文件扮演着至关重要的角色。它被称为 Web 应用描述符 (Web Application Deployment Descriptor),是部署在 Servlet 容器中的 Web 应用的核心配置文件。 文件定义了 Web 应用的各种组件、配置和行为,Servlet 容器通过读取和解析 文件来了解如何部署和运行 Web 应用。 在 Servlet 规范的早期版本中, 是配置 Web 应用的唯一方式。随着 Servlet 规范的演进,特别是 Servlet 3.
在 Tomcat 等 Servlet 容器中,web.xml 文件扮演着至关重要的角色。它被称为 Web 应用描述符 (Web Application Deployment Descriptor),是部署在 Servlet 容器中的 Web 应用的核心配置文件。web.xml 文件定义了 Web 应用的各种组件、配置和行为,Servlet 容器通过读取和解析 web.xml 文件来了解如何部署和运行 Web 应用。
在 Servlet 规范的早期版本中,web.xml 是配置 Web 应用的唯一方式。随着 Servlet 规范的演进,特别是 Servlet 3.0 引入了注解 (Annotations) 和约定优于配置 (Convention over Configuration) 的思想,web.xml 的角色发生了一些变化。现代 Web 应用开发中,虽然注解和约定配置逐渐成为主流,但 web.xml 仍然不可或缺,尤其在以下场景中:
覆盖默认配置: web.xml 可以用来覆盖注解或容器的默认配置,提供更精细的控制。
传统应用维护: 许多遗留的 Web 应用仍然依赖 web.xml 进行配置,维护这些应用需要深入理解 web.xml 的作用。
高级配置: 某些高级特性,例如安全配置、JSP 配置、资源引用等,在 web.xml 中配置更加直观和方便。
清晰的配置中心: web.xml 提供了一个集中的地方来查看和管理 Web 应用的配置信息,方便开发人员理解和维护应用。
web.xml 的位置和基本结构web.xml 文件必须位于 Web 应用的 WEB-INF 目录下。WEB-INF 目录是 Web 应用的私有目录,客户端无法直接访问该目录下的任何内容。Servlet 容器会在 Web 应用启动时自动查找并解析 WEB-INF/web.xml 文件。
web.xml 文件遵循 XML 语法,其根元素是 <web-app>。一个基本的 web.xml 文件结构如下所示:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0" metadata-complete="true"> <!-- Web 应用配置元素将在此处定义 --> </web-app>
结构说明:
<?xml version="1.0" encoding="UTF-8"?>: XML 文档声明,指定 XML 版本和编码。
<web-app ...>: 根元素,包含所有 Web 应用的配置信息。
xmlns="http://xmlns.jcp.org/xml/ns/javaee": 默认命名空间声明,指向 Java EE Web 应用描述符的命名空间。
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance": XML Schema Instance 命名空间声明,用于指定 Schema 位置。
xsi:schemaLocation="...": 指定 XML Schema 的位置,用于验证 web.xml 文件的结构和内容是否符合规范。web-app_4_0.xsd 表示使用 Servlet 4.0 规范的 Schema。
version="4.0": 指定 web.xml 文件遵循的 Servlet 规范版本。根据你的 Tomcat 版本和应用需求选择合适的版本。
metadata-complete="true": 这是一个重要的属性,它指示 Servlet 容器是否应该忽略注解配置,只使用 web.xml 文件中的配置。
true: 容器只使用 web.xml 中的配置,忽略注解。这在需要完全控制配置,或者在传统环境中非常有用。
false (默认): 容器会同时扫描注解和 web.xml 文件,合并配置。注解配置会覆盖 web.xml 中相同类型的配置。
版本选择:
version 属性应该与你的 Servlet 规范版本和 Tomcat 版本相匹配。常用的版本包括:
version="2.4": Servlet 2.4 规范,适用于较旧的 Tomcat 版本。
version="2.5": Servlet 2.5 规范,广泛使用,兼容性好。
version="3.0": Servlet 3.0 规范,引入了注解和约定配置,Tomcat 7 及以上版本支持。
version="3.1": Servlet 3.1 规范,Tomcat 8 及以上版本支持。
version="4.0": Servlet 4.0 规范,Tomcat 9 及以上版本支持。
version="5.0": Servlet 5.0 规范,Tomcat 10 及以上版本支持。
选择合适的版本非常重要,它决定了 web.xml 文件中可以使用的元素和属性。
web.xml 的核心元素详解web.xml 文件中包含多个元素,用于配置 Web 应用的不同方面。以下将详细介绍一些最常用的核心元素,并提供代码示例和图表说明。
<display-name> 和 <description><display-name>: 指定 Web 应用的显示名称,通常在 Web 服务器的管理界面或工具中显示。
<description>: 提供 Web 应用的简短描述信息。
示例:
<web-app ...> <display-name>MyWebApp</display-name> <description>This is a sample web application.</description> </web-app>
这两个元素主要是为了提供 Web 应用的元数据信息,方便管理和识别。
<context-param><context-param>: 定义 Web 应用级别的上下文初始化参数。这些参数在整个 Web 应用的生命周期内都可用,并且可以被所有的 Servlet、Filter、Listener 等组件访问。结构:
<context-param> <param-name>参数名</param-name> <param-value>参数值</param-value> <description>参数描述 (可选)</description> </context-param>
示例:
<web-app ...> <context-param> <param-name>app.encoding</param-name> <param-value>UTF-8</param-value> <description>设置应用程序默认编码</description> </context-param> <context-param> <param-name>log4jConfigLocation</param-name> <param-value>/WEB-INF/log4j.properties</param-value> <description>Log4j 配置文件路径</description> </context-param> </web-app>
访问上下文参数:
可以通过 ServletContext 对象来访问上下文参数。在 Servlet、Filter 或 Listener 中,可以通过 getServletContext() 方法获取 ServletContext 对象,然后使用 getInitParameter(String name) 方法获取参数值。
// Servlet 代码示例 public class MyServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext context = getServletContext(); String encoding = context.getInitParameter("app.encoding"); String log4jConfig = context.getInitParameter("log4jConfigLocation"); resp.setContentType("text/html;charset=" + encoding); PrintWriter out = resp.getWriter(); out.println("<html><body>"); out.println("Application Encoding: " + encoding + "<br>"); out.println("Log4j Config Location: " + log4jConfig); out.println("</body></html>"); } }
graph TD 图示 Context 参数:
<listener><listener>: 配置 Servlet 监听器 (Listener)。监听器是实现了特定接口的 Java 类,用于监听 Servlet 容器中发生的特定事件,例如 Web 应用启动和关闭、会话创建和销毁、请求创建和销毁等。结构:
<listener> <listener-class>监听器类全限定名</listener-class> <description>监听器描述 (可选)</description> </listener>
常用的监听器接口:
ServletContextListener: 监听 ServletContext 的生命周期事件,即 Web 应用的启动和关闭。
ServletRequestListener: 监听 ServletRequest 的生命周期事件,即请求的创建和销毁。
HttpSessionListener: 监听 HttpSession 的生命周期事件,即会话的创建和销毁。
ServletContextAttributeListener: 监听 ServletContext 属性的添加、删除和替换事件。
ServletRequestAttributeListener: 监听 ServletRequest 属性的添加、删除和替换事件。
HttpSessionAttributeListener: 监听 HttpSession 属性的添加、删除和替换事件.
示例 (ServletContextListener):
// MyContextListener.java import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; public class MyContextListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { System.out.println("Web Application Started!"); // 在 Web 应用启动时执行的操作,例如初始化资源 } @Override public void contextDestroyed(ServletContextEvent sce) { System.out.println("Web Application Destroyed!"); // 在 Web 应用关闭时执行的操作,例如释放资源 } }
<web-app ...> <listener> <listener-class>com.example.MyContextListener</listener-class> </listener> </web-app>
graph TD 图示 Listener:
<filter> 和 <filter-mapping><filter>: 定义过滤器 (Filter)。过滤器是用于拦截和处理 Servlet 请求和响应的组件。可以用于实现身份验证、授权、日志记录、请求和响应内容转换等功能。
<filter-mapping>: 将过滤器映射到一个或多个 URL 模式或 Servlet 名称。定义过滤器应该拦截哪些请求。
<filter> 结构:
<filter> <filter-name>过滤器名称 (自定义)</filter-name> <filter-class>过滤器类全限定名</filter-class> <init-param> <!-- 可选:过滤器初始化参数 --> <param-name>参数名</param-name> <param-value>参数值</param-value> <description>参数描述 (可选)</description> </init-param> <description>过滤器描述 (可选)</description> </filter>
<filter-mapping> 结构:
<filter-mapping> <filter-name>过滤器名称 (与 <filter> 中的 <filter-name> 对应)</filter-name> <url-pattern>URL 模式</url-pattern> <!-- 或 <servlet-name> Servlet 名称 --> <dispatcher>调度器类型 (可选,默认 REQUEST)</dispatcher> </filter-mapping>
常用的调度器类型 (<dispatcher>):
REQUEST: 默认值,拦截来自客户端的直接请求。
FORWARD: 拦截通过 RequestDispatcher.forward() 转发的请求。
INCLUDE: 拦截通过 RequestDispatcher.include() 包含的请求。
ERROR: 拦截由错误处理机制调度的请求 (配置 <error-page> 时)。
ASYNC: 拦截异步请求。
示例 (字符编码过滤器):
// CharacterEncodingFilter.java import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException; public class CharacterEncodingFilter implements Filter { private String encoding; @Override public void init(FilterConfig filterConfig) throws ServletException { encoding = filterConfig.getInitParameter("encoding"); if (encoding == null) { encoding = "UTF-8"; // 默认编码 } } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; httpRequest.setCharacterEncoding(encoding); chain.doFilter(request, response); // 继续请求处理链 } @Override public void destroy() { // 释放资源 } }
<web-app ...> <filter> <filter-name>encodingFilter</filter-name> <filter-class>com.example.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> <!-- 拦截所有请求 --> </filter-mapping> </web-app>
graph TD 图示 Filter 链:
<servlet> 和 <servlet-mapping><servlet>: 定义 Servlet。Servlet 是用于处理客户端请求并生成响应的 Java 类。
<servlet-mapping>: 将 Servlet 映射到一个或多个 URL 模式。定义哪些 URL 请求由哪个 Servlet 处理。
<servlet> 结构:
<servlet> <servlet-name>Servlet 名称 (自定义)</servlet-name> <servlet-class>Servlet 类全限定名</servlet-class> <init-param> <!-- 可选:Servlet 初始化参数 --> <param-name>参数名</param-name> <param-value>参数值</param-value> <description>参数描述 (可选)</description> </init-param> <load-on-startup>启动时加载顺序 (可选,正整数)</load-on-startup> <description>Servlet 描述 (可选)</description> </servlet>
<servlet-mapping> 结构:
<servlet-mapping> <servlet-name>Servlet 名称 (与 <servlet> 中的 <servlet-name> 对应)</servlet-name> <url-pattern>URL 模式</url-pattern> </servlet-mapping>
<load-on-startup>: 指定 Servlet 在 Web 应用启动时是否立即加载和初始化。
正整数值:指定加载顺序,数值越小,优先级越高,越先加载。
缺省或负数:Servlet 在第一次接收到请求时才加载和初始化 (延迟加载)。
示例 (简单的 HelloServlet):
// HelloServlet.java import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html"); PrintWriter out = resp.getWriter(); out.println("<html><body>"); out.println("<h1>Hello Servlet!</h1>"); out.println("</body></html>"); } }
<web-app ...> <servlet> <servlet-name>helloServlet</servlet-name> <servlet-class>com.example.HelloServlet</servlet-class> <load-on-startup>1</load-on-startup> <!-- 启动时加载 --> </servlet> <servlet-mapping> <servlet-name>helloServlet</servlet-name> <url-pattern>/hello</url-pattern> <!-- URL 模式: /hello --> </servlet-mapping> </web-app>
graph TD 图示 Servlet 请求处理:
<session-config><session-config>: 配置会话 (Session) 管理相关的设置。子元素:
<session-timeout>: 设置会话超时时间,单位为分钟。默认值通常为 30 分钟。
<cookie-config>: 配置会话 Cookie 的属性,例如 Cookie 的名称、路径、域、HttpOnly、Secure 等。
<tracking-mode>: 配置会话跟踪模式。可选值包括 COOKIE, URL, SSL。默认值为 COOKIE。可以配置多个 <tracking-mode>,容器会按顺序尝试使用这些模式。
示例 (配置会话超时时间和 Cookie):
<web-app ...> <session-config> <session-timeout>60</session-timeout> <!-- 会话超时时间 60 分钟 --> <cookie-config> <name>JSESSIONID</name> <!-- Cookie 名称 --> <path>/</path> <!-- Cookie 路径 --> <http-only>true</http-only> <!-- HttpOnly 属性 --> <secure>true</secure> <!-- Secure 属性 (HTTPS only) --> </cookie-config> <tracking-mode>COOKIE</tracking-mode> </session-config> </web-app>
graph TD 图示 Session 管理:
<mime-mapping><mime-mapping>: 配置 MIME 类型映射。将文件扩展名映射到对应的 MIME 类型,以便浏览器正确处理不同类型的文件。结构:
<mime-mapping> <extension>文件扩展名 (例如: html, jpg, pdf)</extension> <mime-type>MIME 类型 (例如: text/html, image/jpeg, application/pdf)</mime-type> </mime-mapping>
示例 (常见的 MIME 类型映射):
<web-app ...> <mime-mapping> <extension>html</extension> <mime-type>text/html</mime-type> </mime-mapping> <mime-mapping> <extension>htm</extension> <mime-type>text/html</mime-type> </mime-mapping> <mime-mapping> <extension>jpg</extension> <mime-type>image/jpeg</mime-type> </mime-mapping> <mime-mapping> <extension>jpeg</extension> <mime-type>image/jpeg</mime-type> </mime-mapping> <mime-mapping> <extension>png</extension> <mime-type>image/png</mime-type> </mime-mapping> <mime-mapping> <extension>pdf</extension> <mime-type>application/pdf</mime-type> </mime-mapping> </web-app>
Servlet 容器通常会提供默认的 MIME 类型映射,你可以在 web.xml 中添加或覆盖这些映射。
<welcome-file-list><welcome-file-list>: 配置欢迎文件列表。当用户访问 Web 应用的根路径或某个目录时,Servlet 容器会按照列表中定义的顺序查找欢迎文件,如果找到则返回第一个找到的文件。结构:
<welcome-file-list> <welcome-file>欢迎文件名 1</welcome-file> <welcome-file>欢迎文件名 2</welcome-file> <welcome-file>...</welcome-file> </welcome-file-list>
示例:
<web-app ...> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> </welcome-file-list> </web-app>
当用户访问 http://localhost:8080/mywebapp/ 时,容器会依次查找 index.html, index.jsp, default.html,如果找到其中任何一个文件,就将该文件的内容作为响应返回给客户端。
<error-page><error-page>: 配置错误页面。当 Web 应用发生错误 (例如 HTTP 状态码错误或 Java 异常) 时,Servlet 容器可以根据配置跳转到指定的错误页面进行处理。结构:
<error-page> <error-code>HTTP 状态码 (例如: 404, 500)</error-code> <!-- 或 <exception-type> 异常类型全限定名 --> <location>错误页面路径 (例如: /error/404.html, /error/exception.jsp)</location> </error-page>
可以配置基于 HTTP 状态码的错误页面,也可以配置基于 Java 异常类型的错误页面。
示例 (配置 404 错误页面和异常处理页面):
<web-app ...> <error-page> <error-code>404</error-code> <location>/error/404.html</location> </error-page> <error-page> <exception-type>java.lang.Exception</exception-type> <location>/error/exception.jsp</location> </error-page> </web-app>
当发生 404 错误时,容器会跳转到 /error/404.html 页面。当发生任何 java.lang.Exception 及其子类的异常时,容器会跳转到 /error/exception.jsp 页面。
<security-constraint>, <login-config>, <security-role>)<security-constraint>: 定义安全约束。指定哪些资源 (URL 模式) 需要进行安全保护,以及允许哪些角色访问这些资源。
<login-config>: 配置登录认证方式和相关设置。例如,可以使用基本认证 (BASIC)、表单认证 (FORM)、摘要认证 (DIGEST)、NTLM 认证等。
<security-role>: 定义 Web 应用中使用的安全角色。
这些元素用于配置 Web 应用的安全策略,实现用户身份验证和授权。安全配置是一个相对复杂的主题,这里只做简单介绍,后续章节可以深入探讨。
示例 (简单的安全约束配置):
<web-app ...> <security-constraint> <web-resource-collection> <web-resource-name>Admin Resources</web-resource-name> <url-pattern>/admin/*</url-pattern> <!-- 需要保护的 URL 模式 --> </web-resource-collection> <auth-constraint> <role-name>admin</role-name> <!-- 允许的角色 --> </auth-constraint> </security-constraint> <login-config> <auth-method>BASIC</auth-method> <!-- 使用基本认证 --> <realm-name>MyWebApp Realm</realm-name> </login-config> <security-role> <role-name>admin</role-name> <!-- 定义角色 admin --> </security-role> </web-app>
这个配置示例保护了 /admin/* 路径下的所有资源,只允许拥有 admin 角色的用户访问,并使用基本认证进行身份验证。
web.xml 的高级特性和现代应用除了上述核心元素,web.xml 还支持一些高级特性,例如:
<jsp-config>: 配置 JSP 相关的设置,例如 JSP 属性组 (property-group)、taglib 指令等。
资源引用 (<resource-env-ref>, <resource-ref>, <ejb-ref>, <message-destination-ref>): 用于配置 JNDI 资源引用,例如数据源、JMS 连接工厂、EJB 组件等。
<locale-encoding-mapping-list>: 配置基于 Locale 的字符编码映射。
Servlet 3.0+ 新增特性:
<absolute-ordering> 和 <ordering>: 用于定义 Filter 和 Servlet 的加载顺序,在注解配置和 web.xml 混合使用时非常有用。