JSP页面直接输出实体对象空属性引发页面500报错实战案例
一、问题背景
传统Java Web项目开发中,大量业务页面使用JSP+EL表达式渲染数据。开发人员常直接通过${对象.属性}输出实体字段,忽略属性为null、实体对象本身为空的场景。
当实体对象为null,或目标属性未赋值时,EL表达式访问属性会触发NullPointerException,直接导致页面抛出500服务器异常,页面空白无法展示,线上出现用户访问页面报错问题。该问题无编译提示,仅运行时暴露,测试容易遗漏边界场景。
二、错误代码演示(坑点复现)
1. 后端Servlet赋值代码
java
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("/userInfo")
public class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 模拟查询无用户数据,对象直接赋值null
User user = null;
request.setAttribute("user", user);
request.getRequestDispatcher("user.jsp").forward(request, response);
}
}
// 用户实体类
class User {
private String username;
private String phone;
// getter、setter省略
public String getUsername() { return username; }
public String getPhone() { return phone; }
}
2. 存在BUG的JSP页面 user.jsp
jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>用户信息</title>
</head>
<body>
<%-- 未做空值判断,直接访问对象属性 --%>
<p>用户名:${user.username}</p>
<p>手机号:${user.phone}</p>
</body>
</html>
运行异常现象
访问/userInfo后页面返回500错误,控制台抛出空指针异常:
java.lang.NullPointerException
at org.apache.el.parser.AstValue.getValue(AstValue.java:167)
原理:user对象为null,执行user.username时EL底层调用getter方法,空对象调用方法直接触发空指针。
同理,若user对象存在,但phone属性为null,单纯输出不会报错,但如果后续拼接、逻辑判断仍会衍生展示异常。
三、主流修复方案
方案1:EL内置empty关键字判空(推荐轻量方案)
使用empty判断对象是否为空,为空展示默认占位文本,避免访问空对象属性。
jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
<c:if test="${empty user}">
<p>暂无用户信息</p>
</c:if>
<c:if test="${not empty user}">
<p>用户名:${user.username}</p>
<p>手机号:${empty user.phone ? '未填写' : user.phone}</p>
</c:if>
</body>
</html>
需引入核心标签库:
jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
方案2:后端赋默认对象兜底
后端查询无数据时,不返回null,新建空实体对象,避免页面空对象访问:
java
User user = userService.getById(1);
// 兜底处理
if(user == null){
user = new User();
user.setUsername("暂无数据");
user.setPhone("无");
}
request.setAttribute("user", user);
方案3:JSP脚本原生判空(不推荐,仅老旧项目兼容)
jsp
<%
User user = (User)request.getAttribute("user");
String name = user == null ? "暂无用户" : user.getUsername();
%>
<p>用户名:<%=name%></p>
缺点:混合Java脚本与HTML,破坏页面分层,不利于维护。
四、项目开发规范避坑总结
- JSP使用EL渲染对象前,必须通过
empty判断对象非空,再读取内部属性; - 字符串属性输出时使用三元表达式设置默认值,避免页面空白;
- 后端查询数据接口统一兜底,无数据时返回空实体而非null;
- 项目统一引入JSTL标签库,禁止大量内嵌Java脚本;
- 单元测试覆盖数据为空、属性为null边界场景,提前拦截页面500异常。
五、线上风险说明
该异常会直接阻断页面渲染,用户无法查看页面内容,严重影响使用体验;批量列表场景下,单条数据对象为空会导致整个页面崩溃,而非单条数据隐藏,故障影响范围大。
海量精选技术文档和实战案例持续更新,敬请关注【风骏时光少年】