线上与测试环境excel导出列不同
- 在用户有查看年龄权限时,年龄列有列名但无法展示。
线上导出表格为
| 姓名 | 年龄 | 手机号 |
|---|---|---|
| 张三 | 13111112323 | |
| 李四 | 14222223434 |
线下导出表格为
| 姓名 | 年龄 | 手机号 |
|---|---|---|
| 张三 | 18 | 13111112323 |
| 李四 | 20 | 14222223434 |
- 用户无查看年龄权限时,正常屏蔽年龄列
线上导出表格为
| 姓名 | 手机号 |
|---|---|
| 张三 | 13111112323 |
| 李四 | 14222223434 |
线下导出表格为
| 姓名 | 手机号 |
|---|---|
| 张三 | 13111112323 |
| 李四 | 14222223434 |
在无权限时正常屏蔽。
问题定位
代码具体逻辑为先查询500条数据开始写入excel,在写入excel的时候预查询下一批需要写入的数据
public void export(...) { boolean canViewAge = isAuthorizationViewAgeUser(); // 主线程判断 ExcelUtils.exportData(..., userService::queryPage, // 异步线程查询+映射 writer -> { if (!canViewAge) { // 主线程控制列 writer.includeColumnFieldNames(fieldNamesExcluding(..., "age")); } }, 500 ); }根因
权限判断与数据脱敏不在同一线程上下文:
- 表头列控制使用的是主线程的canViewAge(因此保留年龄列)
- 数据查询在异步线程执行,异步线程无法稳定获取SecurityContext
- 导致异步线程判断该用户无权限,将年龄字段置空
触发条件
导出采用分批异步预查询(每批500条)
- 主线程先判断权限 canViewAge
- 开始写当前批Excel
- 同时在线程池异步预查询下一批数据
修复
public void export(...) { canViewAge = isAuthorizationViewAgeUser(); exportData( query, writerCustomizer -> { if (!canViewAge) { writer.includeColumnFieldNames(fieldNamesExcluding(ExportData.class, "age")); } }, (q, pageNum, pageSize) -> queryPage(q, pageNum, pageSize, canViewAge), // 显式透传 500 );