Files
2026-08-13 17:04:23 +08:00

44 lines
6.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 2026-08-13
## 项目:bschclassmanage — UserContext 重构(去掉 authUserWithDept / curRole 参数)
### 目标
从所有 controller 方法签名中移除 `BoaUser authUserWithDept` 与 `UserSysRole curRole` 两个参数,身份改为通过 `UserContext` ThreadLocal 工具类获取。Service 层约定:「显式接收 `UserContext.UserInfo user` 参数」(沿用用户示例 `saveSchSub(UserContext.getCurrentUser(), model)`)。
### 改动清单(已落地)
- `utils/UserContext.java`:新增 `type` 字段(ThreadLocal<Integer> TYPE)+ `setType/getType`,`@Value UserInfo` 加 `Integer type`,`getCurrentUser()` 改 6 参构造,`setUserInfo()`/`clear()` 同步处理 TYPE。原因:`SchsystemController` 原用 `authUserWithDept.getType()` 做超管判断,无对应字段。
- 17 个 `controller/api/*Controller.java`:删除两个参数,调用处 getter 改为 `UserContext.getUserId/getUserName/getType/getRoleId/getSchId`;`getUserInfo()` 返回类型 `BoaUser` → `UserContext.UserInfo`;清理失效 `BoaUser`/`UserSysRole` import,补 `UserContext` import。由临时 Python 脚本批量转换。
- `aspect/ControllerUserContextAspect.java`:populate 逻辑补 `UserContext.setType(...)`;删除一处指向已删解析器的过时注释。
- `interceptor/UserContextInterceptor.java`:修正原 `UserContext.se(...)`(不存在)编译错误,改为 `setUserId/setUserName/setType`。
- `config/DWebMvcConfig.java`:移除已废弃的 `UserSysRoleArgumentResolver` 装配及其 import/@Autowired/addArgumentResolvers。
- 删除 `controller/Handler/UserSysRoleArgumentResolver.java`(仅被 DWebMvcConfig 与 aspect 注释引用)。
### 回归修复
- `SchGradeController`:去掉 `curRole` 后两个 `getGradeSelect(@RequestParam Integer …)` 重载签名撞车(编译错误)。已重命名为 `getGradeSelectBySchsystemId` 与 `getGradeSelectBySchId`,no-arg 版保留 `getGradeSelect`。
### 验证
- 脚本扫描 17 个 controller:**方法签名碰撞 NONE**、**authUserWithDept/curRole 残留 NONE**、**死 import NONE**。
- `pom.xml` 已还原为仅 `spring-boot-maven-plugin`(曾临时加 maven-compiler-plugin annotationProcessorPaths 试图让 mvn 跑 Lombok,无效且非本次范围,已回退)。
### 环境注意(非本次范围)
- 本机 `mvn compile` 因 Lombok annotation processing 未在命令行生效而失败(仅 IntelliJ Lombok 插件可编译),属既有环境限制,未处理。
- 临时文件 `C:\Users\Allen\refactor_usercontext.py` / `build*.log` / `verify_refactor.py` 因安全策略拦截未能自动清理,仍在用户 home 目录,待用户确认后删除。
### 线上 500(code 6 内部服务错误)根因与修复
- 现象:`POST http://192.168.10.166:8086/api/subject/save` 返回 `{"code":6,"msg":"内部服务错误"}`(yunhai `yh-api-std` 的全局异常包装,真实栈在服务器日志)。
- 根因:重构去掉 `BoaUser authUserWithDept` 参数后,`ControllerUserContextAspect` 改为从 **request attribute**(`boaUser/currentUser/...`)取身份,但框架 yunhai 从来不把 BoaUser 放进 request attribute。原 `authUserWithDept` 由框架 `BoaUserArgumentResolver` 解析,其 `resolveArgument` 直接返回 `com.yunhai.platform.auth.BoaUserContext.get()`(一个静态 ThreadLocal<BoaUser>,由框架 `PathBasedAuthInterceptor.preHandle` 每请求 `set`、afterCompletion `clear`)。
- 后果:`UserContext` 的 userId/type 拿不到 → `OtherUtil.setBaseEntityValue` 把 `create_user_id` 写成 null → `schDicSubjectRepository.save` 触发 NOT NULL 约束 → `DataIntegrityViolationException` → code 6。
- 修复:`ControllerUserContextAspect.setUserContext` 改为优先 `BoaUserContext.get()`(try/catch 包住),失败再回退 request attribute;`currentrole`(UserSysRole→schId/roleId)仍由 aspect 从 Header/Query 解析(等价于被删的 `UserSysRoleArgumentResolver`)。新增 import `com.yunhai.platform.auth.BoaUserContext`(yh-auth-core,yh-auth-spring-boot-starter 的非 optional 传递依赖,编译期可达)。
- 验证:`mvn compile` 仍受 Lombok 环境限制跑不起来;正确性通过对 yunhai jar 反编译(javap)确认 `BoaUserContext` 来源与 `PathBasedAuthInterceptor` 的 set 调用。临时解压目录 `C:\Users\Allen\_jarx`、`_jarx2` 为分析用,待清理。
- 若修复后该接口仍 500:下一步排查前端是否发送 `currentrole`(提供 schId);可由 `saveSchSub` 在 `user.getSchId()==null` 时抛明确 `IllegalArgumentException` 来定位。
### @RequestBody 反序列化 500(与身份回归无关,另一独立问题)
- 现象:用户对照实验证明——`saveSchSub()` 无参能跑通(身份/服务正常);`saveSchSub(@Valid @RequestBody SchDicSubject model)` 或去掉 @Valid 后仍 500,断点不进方法体。
- 结论:异常发生在进入方法体之前,即 `@RequestBody` JSON 反序列化阶段(`HttpMessageNotReadableException`)或 Content-Type 不匹配(`HttpMediaTypeNotSupportedException`),二者未被项目异常处理捕获 → 冒泡到 `yh-api-std` 兜底成 `code:6`。
- 排查:实体 `SchDicSubject`(+`BaseEntity`)字段全为标准类型(Integer/String/Boolean/Date),用户所贴 JSON(id,name,schSystemId,enable,source,sort)字段与类型完全匹配,默认 Jackson 不应失败 → 真因是「前端实际请求没带 `Content-Type: application/json`」或「真实请求含实体没有的字段(如 $$hashKey)触发 `FAIL_ON_UNKNOWN_PROPERTIES`」。
- `application.yml` 仅设 `spring.jackson.time-zone/date-format`,无 `fail-on-unknown-properties` → 默认 true。
- 修复(双保险):
1. `entity/SchDicSubject.java` 的 `@JsonIgnoreProperties` 加 `ignoreUnknown = true`(容忍前端多余字段)。
2. `ValidationExceptionHandler` 新增 `@ExceptionHandler(HttpMessageNotReadableException)` 与 `@ExceptionHandler(HttpMediaTypeNotSupportedException)`,把真实原因透出(不再被 code:6 吞掉),返回 `code=ErrorCode.ERROR`、`msg` 含具体原因。
- 验证手段:用 `curl -H "Content-Type: application/json" -d '{...}'` 直连;或部署后看返回 msg 是否直接点出「Content-Type 不被支持」/「JSON 解析失败: Unrecognized field ...」。