SpringBoot+PostgreSQL POST请求JSON反序列化及字段校验报错
问题分析与解决方案
问题1:JSON反序列化无法构造Treino实例
原因
首次请求的JSON中直接用数字(如103)赋值给idTreino字段,但TreinoExercicio的idTreino是Treino类型,Jackson默认无法将数字直接转换为实体对象,缺少对应的反序列化逻辑。
解决方案
推荐使用DTO(数据传输对象)接收请求,再转换为实体类,这是更规范的做法:
- 创建
TreinoExercicioDTO类:
public class TreinoExercicioDTO { private Long idTreino; private Long idExercicio; private String dificuldade; private BigDecimal peso; private BigDecimal series; // 生成Getter和Setter方法 }
- 修改控制器接收DTO:
@PostMapping public ResponseEntity<?> cadastrar(@RequestBody final TreinoExercicioDTO dto){ try{ this.treinoExercicioService.cadastrar(dto); return ResponseEntity.ok("Cadastrado"); }catch(RuntimeException e){ return ResponseEntity.badRequest().body("Error " + e.getMessage()); } }
- 修改服务类,转换DTO为实体并查询关联对象:
@Service public class TreinoExercicioService { @Autowired private TreinoExercicioRepository treinoExercicioRepository; @Autowired private TreinoRepository treinoRepository; @Autowired private ExercicioRepository exercicioRepository; @Transactional(rollbackFor = Exception.class) public void cadastrar(final TreinoExercicioDTO dto){ // 查询关联的Treino和Exercicio实例 Treino treino = treinoRepository.findById(dto.getIdTreino()) .orElseThrow(() -> new RuntimeException("Treino não encontrado")); Exercicio exercicio = exercicioRepository.findById(dto.getIdExercicio()) .orElseThrow(() -> new RuntimeException("Exercício não encontrado")); // 字段校验 Assert.isTrue(!dto.getDificuldade().isBlank(), "Campo DIFICULDADE vazio"); Assert.isTrue(dto.getPeso() != null, "Error campo PESO invalido ou vazio"); Assert.isTrue(dto.getSeries() != null, "Error campo SERIES vazio"); // 构建TreinoExercicio实体 TreinoExercicio treinoExercicio = new TreinoExercicio(); treinoExercicio.setIdTreino(treino); treinoExercicio.setIdExercicio(exercicio); treinoExercicio.setDificuldade(dto.getDificuldade()); treinoExercicio.setPeso(dto.getPeso()); treinoExercicio.setSeries(dto.getSeries()); this.treinoExercicioRepository.save(treinoExercicio); } }
问题2:完整结构请求返回“Error campo TREINO vazio”
原因
- JSON字段错误:请求中把
TreinoExercicio的idExercicio字段写成了idGrupoMuscular,导致idExercicio为null; - LocalDateTime反序列化失败:
AbstractEntity中的dataCadastrado是LocalDateTime类型,若未正确配置Jackson处理该类型,会导致Treino对象无法正常反序列化,最终idTreino为null,触发断言; - 服务类断言逻辑错误:
Assert.isTrue(treinoExercicio.getDificuldade().isBlank(), ...)逻辑反向,会在dificuldade不为空时抛出异常。
解决方案
- 修正请求JSON字段:将
idGrupoMuscular改为idExercicio,正确的JSON结构如下:
{ "idTreino":{ "id": 52, "dataCadastrado": "2023-07-03T02:52:10.719673", "dataAtualizado": "2023-07-03T02:56:48.691866", "ativo": true, "codigoOrdem": "BBB" }, "idExercicio":{ "id": 1, "dataCadastrado": "2023-07-02T16:54:39.44769", "dataAtualizado": null, "ativo": true, "idGrupoMuscular": { "id": 1, "dataCadastrado": "2023-07-02T16:54:39.44769", "dataAtualizado": null, "ativo": true, "nome": "a" }, "nome": "示例 exercício" }, "dificuldade": "aaaa", "peso": "20", "series": "20" }
- 配置Jackson支持LocalDateTime:
Spring Boot默认已包含jackson-datatype-jsr310依赖,只需在application.properties添加配置:
spring.jackson.serialization.write-dates-as-timestamps=false spring.jackson.date-format=yyyy-MM-dd'T'HH:mm:ss.SSSXXX
- 修正服务类断言逻辑:
将Assert.isTrue(treinoExercicio.getDificuldade().isBlank(), "Campo DIFICULDADE vazio");改为:
Assert.isTrue(!treinoExercicio.getDificuldade().isBlank(), "Campo DIFICULDADE vazio");
额外优化建议
- 所有实体类添加显式无参构造函数,避免Jackson或JPA反射实例化时出现异常;
AbstractEntity的id字段可添加@Setter或@JsonProperty注解,允许Jackson为其赋值(若业务需要)。
内容的提问来源于stack exchange,提问作者Emilio Anastacio
相关产品推荐
相关产品推荐

