# 出国行程变更申请 - VO字段缺失修复 ## 🔴 MyBatis映射错误 ### 错误信息 ``` Error querying database. Cause: org.apache.ibatis.reflection.ReflectionException: Could not set property 'createDept' of 'class org.dromara.rs.domain.vo.RsOverseasItineraryChangeVo' with value '103' Cause: org.apache.ibatis.reflection.ReflectionException: There is no setter for property named 'createDept' in 'class org.dromara.rs.domain.vo.RsOverseasItineraryChangeVo' ``` ### 错误原因 **SQL查询返回了 `create_dept` 字段,但VO类中没有对应的属性!** ```sql -- SQL查询中包含 create_dept 字段 SELECT c.change_id, c.record_id, ... c.create_dept, -- ❌ 查询返回了这个字段 c.create_by, c.create_time, ... FROM rs_overseas_itinerary_change c ``` ```java // RsOverseasItineraryChangeVo.java (修复前) @Data public class RsOverseasItineraryChangeVo { private Integer deleted; // ❌ 缺少 createDept 字段! private Long createBy; // MyBatis找不到createDept的setter,抛出异常 private Date createTime; ... } ``` --- ## ✅ 修复方案 ### 添加缺失的 createDept 字段 **修复文件**: `backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/domain/vo/RsOverseasItineraryChangeVo.java` **修复代码**: ```java /** * 删除标志(0代表存在 1代表删除) */ private Integer deleted; /** * 创建部门 ✅ 新增字段 */ private Long createDept; /** * 创建者 */ private Long createBy; /** * 创建时间 */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date createTime; /** * 更新者 */ private Long updateBy; /** * 更新时间 */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date updateTime; ``` --- ## 📋 VO类基础字段统一规范 ### 🚨 强制性要求(来自项目规范) **所有VO类必须包含以下基础字段**: ```java /** * 创建部门 */ private Long createDept; /** * 创建者 */ private Long createBy; /** * 创建时间 */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date createTime; /** * 更新者 */ private Long updateBy; /** * 更新时间 */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date updateTime; ``` ### 为什么必须包含? #### 场景1:MyBatis-Plus 自动查询 ```java // 使用 selectList 等方法 List list = mapper.selectVoList(wrapper); ``` - ✅ MyBatis-Plus 只查询VO类中定义的字段 - ✅ 如果VO中没有 `createDept`,查询SQL不会包含这个字段 - ✅ 不会报错 #### 场景2:自定义SQL查询(本次错误场景) ```xml ``` - ❌ SQL返回了 `create_dept` 字段 - ❌ 但VO类中没有 `createDept` 属性 - ❌ MyBatis尝试调用 `setCreateDept()` 方法 - ❌ 找不到setter方法,抛出 `ReflectionException` - ❌ 导致整个查询失败,返回500错误 ### 对比示例 #### ❌ 错误的VO类(缺少基础字段) ```java @Data public class RsOverseasItineraryChangeVo { private Long changeId; private Long recordId; private String applicantName; // ... 业务字段 // ❌ 缺少基础字段! // private Long createDept; // private Long createBy; // private Date createTime; // private Long updateBy; // private Date updateTime; } ``` **结果**: - 使用MyBatis-Plus自动查询 → ✅ 正常 - 使用自定义SQL查询(包含基础字段) → ❌ 500错误 #### ✅ 正确的VO类(包含基础字段) ```java @Data public class RsOverseasItineraryChangeVo { private Long changeId; private Long recordId; private String applicantName; // ... 业务字段 // ✅ 包含完整的基础字段 private Long createDept; private Long createBy; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date createTime; private Long updateBy; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date updateTime; } ``` **结果**: - 使用MyBatis-Plus自动查询 → ✅ 正常 - 使用自定义SQL查询(包含基础字段) → ✅ 正常 --- ## 🔧 修复步骤 ### 1. 修改VO类 ✅ **已完成** - 添加 `createDept` 字段 ### 2. 重新编译后端 **方法1:使用Maven命令(推荐)** ```bash cd /Users/weizzzz/Documents/Cursor/0828CURSOR/all-project/backend mvn clean compile -DskipTests ``` **方法2:重启后端服务** ```bash cd /Users/weizzzz/Documents/Cursor/0828CURSOR/all-project/backend mvn spring-boot:run ``` **方法3:使用IDE重新编译** - IDEA: Build → Rebuild Project - Eclipse: Project → Clean ### 3. 验证修复 **测试步骤**: 1. 重启后端服务 2. 刷新前端页面 3. 访问"出国行程变更管理" 4. 验证列表是否正常显示 **预期结果**: - ✅ 列表正常加载 - ✅ 没有500错误 - ✅ 能看到所有变更申请数据 --- ## 📊 问题根源分析 ### 时间线 ``` 1. 数据库设计 → 表包含 create_dept 字段 ✅ 2. Entity类设计 → 继承BaseEntity,包含基础字段 ✅ 3. Mapper.xml设计 → SQL查询包含 create_dept ✅ 4. VO类设计 → ❌ 忘记添加 create_dept 字段 5. 运行时错误 → MyBatis无法映射字段 → 500错误 ``` ### 为什么之前没发现? #### 原因1:提交功能先开发 ```java // 提交API - 使用Entity类,不是VO类 public R add(@RequestBody RsOverseasItineraryChangeBo bo) { return toAjax(rsOverseasItineraryChangeService.insertByBo(bo)); } ``` - ✅ Entity类继承 `BaseEntity`,自动包含所有基础字段 - ✅ 提交功能正常工作 #### 原因2:列表查询后开发 ```java // 列表API - 使用VO类 public TableDataInfo list( RsOverseasItineraryChangeBo bo, PageQuery pageQuery ) { return rsOverseasItineraryChangeService.queryPageList(bo, pageQuery); } ``` - ❌ VO类缺少 `createDept` 字段 - ❌ 第一次查询列表时才发现问题 #### 原因3:测试不充分 - ✅ 测试了提交功能 → 通过 - ❌ 没有测试列表查询 → 发现问题 --- ## 🎯 最佳实践建议 ### 1. VO类设计模板 **所有VO类都应该使用这个模板**: ```java package org.dromara.rs.domain.vo; import lombok.Data; import com.fasterxml.jackson.annotation.JsonFormat; import java.io.Serializable; import java.util.Date; /** * XXX视图对象 * * @author xxx * @date xxxx-xx-xx */ @Data public class XxxVo implements Serializable { private static final long serialVersionUID = 1L; // ======================================== // 业务字段 // ======================================== /** * 主键ID */ private Long id; /** * 业务字段1 */ private String field1; // ... 其他业务字段 // ======================================== // 基础字段(必须包含) // ======================================== /** * 租户编号 */ private String tenantId; /** * 删除标志(0代表存在 1代表删除) */ private Integer deleted; /** * 创建部门 */ private Long createDept; /** * 创建者 */ private Long createBy; /** * 创建时间 */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date createTime; /** * 更新者 */ private Long updateBy; /** * 更新时间 */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date updateTime; } ``` ### 2. 检查清单 **创建新VO类时,必须检查**: - [ ] 包含业务字段 - [ ] 包含 `tenantId` - [ ] 包含 `deleted` - [ ] 包含 `createDept` ⭐ - [ ] 包含 `createBy` ⭐ - [ ] 包含 `createTime` ⭐(带 `@JsonFormat`) - [ ] 包含 `updateBy` ⭐ - [ ] 包含 `updateTime` ⭐(带 `@JsonFormat`) ### 3. 测试建议 **完整的测试流程**: ``` 1. 测试新增功能 2. 测试列表查询 ⭐ 验证VO字段映射 3. 测试详情查询 ⭐ 验证VO字段映射 4. 测试修改功能 5. 测试删除功能 ``` **关键点**: 先测试查询,确保VO字段定义正确! --- ## 📚 相关规范 ### 项目规范文档 **位置**: `.cursor/cursorrules-backend.md` **章节**: "VO类基础字段规范(强制性)" **核心内容**: ```markdown ### 🔴 VO类基础字段统一规范(新增 2025-07-01) **⚠️ 超级重要:所有VO类必须包含统一的基础字段!** **背景问题**: - MyBatis-Plus自动查询:不包含继承字段 - 自定义SQL查询:明确包含字段,VO类必须有对应属性 - 导致运行时字段缺失错误:`Could not set property 'createBy'` **统一解决方案**: 所有VO类必须包含的基础字段: - Long createDept - Long createBy - Date createTime (含JSON格式化) - Long updateBy - Date updateTime (含JSON格式化) ``` --- ## 🎉 修复总结 ### ✅ 问题识别 - **错误类型**: MyBatis字段映射错误 - **错误原因**: VO类缺少 `createDept` 字段 - **影响范围**: 所有列表查询API ### ✅ 修复方案 - **修改文件**: `RsOverseasItineraryChangeVo.java` - **修改内容**: 添加 `createDept` 字段 - **修改行数**: 1 个字段,6 行代码 ### ✅ 验证步骤 1. ✅ 代码修改完成 2. ⏳ 需要重新编译后端 3. ⏳ 需要重启后端服务 4. ⏳ 需要测试验证 --- ## 🚀 下一步操作 ### 1. 重新编译后端(必须) ```bash cd /Users/weizzzz/Documents/Cursor/0828CURSOR/all-project/backend mvn clean compile -DskipTests ``` ### 2. 重启后端服务(必须) ```bash # 停止当前服务(Ctrl+C) # 然后重新启动 mvn spring-boot:run ``` ### 3. 刷新前端页面(必须) ```bash # 强制刷新浏览器 Ctrl+Shift+R (Windows) Cmd+Shift+R (Mac) ``` ### 4. 测试验证(必须) 访问: http://localhost/rs/overseas/itinerary-change **预期结果**: - ✅ 列表正常加载 - ✅ 没有500错误 - ✅ 能看到所有变更申请数据 - ✅ 可以正常提交新申请 --- ## 📞 相关文档 | 文档名称 | 说明 | |---------|------| | `行程变更申请-修复总结.md` | 所有问题修复汇总 | | `行程变更申请-recordId修复说明.md` | 必填字段修复 | | `行程变更申请-列表显示问题修复.md` | 分页问题修复 | | `行程变更申请-VO字段缺失修复.md` | 本文档(VO字段修复) | | `.cursor/cursorrules-backend.md` | 后端开发规范 | --- **修复日期**: 2025-10-13 **修复人员**: Cursor AI Assistant **问题级别**: 🔴 严重(阻塞功能) **修复状态**: ✅ 代码修复完成,等待编译和测试 --- **重要提醒**: 1. ⚠️ 必须重新编译后端代码 2. ⚠️ 必须重启后端服务 3. ⚠️ 修改后才会生效 **编译命令**: ```bash cd backend mvn clean compile -DskipTests ```