创建Java更新API遇EntityNotFoundException,困惑DTO与Entity类选择
问题解决与方案建议
一、EntityNotFoundException 异常修复
1. 先修正代码笔误
你的Controller里调用findById时写错了Repository变量名:orgStudentRepo应该是ogStudentRepo,这是明显的拼写错误,会导致逻辑异常。
2. 排查数据存在性
如果修正笔误后仍抛出异常,说明传入的ogStudentId在数据库中不存在:
- 检查Liquibase生成的
og_student表,确认是否有对应ID的记录 - 验证请求路径中的
{ogStudentId}参数是否正确(注意String类型主键大小写敏感,避免空格、格式错误) - 可添加日志打印实际传入的ID,方便排查:
log.info("尝试更新学生ID: {}", ogStudentId);
3. 移除冗余代码
orElseThrow在找不到数据时已经抛出异常,后续的if(existingStudent == null)判断完全多余,直接删掉即可。
修复后的Controller方法:
@PutMapping("/update/{ogStudentId}") public ResponseEntity<String> updateStudent(@PathVariable String ogStudentId, @RequestBody OgStudent ogStudent){ log.info("尝试更新学生ID: {}", ogStudentId); OgStudent existingStudent = ogStudentRepo.findById(ogStudentId) .orElseThrow(() -> new EntityNotFoundException("OG学生不存在")); existingStudent.setFirstName(ogStudent.getFirstName()); existingStudent.setLastName(ogStudent.getLastName()); existingStudent.setMiddleName(ogStudent.getMiddleName()); ogStudentRepo.save(existingStudent); return ResponseEntity.ok("更新成功"); }
二、DTO类 vs Entity类的选择建议
为什么不直接用Entity接收请求?
- 敏感字段暴露风险:你的Entity包含
email、dob等字段,直接用它接收请求时,客户端可能传入这些字段并被意外修改(哪怕当前代码没处理,后续迭代也容易出问题)。 - 耦合性过高:Entity与数据库表结构强绑定,表结构变更时,接口请求参数也被迫修改,不符合开闭原则。
- 校验逻辑混乱:请求参数的校验(非空、格式验证等)应该和持久层代码分离,避免污染Entity。
如何实现DTO?
- 创建仅包含需要更新字段的DTO类:
import jakarta.validation.constraints.NotBlank; import lombok.Getter; import lombok.Setter; @Getter @Setter public class UpdateStudentDTO { @NotBlank(message = "名不能为空") private String firstName; private String middleName; @NotBlank(message = "姓不能为空") private String lastName; }
- 修改Controller方法,用DTO接收请求并添加参数校验:
@PutMapping("/update/{ogStudentId}") public ResponseEntity<String> updateStudent(@PathVariable String ogStudentId, @Valid @RequestBody UpdateStudentDTO updateStudentDTO){ log.info("尝试更新学生ID: {}", ogStudentId); OgStudent existingStudent = ogStudentRepo.findById(ogStudentId) .orElseThrow(() -> new EntityNotFoundException("OG学生不存在")); existingStudent.setFirstName(updateStudentDTO.getFirstName()); existingStudent.setLastName(updateStudentDTO.getLastName()); existingStudent.setMiddleName(updateStudentDTO.getMiddleName()); ogStudentRepo.save(existingStudent); return ResponseEntity.ok("更新成功"); }
- 确保项目引入
spring-boot-starter-validation依赖(Spring Boot 3.x需手动添加),并在启动类/配置类添加@Validated注解开启校验。
总结
- 前端请求用DTO接收:隔离业务层与持久层,降低耦合,避免敏感字段暴露。
- Entity仅用于数据库交互:作为持久化对象,不直接暴露给接口层。
内容的提问来源于stack exchange,提问作者dracile
相关产品推荐
相关产品推荐

