你提供的这段 Java 代码是一个典型的 Struts2 框架中的 Action 方法,用于跳转到主页面并准备一些数据(如通知公告、下载资料、待办事项等)传递给前端页面。然而你说“**页面不显示数据只有空白行**”,这说明后端可能没有正确地将数据传入页面,或者前端未正确渲染。
---
### ✅ 问题分析
我们来逐步排查可能导致 **页面为空白、无数据显示** 的原因:
---
#### 🔍 1. 数据查询是否成功?
```java
String sql = "select a.fsid as fsid,a.ftype as ftype,b.fendtime as ftime,fistop as fistop,fisbold as fisbold,a.ftitle as ftitle from tongzhi a,t_sys_flow_use b where a.fflowuseid=b.fsid and b.fstate='"+FlowDao.OVER+"' order by b.fendtime desc limit 5";
ActionContext.getContext().put("tongzhis", getSessionFactory().getCurrentSession().createSQLQuery(sql).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP) .list());
```
- 使用了原生 SQL 查询,并通过 `ALIAS_TO_ENTITY_MAP` 转换为 `Map<String, Object>` 列表。
- 存在 **SQL 注入风险**:`b.fstate='"+FlowDao.OVER+"'` 是拼接字符串,应使用参数化查询。
- 更重要的是:如果查询结果为空或异常,`tongzhis` 就是空列表或 `null`,但不会报错,前端就看不到内容。
✅ **建议改写为参数化查询**:
```java
String sql = "SELECT a.fsid AS fsid, a.ftype AS ftype, b.fendtime AS ftime, a.fistop AS fistop, a.fisbold AS fisbold, a.ftitle AS ftitle " +
"FROM tongzhi a, t_sys_flow_use b " +
"WHERE a.fflowuseid = b.fsid AND b.fstate = :fstate " +
"ORDER BY b.fendtime DESC LIMIT 5";
List<Map<String, Object>> tongzhis = getSessionFactory().getCurrentSession()
.createSQLQuery(sql)
.setParameter("fstate", FlowDao.OVER)
.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP)
.list();
ActionContext.getContext().put("tongzhis", tongzhis);
```
> ⚠️ 如果不加 `.list()` 或查询出错,会返回 `null`,导致前端拿不到数据。
---
#### 🔍 2. `xiazais` 数据是否正常?
```java
ActionContext.getContext().put("xiazais", this.findAll(Xiazai.class, "fistop asc,ftime desc",5));
```
- 假设 `findAll(Class<T>, String orderBy, int maxResults)` 是自定义方法。
- 需确认:
- `Xiazai` 类是否存在?
- 是否有数据满足条件?
- 排序字段名是否正确?比如 `fistop`, `ftime` 是否真实存在?
- 返回值是否真的有数据?可以打印调试:
```java
List<Xiazai> xiazais = this.findAll(Xiazai.class, "fistop asc,ftime desc", 5);
System.out.println("Xiazai count: " + xiazais.size()); // 调试输出
ActionContext.getContext().put("xiazais", xiazais);
```
---
#### 🔍 3. `ActionContext.getContext().put(...)` 是否有效?
Struts2 中,`ActionContext.getContext().put(key, value)` 相当于把数据放入 **ValueStack** 和 **OGNL Context**,供 JSP 页面使用 `${tongzhis}` 或 `<s:iterator value="tongzhis">` 访问。
但如果:
- 页面使用的是 Thymeleaf / Freemarker 而不是 JSP;
- 或者用了 ModelDriven 而没暴露属性;
- 或 Struts 配置禁用了某些访问方式;
会导致数据无法读取。
✅ 确保你在 JSP 页面中这样访问:
```jsp
<s:iterator value="tongzhis" var="item">
<p>${item.fsid}: ${item.ftitle}</p>
</s:iterator>
```
而不是试图用 EL 表达式直接访问 `requestScope.tongzhis`。
---
#### 🔍 4. `executeViewMethod(viewData)` 干了什么?
```java
executeViewMethod(viewData);
```
这个方法看起来是你自己封装的逻辑,可能是根据角色动态执行某些“统计”或“待办任务”的查询,并把结果放到 `ActionContext`。
⚠️ **关键点:这些数据是不是也放进 `ActionContext` 了?**
例如:`queryYlqxWaitDo` 方法内部有没有做类似:
```java
ActionContext.getContext().put("ylqxWaitDoList", list);
```
如果没有放进去,即使执行了方法,前端也无法获取数据。
👉 所以你需要检查 `executeViewMethod()` 内部实现,确保它确实把各种待办数据 put 到 context。
---
#### 🔍 5. 前端页面是否有错误?HTML 结构问题?
即使后台传了数据,前端也可能因为以下原因显示为空白行:
- `<s:iterator>` 标签拼写错误;
- OGNL 表达式写错,如 `${tongzhis[0].ftitle}` 访问越界;
- CSS 隐藏了元素(如 `display:none`);
- JavaScript 报错中断渲染;
- 页面根本没写迭代逻辑!
✅ 示例正确的 JSP 显示代码:
```jsp
<!-- 显示通知 -->
<h3>通知公告</h3>
<s:if test="tongzhis != null && !tongzhis.isEmpty()">
<s:iterator value="tongzhis" var="tz">
<div style="<s:property value='#tz.fisbold == 1 ? \"font-weight:bold\" : \"\"'/>">
<s:property value="#tz.ftitle"/>
(<s:date name="#tz.ftime" format="yyyy-MM-dd HH:mm"/>)
</div>
</s:iterator>
</s:if>
<s:else>
暂无通知
</s:else>
```
---
#### 🔍 6. 异常被捕获但未打印?
当前方法声明抛出 `Exception`,但如果中间发生异常(如 SQL 错误、类转换异常),而你没日志记录,则可能静默失败。
✅ 添加 try-catch 日志:
```java
public String toMainPage() throws Exception {
try {
// 你的原有逻辑
} catch (Exception e) {
e.printStackTrace();
log.error("toMainPage error", e); // 使用 log4j 或 slf4j
throw e;
}
}
```
---
### ✅ 解决方案总结与修复建议
下面是优化后的完整代码示例(含修复项):
```java
public String toMainPage() throws Exception {
try {
// 1. 查询通知公告(参数化防止注入)
String sql = "SELECT a.fsid AS fsid, a.ftype AS ftype, b.fendtime AS ftime, " +
"a.fistop AS fistop, a.fisbold AS fisbold, a.ftitle AS ftitle " +
"FROM tongzhi a JOIN t_sys_flow_use b ON a.fflowuseid = b.fsid " +
"WHERE b.fstate = :fstate " +
"ORDER BY b.fendtime DESC LIMIT 5";
List<Map<String, Object>> tongzhis = getSessionFactory().getCurrentSession()
.createSQLQuery(sql)
.setParameter("fstate", FlowDao.OVER)
.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP)
.list();
System.out.println("Tongzhi size: " + tongzhis.size()); // 调试
ActionContext.getContext().put("tongzhis", tongzhis);
// 2. 查询资料下载
List<Xiazai> xiazais = this.findAll(Xiazai.class, "fistop asc, ftime desc", 5);
System.out.println("Xiazai size: " + xiazais.size());
ActionContext.getContext().put("xiazais", xiazais);
// 3. 获取用户部门和角色
TSysDepartment department = this.findBySid(TSysDepartment.class, Tools.getCurrentUser().getFrybm());
List<String> roleNames = this.getPeoRole(Tools.getCurrentUser().getFsid());
CustomList<String> viewData = new CustomList<>();
if (Tools.getCurrentUser().getFsid().equals(AppConstants.SUPER_ADMIN_USER)) {
viewData.add("adminPageQuery", "ndsjtj", "jycqyjtj_all");
} else if ("院领导".equals(department.getFdepmc())) {
viewData.add("queryYlqxWaitDo", "ndsjtj");
if (roleNames.contains("授权签字人")) viewData.add("jycqyjtj_all");
} else if ("业务室".equals(department.getFdepmc()) && roleNames.contains("科室主任")) {
viewData.add("queryYlqxWaitDo", "chaoqiyujing_depart", "ndsjtj");
} else if (StringUtils.equalsAny(department.getFdepmc(), "业务室", "质量科") && !roleNames.contains("科室主任")) {
viewData.add("queryYlqxWaitDo", "chaoqiyujing_person");
} else if ("是".equals(department.getFisjyjg())) {
viewData.add("queryYlqxWaitDo", "jycqyjtj_person");
if (roleNames.contains("科室主任")) viewData.add("jycqyjtj_depart");
}
viewData.add("queryJJSWaitDo");
viewData.add("queryFuzhuWaitDo");
executeViewMethod(viewData); // 确保该方法内 put 了对应的数据
return "main";
} catch (Exception e) {
e.printStackTrace();
log.error("Error in toMainPage", e);
throw e;
}
}
```
---
### ✅ 排查清单(你可以逐条验证)
| 检查项 | 是否完成 |
|------|--------|
| 后台打印 `tongzhis.size()` 和 `xiazais.size()` | ✅ |
| SQL 改为参数化查询 | ✅ |
| `executeViewMethod` 是否真正向 context 放数据 | ✅ |
| JSP 页面是否用 `<s:iterator value="tongzhis">` 正确遍历 | ✅ |
| 浏览器开发者工具查看响应 HTML 是否包含数据 | ✅ |
| 控制台/日志有无异常输出 | ✅ |
---
### ❓常见相关问题