JSP页面空白乱码报错页面显示错误代码 程序员必学的jsp调试排错方法从常见错误到实战解决方案
你好!我是 Agnes,今天我们来聊聊程序员最头疼也最必备的技能——JSP 调试排错。说实话,JSP 虽然现在用得少了,但在很多老项目、政企系统、医院后台里,它依然是主力。遇到页面空白、乱码、错误代码满天飞的时候,真的会让人抓狂。
下面我把从常见错误到实战解决方案,全部给你捋清楚,保证你看完能直接上手。
一、JSP页面空白:最常见也最容易被忽视的问题
1.1 空白页面的三大原因
原因一:JSP语法错误导致编译失败
这是最坑的。你写好JSP,打开浏览器,一片空白,连错误信息都没有。为什么?因为Tomcat在编译JSP时把异常吞掉了,或者你把错误页面配置得不够详细。
让我用一个真实例子说明:
<%-- test.jsp --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>测试页面</title>
</head>
<body>
<h1>Hello World</h1>
<%
// 注意:这里少了一个分号,会导致编译错误
String name = "张三"
out.println("姓名:" + name);
%>
</body>
</html>
打开浏览器,页面空白。你去Tomcat的日志里看:
SEVERE: Servlet.service() for servlet [jsp] in context with path [] threw exception
org.apache.jasper.JasperException: Unable to compile class for JSP:
An error occurred at line: 12 in the jsp file: /test.jsp
Syntax error, insert ";" to complete LocalVariableDeclaration
解决思路:不要只看浏览器,要去Tomcat的日志里找原因。日志路径通常在 tomcat/logs/catalina.out 或者 tomcat/logs/localhost.YYYY-MM-DD.log。
原因二:response被提前commit
<%-- test2.jsp --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>测试2</title></head>
<body>
<h1>前面有内容</h1>
<%
// 问题:在前面输出了内容之后,又调用了sendError
out.println("已经输出");
response.sendError(404, "页面不存在"); // 这行会抛异常
%>
</body>
</html>
原因三:JSP包含文件路径错误
<%-- test3.jsp --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
<%-- 路径错误,导致包含失败 --%>
<%@ include file="/WEB-INF/jsp/header.jsp" %>
<h1>正文</h1>
<%@ include file="/WEB-INF/jsp/footer.jsp" %>
</body>
</html>
1.2 空白页面的调试方法
方法一:开启JSP调试模式
在 web.xml 里加上:
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>3</param-value> <!-- 0-9,数字越大调试信息越详细 -->
</init-param>
<init-param>
<param-name>mappedfile</param-name>
<param-value>false</param-value>
</init-param>
</servlet>
方法二:配置自定义错误页面
<!-- web.xml -->
<error-page>
<error-code>500</error-code>
<location>/error/500.jsp</location>
</error-page>
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/error/500.jsp</location>
</error-page>
然后创建 error/500.jsp:
<%-- error/500.jsp --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %>
<%@ page import="java.io.*, java.util.*" %>
<!DOCTYPE html>
<html>
<head><title>系统错误</title></head>
<body>
<h2>页面出错了!</h2>
<p>错误信息:<%= exception.getMessage() %></p>
<p>错误类型:<%= exception.getClass().getName() %></p>
<h3>堆栈跟踪:</h3>
<pre>
<%
StringWriter sw = new StringWriter();
exception.printStackTrace(new PrintWriter(sw));
out.println(sw.toString());
%>
</pre>
<a href="javascript:history.back()">返回上一页</a>
</body>
</html>
二、JSP乱码问题:从根上解决编码
2.1 乱码的四种场景
场景一:JSP文件本身编码和声明不一致
<%-- 文件保存为GBK,但声明是UTF-8 --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
<h1>中文测试</h1> <!-- 实际显示为乱码 -->
</body>
</html>
解决:统一编码。推荐使用UTF-8。
<%-- 文件保存为UTF-8,声明也是UTF-8 --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
场景二:浏览器编码和JSP声明不一致
<%-- 没有设置charset,浏览器默认用GBK解析 --%>
<%@ page contentType="text/html" language="java" %>
<html>
<body>
<h1>中文测试</h1>
</body>
</html>
解决:
<%-- 明确指定charset为UTF-8 --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
场景三:表单提交中文乱码
<%-- post.jsp --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
<form action="post2.jsp" method="post">
<input type="text" name="name">
<input type="submit" value="提交">
</form>
</body>
</html>
<%-- post2.jsp --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
// 问题:没有设置request.setCharacterEncoding
String name = request.getParameter("name"); // 乱码
out.println("姓名:" + name);
%>
解决:
<%-- post2.jsp --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
// 解决:在获取参数之前设置编码
request.setCharacterEncoding("UTF-8");
String name = request.getParameter("name");
out.println("姓名:" + name);
%>
场景四:数据库读取中文乱码
<%-- db.jsp --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.sql.*" %>
<%
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
// 问题:没有设置characterEncoding
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/test", "root", "123456");
pstmt = conn.prepareStatement("SELECT name FROM user WHERE id=?");
pstmt.setInt(1, 1);
rs = pstmt.executeQuery();
if (rs.next()) {
out.println("姓名:" + rs.getString("name")); // 乱码
}
} finally {
// 关闭资源...
}
%>
解决:
<%-- db.jsp --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.sql.*" %>
<%
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
// 解决:URL里加上characterEncoding
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8&useSSL=false",
"root", "123456");
pstmt = conn.prepareStatement("SELECT name FROM user WHERE id=?");
pstmt.setInt(1, 1);
rs = pstmt.executeQuery();
if (rs.next()) {
out.println("姓名:" + rs.getString("name"));
}
} finally {
if (rs != null) rs.close();
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
}
%>
2.2 乱码的终极解决方案:统一UTF-8
第一步:JSP文件保存为UTF-8
在IDE里设置:File → Encoding → UTF-8
第二步:JSP声明统一UTF-8
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
第三步:web.xml加过滤器
<!-- web.xml -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
第四步:数据库URL加编码
jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8&useUnicode=true&useSSL=false
三、JSP错误代码:从500到404,一文看懂
3.1 常见HTTP状态码
| 状态码 | 含义 | 常见原因 |
|---|---|---|
| 404 | Not Found | JSP路径错误、过滤器拦截、静态资源找不到 |
| 500 | Internal Error | JSP编译错误、NullPointerException、数据库连接失败 |
| 403 | Forbidden | 权限不足、文件夹没有读取权限 |
| 503 | Service Unavailable | Tomcat崩溃、内存溢出、线程池满 |
3.2 500错误的调试方法
方法一:查看Tomcat日志
# Linux/Mac
tail -f /path/to/tomcat/logs/catalina.out
# Windows
type tomcat\logs\catalina.out
方法二:配置详细错误页面
<%-- 500.jsp --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %>
<%@ page import="java.io.*, java.util.*" %>
<!DOCTYPE html>
<html>
<head><title>系统错误</title></head>
<body>
<h2>500 - 内部服务器错误</h2>
<p>错误信息:<%= exception.getMessage() %></p>
<p>错误类型:<%= exception.getClass().getName() %></p>
<h3>堆栈跟踪:</h3>
<pre>
<%
StringWriter sw = new StringWriter();
exception.printStackTrace(new PrintWriter(sw));
out.println(sw.toString());
%>
</pre>
</body>
</html>
方法三:使用try-catch包裹JSP代码
<%-- test.jsp --%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
<h1>测试页面</h1>
<%
try {
// 你的业务代码
String name = request.getParameter("name");
out.println("姓名:" + name);
} catch (Exception e) {
// 错误时显示详细信息
out.println("<h3 style='color:red;'>错误发生!</h3>");
out.println("<p>错误信息:" + e.getMessage() + "</p>");
out.println("<pre>");
e.printStackTrace(out);
out.println("</pre>");
}
%>
</body>
</html>
3.3 404错误的调试方法
方法一:检查JSP路径
webapps/
└── ROOT/
└── jsp/
└── test.jsp
访问方式:http://localhost:8080/jsp/test.jsp
方法二:检查web.xml配置
<!-- 确保没有错误的filter-mapping -->
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*.jsp</url-pattern> <!-- 不要拦截.jsp -->
</filter-mapping>
方法三:检查JSP包含路径
<%-- 正确写法 --%>
<%@ include file="/jsp/header.jsp" %>
<%-- 错误写法(路径多了一个斜杠) --%>
<%@ include file:"//jsp/header.jsp" %>
四、JSP调试工具:让排错效率翻倍
4.1 IDEA调试JSP
第一步:配置Tomcat服务器
- Run → Edit Configurations
- 添加Tomcat Server
- 配置Deployment,添加Artifact
第二步:设置断点
在JSP的<% %>代码块里设置断点,然后Debug启动。
第三步:查看变量值
断点暂停后,可以看到所有变量的值,方便排查问题。
4.2 Firefox/Chrome开发者工具
查看网络请求
- 按F12打开开发者工具
- 切换到Network标签
- 刷新页面,查看所有请求的状态码
- 点击请求,查看Response和Headers
查看控制台错误
- 切换到Console标签
- 查看JavaScript错误
- 查看网络请求失败信息
4.3 Tomcat管理器
访问 http://localhost:8080/manager/html
可以查看:
- 当前部署的应用
- 应用状态
- 会话信息
- 内存使用情况
五、实战案例:一个完整的JSP调试过程
5.1 问题描述
用户反馈:某个页面打开后空白,没有任何错误信息。
5.2 调试步骤
第一步:查看Tomcat日志
tail -f tomcat/logs/catalina.out
发现:
SEVERE: Servlet.service() for servlet [jsp] threw exception
java.lang.NullPointerException
at org.apache.jsp.user.list_jsp._jspService(list_jsp.java:123)
第二步:定位JSP文件
user/list.jsp 第123行附近:
<%-- list.jsp --%>
<%-- 第120行 --%>
<%
UserService userService = (UserService) request.getAttribute("userService");
// 第123行:userService为null,导致NullPointerException
List<User> users = userService.findAll();
%>
第三步:分析问题原因
userService 没有被正确传入request。检查控制器:
// UserController.java
@GetMapping("/list")
public String list(Model model) {
// 问题:没有把userService放入model
// model.addAttribute("userService", userService);
return "user/list";
}
第四步:修复问题
// UserController.java
@GetMapping("/list")
public String list(Model model) {
List<User> users = userService.findAll();
model.addAttribute("users", users);
return "user/list";
}
同时修改JSP:
<%-- list.jsp --%>
<%-- 修改前 --%>
<%
UserService userService = (UserService) request.getAttribute("userService");
List<User> users = userService.findAll();
%>
<%-- 修改后 --%>
<%
List<User> users = (List<User>) request.getAttribute("users");
%>
第五步:验证修复
重启Tomcat,刷新页面,问题解决。
六、JSP调试的最佳实践
6.1 编码规范
- 统一UTF-8:JSP文件、声明、过滤器、数据库URL全部使用UTF-8
- 避免魔法数字:错误码、状态码使用常量
- 添加注释:关键代码添加注释,说明意图
6.2 错误处理
- 自定义错误页面:不要显示默认的Tomcat错误页
- 记录日志:使用SLF4J/Log4j记录异常
- 友好提示:给用户友好的错误提示,不要暴露内部细节
6.3 调试技巧
- 先看日志:遇到问题先查看Tomcat日志
- 再查网络:使用开发者工具查看网络请求
- 后看代码:根据日志定位问题代码
- 最后验证:修复后验证问题是否解决
七、总结
JSP调试虽然有些麻烦,但只要掌握了方法,就能快速定位和解决问题。记住三个关键词:日志、编码、路径。
- 日志:遇到问题先看Tomcat日志
- 编码:统一UTF-8,避免乱码
- 路径:检查JSP路径、包含路径、过滤器路径
希望这篇文章能帮到你!如果还有问题,欢迎留言讨论。我是Agnes,祝你调试顺利!
