杰瑞科技汇

Java自定义错误页面跳转如何实现?

  1. 传统方式:使用 web.xml 配置(Servlet 3.0 及以下版本推荐)
  2. 现代方式:使用 @WebServlet@WebServlet 注解(Servlet 3.0 及以上版本推荐)

这两种方式都是声明式的,意味着你不需要在 Java 代码中写 try-catch 来处理异常然后手动跳转,Web 容器(如 Tomcat)会根据你的配置,在发生特定错误或异常时,自动将请求转发到你指定的错误页面。

Java自定义错误页面跳转如何实现?-图1
(图片来源网络,侵删)

下面我将详细讲解这两种方式,并提供完整的示例。


使用 web.xml 配置(最传统、最通用)

这是最经典的方法,适用于所有支持 Servlet 的容器,它通过在 web.xml 中配置 <error-page> 标签来实现。

核心配置标签

web.xml 中,你需要一个或多个 <error-page> 标签,每个标签可以包含以下子元素:

  • <error-code>:指定一个 HTTP 状态码,404 (Not Found), 500 (Internal Server Error)。
  • <exception-type>:指定一个 Java 异常类的全限定名,java.lang.NullPointerException
  • <location>:指定要跳转到的错误页面的路径。注意:这个路径是相对于 Web 应用根目录(webapp)的

工作原理

当 Servlet 容器捕获到一个异常或返回一个特定的 HTTP 状态码时,它会检查 web.xml 中的 <error-page> 配置,如果找到匹配项,容器会清除响应状态码和头信息,然后使用 RequestDispatcher 将请求转发到 <location> 指定的页面。

Java自定义错误页面跳转如何实现?-图2
(图片来源网络,侵删)

重要提示

  • 跳转是服务器端转发,浏览器的地址栏不会改变。
  • 错误页面只能使用 request 作用域来传递数据,不能使用 sessionapplication,因为 response 已经被提交了。
  • 你可以在错误页面中使用 Servlet API 提供的预定义变量:
    • request.getAttribute("javax.servlet.error.status_code"):获取错误状态码。
    • request.getAttribute("javax.servlet.error.exception_type"):获取异常类型。
    • request.getAttribute("javax.servlet.error.message"):获取错误信息。
    • request.getAttribute("javax.servlet.error.request_uri"):获取发生错误的请求 URI。
    • request.getAttribute("javax.servlet.error.exception"):获取异常对象(如果发生的是异常)。

完整示例(web.xml 方式)

项目结构:

my-web-app/
├── src/
│   └── main/
│       ├── java/
│       │   └── com/
│       │       └── example/
│       │           └── MyServlet.java
│       └── webapp/
│           ├── WEB-INF/
│           │   └── web.xml
│           ├── error/
│           │   ├── 404.html
│           │   └── 500.html
│           └── index.html

配置 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">
    <!-- 配置 404 错误 -->
    <error-page>
        <error-code>404</error-code>
        <location>/error/404.html</location>
    </error-page>
    <!-- 配置 500 错误 -->
    <error-page>
        <error-code>500</error-code>
        <location>/error/500.html</location>
    </error-page>
    <!-- 配置特定异常 -->
    <error-page>
        <exception-type>java.lang.ArithmeticException</exception-type>
        <location>/error/500.html</location>
    </error-page>
    <!-- 可以配置一个默认的错误页面,处理所有未明确配置的错误 -->
    <!-- <error-page>
        <location>/error/generic.html</location>
    </error-page> -->
</web-app>

创建错误页面

Java自定义错误页面跳转如何实现?-图3
(图片来源网络,侵删)

error/404.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">404 - 页面未找到</title>
    <style>
        body { font-family: Arial, sans-serif; text-align: center; padding-top: 50px; }
        h1 { color: #d9534f; }
    </style>
</head>
<body>
    <h1>404 - 抱歉,您访问的页面不存在!</h1>
    <p>错误状态码: <span id="status-code"></span></p>
    <p>请求路径: <span id="request-uri"></span></p>
    <script>
        // 使用 JavaScript 从 request 属性中获取值并显示
        document.getElementById("status-code").innerText = "<%= request.getAttribute("javax.servlet.error.status_code") %>";
        document.getElementById("request-uri").innerText = "<%= request.getAttribute("javax.servlet.error.request_uri") %>";
    </script>
</body>
</html>

error/500.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">500 - 服务器内部错误</title>
    <style>
        body { font-family: Arial, sans-serif; text-align: center; padding-top: 50px; }
        h1 { color: #d9534f; }
    </style>
</head>
<body>
    <h1>500 - 抱歉,服务器出错了!</h1>
    <p>错误信息: <span id="error-message"></span></p>
    <p>异常类型: <span id="exception-type"></span></p>
    <script>
        document.getElementById("error-message").innerText = "<%= request.getAttribute("javax.servlet.error.message") %>";
        document.getElementById("exception-type").innerText = "<%= request.getAttribute("javax.servlet.error.exception_type") %>";
    </script>
</body>
</html>

创建一个会触发错误的 Servlet

src/main/java/com/example/MyServlet.java

package com.example;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/causeError") // 使用注解映射,与 web.xml 无关
public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 模拟一个算术异常,会触发 500 错误页面
        int a = 10;
        int b = 0;
        int c = a / b; // 这里会抛出 ArithmeticException
    }
}

使用注解(Servlet 3.0+)

从 Servlet 3.0 开始,引入了 @WebServlet 等注解,使得配置更加简洁。错误页面的配置仍然需要 web.xml,目前没有纯注解的方式来配置全局错误页面。

最佳实践是:

  • Servlet 映射:使用 @WebServlet
  • 错误页面配置:仍然使用 web.xml

如果你完全不想使用 web.xml,那么你就失去了声明式错误页面跳转的能力,必须在代码中手动处理。

完整示例(注解 + web.xml 方式)

这种方式和方式一几乎完全一样,只是 Servlet 的定义方式改为了注解。

项目结构: (与方式一相同)

web.xml 配置 (与方式一完全相同)

<!-- ... 与上面方式一的 web.xml 内容相同 ... -->

错误页面 (与方式一完全相同)

error/404.htmlerror/500.html 的内容与上面相同。

创建 Servlet (使用注解)

src/main/java/com/example/MyServlet.java

package com.example;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
// 使用 @WebServlet 注解来映射 URL
@WebServlet("/causeError")
public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 访问 /causeError 时,重定向到一个不存在的页面,触发 404
        resp.sendRedirect("/this-page-does-not-exist.html");
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 模拟一个算术异常,会触发 500 错误页面
        int a = 10;
        int b = 0;
        int c = a / b;
    }
}

总结与对比

特性 web.xml 配置 注解 (@WebServlet)
Servlet 映射 使用 <servlet><servlet-mapping> 使用 @WebServlet 注解,更简洁
错误页面配置 必须使用 <error-page> 仍然必须使用 <error-page>
适用版本 所有 Servlet 版本 Servlet 3.0+
优点 传统、稳定、配置集中 Servlet 映射更简洁,无需修改 web.xml
缺点 配置繁琐,XML 文件可读性有时不如注解 错误页面配置仍依赖 web.xml

最终建议:

对于现代项目(Servlet 3.0+),推荐采用 “注解 + web.xml 的混合模式。

  • 使用 @WebServlet 等注解来定义 Servlet、Filter、Listener,因为这些配置是应用特有的。
  • 仍然在 web.xml 中配置 <error-page>,因为这是全局的、与部署描述相关的配置,且目前没有更好的替代方案,这既保持了代码的简洁性,又能实现强大的全局错误处理功能。
分享:
扫描分享到社交APP
上一篇
下一篇