交叉参数验证程序isvalid引发constraintviolationexception

xpcnnkqh  于 2021-07-14  发布在  Java
关注(0)|答案(1)|浏览(252)

我有一个带有post调用的控制器,它接收的不是pojo,而是httpservletrequest请求和@parambody la:

class MyController {

@PostMapping("/entrypoint")
public ResponseEntity<String> hello(HttpServletRequest request, @ParamBody body){
 /* Many subcalls */
}

控制器将调用服务和其他rest客户机的一些子调用以形成响应,但是我们在中间完成了许多验证,我们希望将它们移动到验证器以进行一些排序。在主子调用之前,有一个对小型外部服务的调用,我们将根据响应来考虑请求是否有效。我们也会将该子调用移动到验证器,并将服务作为bean添加。稍后我们需要在控制器中使用来自该调用的响应。
为此,我创建了一个验证器及其接口:

@Constraint(validatedBy = ParamConstraintValidator.class)
    @Target({ PARAMETERS })
    @Retention(RUNTIME)
    @Documented
    public @interface ParamConstraint{

        String message() default "default message";

        Class<?>[] groups() default { };

        Class<? extends Payload>[] payload() default { };
    }

    @SupportedValidationTarget(ValidationTarget.PARAMETERS)
    public class ParamConstraintValidator implements
            ConstraintValidator<ParamConstraint, Object[]> {

        @Autowire
        ClientCheck clientCheck;

        @Override
        public void initialize(ParamConstraint paramConstraint) {
        }

        @Override
        public boolean isValid(Object[] value, ConstraintValidatorContext context) {
            if ( value.length != 4 ) {
                context.disableDefaultConstraintViolation();
                context.buildConstraintViolationWithTemplate("Param number is wrong")
                        .addConstraintViolation();
                return false;
            }

            if ( value[0] == null || value[1] == null ) {
                context.disableDefaultConstraintViolation();
                context.buildConstraintViolationWithTemplate("Param contents are null")
                        .addConstraintViolation();
                return false;
            }
            /* More validations*/
            ClientToken ct = clientCheck.verify(value[0], value[1])

            /* More validations*/
            value[2] = ct;
            return true;
    }

由于我们需要将客户机令牌传递给后续的子调用,我将它作为第三个参数添加到控制器的方法签名中(第四个参数是bindingresult,用于从上下文检索错误)

class MyController {

    @PostMapping("/entrypoint")
    @ParamConstraint
    public ResponseEntity<String> hello(HttpServletRequest request, @ParamBody String body,
    @Param(required = false) ClientToken ct, BindingResult result){
       try {
        if(result.hasErrors()) {
            throw new WhateverException("Custom error to be processed by a handler");
        }
     /* Many subcalls */
       }
       catch (Exception e) {
       }
    }

我注意到的第一件事是没有调用来自验证器的isvalid。在多次尝试和错误之后,我尝试将@validation注解添加到控制器类中,如:

@Validation
MyController

直到那时isvalid方法才开始工作。我可以从isvalid获得clienttoken。当我必须在isvalid中返回false时,问题就来了。接下来发生的是没有我所期望的parameterexception,而是一个constraintviolationexception,我无法在控制器中捕获它。bindingresult似乎不可用,因此我也不知道触发异常的错误是什么。从理论上看,交叉参数约束被转换为类约束,从而阻止我从控制器捕获violationconstraintexception。
第一个问题:考虑到签名中有一个未注解的httpservletrequest、@parambody body和@param参数,是否可以为我的示例执行一个跨参数验证器?
第二:如果是,那么为什么不调用isvalid呢?我需要改变什么?
第三:在控制器中添加@validation是否将我的跨参数验证器转换为类验证器?
第四:如果我必须使用类验证器,因为我不能使用交叉参数:我如何读取constraintviolationexception?一个controllerhandler是否足以捕获异常?如何填充constraintviolationexception以知道应该将哪个错误响应发送回客户端?
这有点长,因为这可能是一个角落的案件。我在某个地方读到过,但没有消息来源证明交叉参数验证只适用于@param,而不适用于@parambody,它将由另一个组件管理,该组件可能不接受将不同类型的参数放入isvalid方法中。
我希望有人能帮上忙。打电话问我有什么问题吗

nnt7mjpx

nnt7mjpx1#

在我看来,您应该创建一个dto来接收有效负载并创建 annotation 基于另一个属性验证属性,然后您应该能够 bindingresults 其中包括验证错误(如果有),或者您可以在控制器方法中进一步实现自己的验证逻辑。

相关问题