Spring MVC 如何使用Validated验证Controller上的集合对象?

exdqitrt  于 2023-06-23  发布在  Spring
关注(0)|答案(1)|浏览(129)

我有以下要验证的DTO:

@Data
public class ContinentDto {

    @Null(groups = { CreateValidation.class }, message = "ID must be null")
    @NotNull(groups = { UpdateValidation.class }, message = "ID must not be null")
    @JsonProperty
    private Integer id;

    @NotBlank(groups = { CreateValidation.class, UpdateValidation.class }, message = "continentName must not be blank")
    @JsonProperty
    private String continentName;

    public interface CreateValidation {
        // validation group marker interface
    }

    public interface UpdateValidation {
        // validation group marker interface
    }

}

它包含两个Validation GroupsCreateValidationUpdateValidation,应用不同的验证。
当DTO作为单个参数传递时,我完全能够验证它,但是对于具有DTO集合作为请求的API,不再应用验证。
这是我的控制器:

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/continent")
public class ContinentRestController {

    private final ContinentService service;

    @PostMapping(value = "/save-one", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    public @ResponseBody Integer save(
           @Validated(ContinentDto.CreateValidation.class) 
           @RequestBody final ContinentDto dto) throws TechnicalException {

        return service.save(dto);

    }

    @PostMapping(value = "/save-all", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    public @ResponseBody Collection<Integer> saveAll(
           @Validated(ContinentDto.CreateValidation.class) 
           @RequestBody final Collection<ContinentDto> dtos) throws TechnicalException {

        return service.save(dtos);

    }

    @PutMapping(value = "/update-one", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    public @ResponseBody Integer update(
           @Validated(ContinentDto.UpdateValidation.class) 
           @RequestBody final ContinentDto dto) throws FunctionalException, TechnicalException {
    
        return service.update(dto);

    }

    @PutMapping(value = "/update-all", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    public @ResponseBody Collection<Integer> updateAll(
           @Validated(ContinentDto.UpdateValidation.class)
           @RequestBody final Collection<ContinentDto> dtos) throws FunctionalException, TechnicalException {
    
        return service.update(dtos);
    
    }

}

我还尝试在集合的菱形括号内添加@Valid注解,但没有任何变化。
我看到关于列表验证的其他问题,建议的答案是在类级别应用@Validated注解,但在我的情况下,我认为这是不可能的,因为我使用的是Validation Groups

vql8enpb

vql8enpb1#

我仍然在寻找使用注解的解决方案,但在此之前,我用这种方式解决了它:
我创建了一个ValidatorUtils

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ValidatorUtils {

    public static <TO_VALIDATE> void validate(Collection<TO_VALIDATE> collectionToValidate) {
        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
        for (TO_VALIDATE toValidate : collectionToValidate) {
            Set<ConstraintViolation<TO_VALIDATE>> violations = validator.validate(toValidate);
            if (!violations.isEmpty()) {
                throw new ConstraintViolationException(violations);
            }
        }
    }

    public static <TO_VALIDATE> void validateGroups(Collection<TO_VALIDATE> collectionToValidate, Class<?>... groups) {
        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
        for (TO_VALIDATE toValidate : collectionToValidate) {
            Set<ConstraintViolation<TO_VALIDATE>> violations = validator.validate(toValidate, groups);
            if (!violations.isEmpty()) {
                throw new ConstraintViolationException(violations);
            }
        }
    }

}

然后在调用服务之前在控制器中使用它:

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/continent")
public class ContinentRestController {

    private final ContinentService service;

    @PostMapping(value = "/save-one", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    public @ResponseBody Integer save(
           @Validated(ContinentDto.CreateValidation.class) 
           @RequestBody final ContinentDto dto) throws TechnicalException {

        return service.save(dto);

    }

    @PostMapping(value = "/save-all", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    public @ResponseBody Collection<Integer> saveAll(
           @RequestBody final Collection<ContinentDto> dtos) throws TechnicalException {

        ValidatorUtils.validateGroups(dtos, ContinentDto.CreateValidation.class);
        return service.save(dtos);

    }

    @PutMapping(value = "/update-one", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    public @ResponseBody Integer update(
           @Validated(ContinentDto.UpdateValidation.class) 
           @RequestBody final ContinentDto dto) throws FunctionalException, TechnicalException {
    
        return service.update(dto);

    }

    @PutMapping(value = "/update-all", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    public @ResponseBody Collection<Integer> updateAll(
           @RequestBody final Collection<ContinentDto> dtos) throws FunctionalException, TechnicalException {
    
        ValidatorUtils.validateGroups(dtos, ContinentDto.UpdateValidation.class);
        return service.update(dtos);
    
    }

}

相关问题