Files
ccdi/doc/implementation/frontend-backend-field-matching-report.md
2026-02-09 21:27:20 +08:00

9.1 KiB
Raw Permalink Blame History

员工实体关系 - 前后端字段匹配验证报告

生成时间: 2026-02-09 验证范围: 新增/编辑接口字段匹配


一、新增接口字段匹配

前端Form字段index.vue

form: {
  id: null,                  // 编辑时使用
  personId: null,            // ✅ 必填
  relationPersonPost: null,  // ✅ 可选
  socialCreditCode: null,    // ✅ 必填
  enterpriseName: null,      // ✅ 必填
  status: '1',               // ✅ 默认有效
  remark: null               // ✅ 可选
}

后端AddDTO字段

@NotNull private Long id;                          // ❌ 新增时不传递
@NotBlank private String personId;                 // ✅ 必填
@Size(max=100) private String relationPersonPost; // ✅ 可选
@NotBlank private String socialCreditCode;         // ✅ 必填
@NotBlank private String enterpriseName;           // ✅ 必填
private Integer status;                            // ✅ 可选后端默认1
private String remark;                             // ✅ 可选
@Size(max=50) private String dataSource;          // ❌ 新增时不传递,后端设置
private Integer isEmployee;                        // ❌ 新增时不传递,后端设置
private Integer isEmpFamily;                       // ❌ 新增时不传递,后端设置
private Integer isCustomer;                        // ❌ 新增时不传递,后端设置
private Integer isCustFamily;                      // ❌ 新增时不传递,后端设置

匹配状态

字段 前端 后端 匹配 说明
id 不传递 @NotNull ⚠️ 新增时不传递,由数据库自增
personId @NotBlank 完全匹配
relationPersonPost @Size 完全匹配
socialCreditCode @NotBlank 完全匹配
enterpriseName @NotBlank 完全匹配
status '1' 可选 前端传递,后端有默认值
remark 可选 完全匹配
dataSource @Size 后端自动设置为"MANUAL"
isEmployee 后端自动设置为0
isEmpFamily 后端自动设置为1
isCustomer 后端自动设置为0
isCustFamily 后端自动设置为0

结论: 新增接口字段匹配正确,系统字段由后端自动设置


二、编辑接口字段匹配

前端Form字段编辑时

form: {
  id: xxx,                  // ✅ 从接口获取
  personId: xxx,            // ✅ 从接口获取
  relationPersonPost: xxx,  // ✅ 可编辑
  socialCreditCode: xxx,    // ✅ 可编辑
  enterpriseName: xxx,      // ✅ 可编辑
  status: xxx,              // ✅ 可编辑(仅编辑时显示)
  remark: xxx               // ✅ 可编辑
}

后端EditDTO字段

@NotNull private Long id;                          // ✅ 必填
@NotBlank private String personId;                 // ✅ 必填
@Size(max=100) private String relationPersonPost; // ✅ 可选
@NotBlank private String socialCreditCode;         // ✅ 必填
@NotBlank private String enterpriseName;           // ✅ 必填
private Integer status;                            // ✅ 可选
private String remark;                             // ✅ 可选
@Size(max=50) private String dataSource;          // ⚠️ 前端不传递
private Integer isEmployee;                        // ⚠️ 前端不传递
private Integer isEmpFamily;                       // ⚠️ 前端不传递
private Integer isCustomer;                        // ⚠️ 前端不传递
private Integer isCustFamily;                      // ⚠️ 前端不传递

后端更新逻辑(已修复)

@Override
@Transactional
public int updateRelation(CcdiStaffEnterpriseRelationEditDTO editDTO) {
    // 使用LambdaUpdateWrapper只更新非null字段
    LambdaUpdateWrapper<CcdiStaffEnterpriseRelation> updateWrapper = new LambdaUpdateWrapper<>();
    updateWrapper.eq(CcdiStaffEnterpriseRelation::getId, editDTO.getId());

    // 只更新前端可编辑的字段
    updateWrapper.set(editDTO.getPersonId() != null, CcdiStaffEnterpriseRelation::getPersonId, editDTO.getPersonId());
    updateWrapper.set(editDTO.getRelationPersonPost() != null, CcdiStaffEnterpriseRelation::getRelationPersonPost, editDTO.getRelationPersonPost());
    updateWrapper.set(editDTO.getSocialCreditCode() != null, CcdiStaffEnterpriseRelation::getSocialCreditCode, editDTO.getSocialCreditCode());
    updateWrapper.set(editDTO.getEnterpriseName() != null, CcdiStaffEnterpriseRelation::getEnterpriseName, editDTO.getEnterpriseName());
    updateWrapper.set(editDTO.getStatus() != null, CcdiStaffEnterpriseRelation::getStatus, editDTO.getStatus());
    updateWrapper.set(editDTO.getRemark() != null, CcdiStaffEnterpriseRelation::getRemark, editDTO.getRemark());

    // 系统字段不更新,保留原值
    // - dataSource, isEmployee, isEmpFamily, isCustomer, isCustFamily

    return relationMapper.update(null, updateWrapper);
}

匹配状态

字段 前端传递 后端处理 匹配 说明
id @NotNull 必填,用于定位记录
personId @NotBlank 完全匹配
relationPersonPost @Size 完全匹配
socialCreditCode @NotBlank 完全匹配
enterpriseName @NotBlank 完全匹配
status 可选 完全匹配
remark 可选 完全匹配
dataSource null 保留原值 系统字段,不更新
isEmployee null 保留原值 系统字段,不更新
isEmpFamily null 保留原值 系统字段,不更新
isCustomer null 保留原值 系统字段,不更新
isCustFamily null 保留原值 系统字段,不更新

结论: 编辑接口字段匹配正确使用LambdaUpdateWrapper保护系统字段


三、修复前的问题

问题1使用BeanUtils.copyProperties + updateById

// 修复前的问题代码
CcdiStaffEnterpriseRelation relation = new CcdiStaffEnterpriseRelation();
BeanUtils.copyProperties(editDTO, relation);
int result = relationMapper.updateById(relation);

问题描述:

  • BeanUtils.copyProperties 会复制所有字段包括null值
  • updateById 会更新所有字段将系统字段覆盖为null
  • 导致 dataSource, isEmployee, isEmpFamily 等字段丢失

影响:

  • 编辑后数据来源变为null
  • 编辑后员工标识字段变为null
  • 数据完整性受损

问题2前端状态字段类型

// 前端传递字符串
status: '1'  // 字符串
// 后端期望Integer
private Integer status;  // 整数

解决方案: Spring自动进行类型转换


四、修复后的改进

改进1使用LambdaUpdateWrapper

// 修复后的正确代码
LambdaUpdateWrapper<CcdiStaffEnterpriseRelation> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(CcdiStaffEnterpriseRelation::getId, editDTO.getId());

// 只更新非null字段
updateWrapper.set(editDTO.getPersonId() != null, CcdiStaffEnterpriseRelation::getPersonId, editDTO.getPersonId());
// ... 其他字段

int result = relationMapper.update(null, updateWrapper);

优点:

  • 只更新非null字段
  • 保护系统字段不被覆盖
  • 符合业务逻辑(系统字段由后端控制)

改进2字段名统一

原字段名 统一后 位置
idCard personId 前端 → 后端
enterpriseUscc socialCreditCode 前端 → 后端
positionInEnterprise relationPersonPost 前端 → 后端
supplementDescription remark 前端 → 后端

五、测试验证建议

新增测试

  1. 提交完整必填字段,验证保存成功
  2. 验证系统字段自动设置:
    • status = 1
    • dataSource = "MANUAL"
    • isEmployee = 0
    • isEmpFamily = 1
    • isCustomer = 0
    • isCustFamily = 0

编辑测试

  1. 修改可编辑字段,验证更新成功
  2. 验证系统字段保持不变:
    • dataSource 不变
    • isEmployee 不变
    • isEmpFamily 不变
    • isCustomer 不变
    • isCustFamily 不变

边界测试

  1. 编辑时清空可选字段relationPersonPost, remark验证更新为空字符串而非null
  2. 编辑时修改状态,验证状态正确更新

六、总结

项目 状态 说明
新增接口 正常 字段匹配正确,系统字段自动设置
编辑接口 已修复 使用LambdaUpdateWrapper保护系统字段
字段名统一 已完成 前后端字段名完全一致
默认值设置 正常 新增时status默认为1有效
系统字段保护 已修复 编辑时不会覆盖系统字段

修复文件: CcdiStaffEnterpriseRelationServiceImpl.java 修复内容: 将 BeanUtils.copyProperties + updateById 改为 LambdaUpdateWrapper 条件更新