Spring 启动 - 验证服务中的数据

Spring boot - Validate data in service

我需要在我的 Spring 引导应用程序的服务中执行 DTO 的手动验证。如果出现验证错误,是抛出自定义异常还是抛出 ConstraintViolationException 更好?

在 ConstraintViolationException 的情况下,我该如何抛出它?

我会坚持使用验证注释和 ConstraintViolationException 来使代码和验证尽可能简单。

根据您计划如何进行验证,有很多选项,但我使用 - 在类似情况下 - 一种创建注释和验证器的方法,它们与控制器中的任何验证注释一样使用,例如.

验证内容如下所示:

@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = MyValidatorAnnotation.MyValidator.class)
public @interface MyValidatorAnnotation {
    String message() default "not a valid DTO";
    Class<? extends Payload>[] payload() default {};
    Class<?>[] groups() default {};
    // I have created this validator as interface's inner class to
    // to keep code simpler but it can be "outer" class also.
    @Component // this is not necessarily needed
    class MyValidator
            implements ConstraintValidator<MyValidatorAnnotation, MyDto> {
        @Resource
        private MyRepository myRepository;
        @Override
        public boolean isValid(MyDto myDto, ConstraintValidatorContext context) {
            boolean valid = true;
            // If you need some custom messages, try something like:
            context.disableDefaultConstraintViolation();
            if (StringUtils.isBlank(myDto.getName())) {
                context.buildConstraintViolationWithTemplate("NAME WAS BLANK")
                        .addPropertyNode("name")
                        .addConstraintViolation();
                valid = false;
            }
            // Any checks you need to do with myRepository
            // or with any other resources
            return valid;
        }
    }
}

然后 using/triggering 此验证取决于几件事。请参阅以下服务示例:

@Service
@Validated
public class MyService {
    // In this method validation will not work if called from MyService itself.
    // Works only when called from "outside" so from any other managed bean
    public void handleMyDtoExt(@Valid MyDto myDto) {
        // furious handling
    }
    // Works when called anywhere even from service itself.
    // The drawback is that you need more code & injection & testing which you of
    // course want to avoid.
    // In this case you also might not want add @Validated to your service.
    @Resource
    private Validator validator;
    private void handleMyDto(MyDto myDto) {
        Set<ConstraintViolation<MyDto>> cvs = validator.validate(myDto);
        if(!cvs.isEmpty()) {
            throw new ConstraintViolationException(cvs);
        }
        // furious handling
    }
}