Spring Boot 3中如何根据PathVariable切换@RequestBody的DTO类
Spring Boot 3 根据PathVariable切换RequestBody DTO的实现方案
方案1:拆分端点(Spring官方推荐)
最简洁且易维护的方式是拆分对应不同业务逻辑的子端点,天然支持各自的参数验证:
@PostMapping(value = "/data/update/1", produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<?> editRegV1(@Validated @RequestBody EditEmailBulkRequest request) { // 处理value=1的业务逻辑 return ResponseEntity.ok("处理版本1请求成功"); } @PostMapping(value = "/data/update/2", produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<?> editRegV2(@Validated @RequestBody EditEmailBulkRequestNew request) { // 处理value=2的业务逻辑 return ResponseEntity.ok("处理版本2请求成功"); }
方案2:手动解析RequestBody并切换DTO
如果必须保留同一端点,可以直接接收JSON字符串,根据value值手动解析为对应DTO,并自行处理参数验证:
@PostMapping(value = "/data/update/{value}", produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<?> editReg(@PathVariable String value, @RequestBody String requestBody) { ObjectMapper objectMapper = new ObjectMapper(); Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); Object dto; Set<ConstraintViolation<Object>> violations; try { if ("1".equals(value)) { EditEmailBulkRequest request = objectMapper.readValue(requestBody, EditEmailBulkRequest.class); violations = validator.validate(request); dto = request; } else if ("2".equals(value)) { EditEmailBulkRequestNew request = objectMapper.readValue(requestBody, EditEmailBulkRequestNew.class); violations = validator.validate(request); dto = request; } else { return ResponseEntity.badRequest().body("无效的value参数"); } } catch (JsonProcessingException e) { return ResponseEntity.badRequest().body("请求格式错误"); } // 处理验证错误 if (!violations.isEmpty()) { List<String> errorMessages = violations.stream() .map(ConstraintViolation::getMessage) .collect(Collectors.toList()); return ResponseEntity.badRequest().body(errorMessages); } // 根据DTO类型执行对应业务逻辑 if (dto instanceof EditEmailBulkRequest) { EditEmailBulkRequest req = (EditEmailBulkRequest) dto; // 版本1业务处理 } else if (dto instanceof EditEmailBulkRequestNew) { EditEmailBulkRequestNew req = (EditEmailBulkRequestNew) dto; // 版本2业务处理 } return ResponseEntity.ok("请求处理成功"); }
方案3:使用多态DTO结合Jackson类型解析
通过定义父类DTO,利用Jackson的多态类型解析功能,结合value参数自动匹配对应子类:
- 定义父类DTO并配置Jackson多态注解:
@Data @NoArgsConstructor @AllArgsConstructor @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "value") @JsonSubTypes({ @JsonSubTypes.Type(value = EditEmailBulkRequest.class, name = "1"), @JsonSubTypes.Type(value = EditEmailBulkRequestNew.class, name = "2") }) public abstract class BaseEditRequest { }
- 修改现有DTO继承父类:
@Data @NoArgsConstructor @AllArgsConstructor public class EditEmailBulkRequest extends BaseEditRequest { @NotNull private int id; @NonNull @NotEmpty private String name; }
@Data @NoArgsConstructor @AllArgsConstructor public class EditEmailBulkRequestNew extends BaseEditRequest { @NotNull private String email; @NonNull @NotEmpty private String org; }
- 控制器方法实现:
@PostMapping(value = "/data/update/{value}", produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<?> editReg(@PathVariable String value, @Validated @RequestBody BaseEditRequest request) { // 根据子类类型处理业务 if (request instanceof EditEmailBulkRequest) { EditEmailBulkRequest req = (EditEmailBulkRequest) request; // 版本1业务逻辑 } else if (request instanceof EditEmailBulkRequestNew) { EditEmailBulkRequestNew req = (EditEmailBulkRequestNew) request; // 版本2业务逻辑 } else { return ResponseEntity.badRequest().body("不支持的请求类型"); } return ResponseEntity.ok("请求处理成功"); }
注意:若自动解析不生效,可手动配置ObjectMapper或在控制器中手动传入
value参数辅助解析。
内容的提问来源于stack exchange,提问作者vegeta
相关产品推荐
相关产品推荐

