JSP 调试
JSP 报错在哪看、翻译后的源码、断点与常见错误对照。
Key PointsJSP 的编译错误只写日志不显示在浏览器上,页面空白时第一件事就是看 catalina.out。
页面空白怎么办
- 看
logs/catalina.out或logs/localhost.<日期>.log - 找
Unable to compile class for JSP附近的行号 - 去
work/Catalina/localhost/<app>/org/apache/jsp/看翻译出来的.java - 对照
.java的行号定位到 JSP 的原始行
Text
work/Catalina/localhost/myapp/org/apache/jsp/
├── index_jsp.java ← 你的 index.jsp 翻译结果
├── index_jsp.class
└── user/
└── list_jsp.java ← user/list.jspThe translated .java is the code that actually runs. When wondering "why is this null" or "why is the order wrong", reading it beats adding more printlns.
常见错误对照
| Message | Cause |
|---|---|
| Unable to compile class for JSP | Java 语法错、缺 import、括号不配对 |
| cannot find symbol: exception | 页面没标 isErrorPage="true" |
| The absolute uri ... cannot be resolved | TLD 不在 WEB-INF 或 URI 写错 |
| getOutputStream() has already been called | 同时用了 out 和 getOutputStream |
| Response has already been committed | 输出后才 sendRedirect / sendError |
| NullPointerException | <%= %> 里对 null 调方法 |
在页面上打印调试信息
JSP
<%-- 开发期临时打开:把 request 里的属性全列出来 --%>
<%@ page import="java.util.*" %>
<%
Enumeration<String> names = request.getAttributeNames();
while (names.hasMoreElements()) {
String n = names.nextElement();
out.println("<!-- attr: " + n + " = " + request.getAttribute(n) + " -->");
}
%>Wrapping in HTML comments keeps the page unchanged while remaining visible in page source. Remove it before release — the request may hold sensitive data.
断点调试
- JSP 里下断点 —— IDE 会映射到
_jspService的对应行 - Java 类里下断点 —— 需要以 debug 模式启动容器
- 改 JSP 后刷新即可 —— 容器检测到文件时间戳变化会重新翻译
If a JSP change does not take effect, delete the matching directory under
work/ and reload. Timestamp resolution (especially on network filesystems) can hide the change and the old compiled class keeps serving — the classic "but I did change it".日志
JSP
<%
application.log("用户 " + session.getAttribute("uid") + " 访问了订单页");
try {
// 业务
} catch (Exception e) {
application.log("订单查询失败", e); // 带堆栈
response.sendError(500);
return;
}
%>application.log writes to the container's app log with a timestamp and source. System.out.println only lands in catalina.out with no level and becomes useless at volume.
页面空白怎么办
- 看
logs/catalina.out或logs/localhost.<日期>.log - 找
Unable to compile class for JSP附近的行号 - 去
work/Catalina/localhost/<app>/org/apache/jsp/看翻译出来的.java - 对照
.java的行号定位到 JSP 的原始行
Text
work/Catalina/localhost/myapp/org/apache/jsp/
├── index_jsp.java ← 你的 index.jsp 翻译结果
├── index_jsp.class
└── user/
└── list_jsp.java ← user/list.jsp翻译后的 .java 就是最终执行的代码。怀疑「为什么这个变量是 null」「为什么输出顺序不对」时,直接读它比反复加 println 有效得多。
常见错误对照
| 报错 | 原因 |
|---|---|
| JSP 编译失败 | Java 语法错、缺 import、括号不配对 |
| 找不到 exception | 页面没标 isErrorPage="true" |
| 标签库解析失败 | TLD 不在 WEB-INF 或 URI 写错 |
| 输出流冲突 | 同时用了 out 和 getOutputStream |
| 响应已提交 | 输出后才 sendRedirect / sendError |
| 空指针 | <%= %> 里对 null 调方法 |
在页面上打印调试信息
JSP
<%-- 开发期临时打开:把 request 里的属性全列出来 --%>
<%@ page import="java.util.*" %>
<%
Enumeration<String> names = request.getAttributeNames();
while (names.hasMoreElements()) {
String n = names.nextElement();
out.println("<!-- attr: " + n + " = " + request.getAttribute(n) + " -->");
}
%>用 HTML 注释包起来,不影响页面外观,查看源码就能看到。上线前记得删掉——request 里可能有用户敏感数据。
断点调试
- JSP 里下断点 —— IDE 会映射到
_jspService的对应行 - Java 类里下断点 —— 需要以 debug 模式启动容器
- 改 JSP 后刷新即可 —— 容器检测到文件时间戳变化会重新翻译
改了 JSP 却没生效,先删掉
work/ 下对应的目录再刷新。容器有时因为时间戳精度(尤其网络文件系统)判断不出文件已变,继续用旧的编译结果——「我明明改了」的经典原因。日志
JSP
<%
application.log("用户 " + session.getAttribute("uid") + " 访问了订单页");
try {
// 业务
} catch (Exception e) {
application.log("订单查询失败", e); // 带堆栈
response.sendError(500);
return;
}
%>application.log 写到容器的应用日志,带时间戳和来源。System.out.println 只进 catalina.out 且没有级别——量一大就完全没法用。