11 KiB
11 KiB
出国行程变更申请 - 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查询中包含 create_dept 字段
SELECT
c.change_id,
c.record_id,
...
c.create_dept, -- ❌ 查询返回了这个字段
c.create_by,
c.create_time,
...
FROM rs_overseas_itinerary_change c
// 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
修复代码:
/**
* 删除标志(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类必须包含以下基础字段:
/**
* 创建部门
*/
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 自动查询
// 使用 selectList 等方法
List<RsOverseasItineraryChangeVo> list = mapper.selectVoList(wrapper);
- ✅ MyBatis-Plus 只查询VO类中定义的字段
- ✅ 如果VO中没有
createDept,查询SQL不会包含这个字段 - ✅ 不会报错
场景2:自定义SQL查询(本次错误场景)
<!-- RsOverseasItineraryChangeMapper.xml -->
<select id="selectChangeList" resultType="RsOverseasItineraryChangeVo">
SELECT
c.change_id,
c.record_id,
...
c.create_dept, -- ✅ SQL明确查询了这个字段
c.create_by,
c.create_time,
...
FROM rs_overseas_itinerary_change c
</select>
- ❌ SQL返回了
create_dept字段 - ❌ 但VO类中没有
createDept属性 - ❌ MyBatis尝试调用
setCreateDept()方法 - ❌ 找不到setter方法,抛出
ReflectionException - ❌ 导致整个查询失败,返回500错误
对比示例
❌ 错误的VO类(缺少基础字段)
@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类(包含基础字段)
@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命令(推荐)
cd /Users/weizzzz/Documents/Cursor/0828CURSOR/all-project/backend
mvn clean compile -DskipTests
方法2:重启后端服务
cd /Users/weizzzz/Documents/Cursor/0828CURSOR/all-project/backend
mvn spring-boot:run
方法3:使用IDE重新编译
- IDEA: Build → Rebuild Project
- Eclipse: Project → Clean
3. 验证修复
测试步骤:
- 重启后端服务
- 刷新前端页面
- 访问"出国行程变更管理"
- 验证列表是否正常显示
预期结果:
- ✅ 列表正常加载
- ✅ 没有500错误
- ✅ 能看到所有变更申请数据
📊 问题根源分析
时间线
1. 数据库设计 → 表包含 create_dept 字段 ✅
2. Entity类设计 → 继承BaseEntity,包含基础字段 ✅
3. Mapper.xml设计 → SQL查询包含 create_dept ✅
4. VO类设计 → ❌ 忘记添加 create_dept 字段
5. 运行时错误 → MyBatis无法映射字段 → 500错误
为什么之前没发现?
原因1:提交功能先开发
// 提交API - 使用Entity类,不是VO类
public R<Void> add(@RequestBody RsOverseasItineraryChangeBo bo) {
return toAjax(rsOverseasItineraryChangeService.insertByBo(bo));
}
- ✅ Entity类继承
BaseEntity,自动包含所有基础字段 - ✅ 提交功能正常工作
原因2:列表查询后开发
// 列表API - 使用VO类
public TableDataInfo<RsOverseasItineraryChangeVo> list(
RsOverseasItineraryChangeBo bo,
PageQuery pageQuery
) {
return rsOverseasItineraryChangeService.queryPageList(bo, pageQuery);
}
- ❌ VO类缺少
createDept字段 - ❌ 第一次查询列表时才发现问题
原因3:测试不充分
- ✅ 测试了提交功能 → 通过
- ❌ 没有测试列表查询 → 发现问题
🎯 最佳实践建议
1. VO类设计模板
所有VO类都应该使用这个模板:
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类基础字段规范(强制性)"
核心内容:
### 🔴 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. 重新编译后端(必须)
cd /Users/weizzzz/Documents/Cursor/0828CURSOR/all-project/backend
mvn clean compile -DskipTests
2. 重启后端服务(必须)
# 停止当前服务(Ctrl+C)
# 然后重新启动
mvn spring-boot:run
3. 刷新前端页面(必须)
# 强制刷新浏览器
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
问题级别: 🔴 严重(阻塞功能)
修复状态: ✅ 代码修复完成,等待编译和测试
重要提醒:
- ⚠️ 必须重新编译后端代码
- ⚠️ 必须重启后端服务
- ⚠️ 修改后才会生效
编译命令:
cd backend
mvn clean compile -DskipTests