简体   繁体   English

手动调用 Spring Annotation Validation

[英]Manually call Spring Annotation Validation

I'm doing a lot of our validation with Hibernate and Spring Annotations like so:我正在使用 Hibernate 和 Spring Annotations 进行很多验证,如下所示:

public class Account {
    @NotEmpty(groups = {Step1.class, Step2.class})
    private String name;

    @NotNull(groups = {Step2.class})
    private Long accountNumber;

    public interface Step1{}
    public interface Step2{}
}

And then in the controller it's called in the arguments:然后在控制器中在参数中调用它:

public String saveAccount(@ModelAttribute @Validated({Account.Step1.class}) Account account, BindingResult result) {
   //some more code and stuff here
   return "";
}

But I would like to decide the group used based on some logic in the controller method.但我想根据控制器方法中的一些逻辑来决定使用的组。 Is there a way to call validation manually?有没有办法手动调用验证? Something like result = account.validate(Account.Step1.class) ?类似result = account.validate(Account.Step1.class)的东西?

I am aware of creating your own Validator class, but that's something I want to avoid, I would prefer to just use the annotations on the class variables themselves.我知道创建自己的 Validator 类,但这是我想避免的,我宁愿只使用类变量本身的注释。

Spring provides LocalValidatorFactoryBean , which implements the Spring SmartValidator interface as well as the Java Bean Validation Validator interface. Spring 提供了LocalValidatorFactoryBean ,它实现了 Spring SmartValidator接口以及 Java Bean Validation Validator接口。

// org.springframework.validation.SmartValidator - implemented by LocalValidatorFactoryBean
@Autowired
SmartValidator validator;

public String saveAccount(@ModelAttribute Account account, BindingResult result) {
    // ... custom logic
    validator.validate(account, result, Account.Step1.class);
    if (result.hasErrors()) {
        // ... on binding or validation errors
    } else {
        // ... on no errors
    }
    return "";
}

Here is a code sample from JSR 303 spec这是来自JSR 303 规范的代码示例

Validator validator = Validation.buildDefaultValidatorFactory().getValidator();

Driver driver = new Driver();
driver.setAge(16);
Car porsche = new Car();
driver.setCar(porsche);


Set<ConstraintViolation<Driver>> violations = validator.validate( driver );

So yes, you can just get a validator instance from the validator factory and run the validation yourself, then check to see if there are violations or not.所以是的,您可以从验证器工厂获取验证器实例并自己运行验证,然后检查是否存在违规行为。 You can see in the javadoc for Validator that it will also accept an array of groups to validate against.您可以在Validator 的 javadoc 中看到,它还将接受一组要验证的组。

Obviously this uses JSR-303 validation directly instead of going through Spring validation, but I believe spring validation annotations will use JSR-303 if it's found in the classpath显然,这直接使用 JSR-303 验证而不是通过 Spring 验证,但我相信 Spring 验证注释如果在类路径中找到它会使用 JSR-303

If you have everything correctly configured, you can do this:如果您已正确配置所有内容,则可以执行以下操作:

import javax.validation.Validator;

@Autowired
Validator validator;

Then you can use it to validate you object:然后你可以用它来验证你的对象:

var errors = validator.validate(obj);

This link gives pretty good examples of using validations in Spring apps.这个链接给出了在 Spring 应用程序中使用验证的很好的例子。 https://reflectoring.io/bean-validation-with-spring-boot/ https://reflectoring.io/bean-validation-with-spring-boot/

I have found an example to run the validation programmitically in this article.我在本文中找到了一个以编程方式运行验证的示例。

class MyValidatingService {

  void validatePerson(Person person) {
    ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
    Validator validator = factory.getValidator();
    Set<ConstraintViolation<Person>> violations = validator.validate(person);
    if (!violations.isEmpty()) {
      throw new ConstraintViolationException(violations);
    }
  } 
}

It throws 500 status, so it is recommended to handle it with custom exception handler.它会抛出500状态,因此建议使用自定义异常处理程序进行处理。

@ControllerAdvice(annotations = RestController.class)
public class CustomGlobalExceptionHandler extends ResponseEntityExceptionHandler {
    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseEntity<CustomErrorResponse> constraintViolationException(HttpServletResponse response, Exception ex) throws IOException {
        CustomErrorResponse errorResponse = new CustomErrorResponse();
        errorResponse.setTimestamp(LocalDateTime.now());
        errorResponse.setStatus(HttpStatus.BAD_REQUEST.value());
        errorResponse.setError(HttpStatus.BAD_REQUEST.getReasonPhrase());
        errorResponse.setMessage(ex.getMessage());
        return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST);
    }
}

Second example is from https://www.mkyong.com/spring-boot/spring-rest-error-handling-example/第二个示例来自https://www.mkyong.com/spring-boot/spring-rest-error-handling-example/

Update: Using validation is persistence layer is not recommended: https://twitter.com/odrotbohm/status/1055015506326052865更新:不推荐使用验证是持久层: https ://twitter.com/odrotbohm/status/1055015506326052865

Adding to answered by @digitaljoel, you can throw the ConstraintViolationException once you got the set of violations.除了@digitaljoel 的回答之外,一旦您获得了一组违规行为,您就可以抛出 ConstraintViolationException。

Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
        Set<ConstraintViolation<NotionalProviderPaymentDTO>> violations = validator.validate( notionalProviderPaymentDTO );

        if(!violations.isEmpty()) {
            throw new ConstraintViolationException(violations);
        }

You can create your own exception mapper which will handle ConstraintViolationException and send the errors messages to the client.您可以创建自己的异常映射器来处理 ConstraintViolationException 并将错误消息发送到客户端。

And also:并且:

@Autowired
@Qualifier("mvcValidator")
Validator validator;

...
violations = validator.validate(account);
import javax.validation.Validator;
import javax.validation.ConstraintViolation;

public class{
    @Autowired
    private Validator validator;
       .
       .
    public void validateEmployee(Employee employee){

        Set<ConstraintViolation<Employee>> violations = validator.validate(employee);
        if(!violations.isEmpty()) {
            throw new ConstraintViolationException(violations);
        }
    }
}

Here, 'Employee' is a pojo class and 'employee' is it's object在这里,'Employee' 是一个 pojo 类,'employee' 是它的对象

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM