Spring Boot:请求参数中的自定义验证

问题描述 投票:0回答:1

我想验证控制器中的请求参数之一。 request参数应该来自给定值列表之一,否则,将引发错误。在下面的代码中,我希望请求参数orderBy来自@ValuesAllowed中存在的值列表。

@RestController
@RequestMapping("/api/opportunity")
@Api(value = "Opportunity APIs")
@ValuesAllowed(propName = "orderBy", values = { "OpportunityCount", "OpportunityPublishedCount", "ApplicationCount",
        "ApplicationsApprovedCount" })
public class OpportunityController {

@GetMapping("/vendors/list")
    @ApiOperation(value = "Get all vendors")

    public ResultWrapperDTO getVendorpage(@RequestParam(required = false) String term,
            @RequestParam(required = false) Integer page, @RequestParam(required = false) Integer size,
            @RequestParam(required = false) String orderBy, @RequestParam(required = false) String sortDir) {

我已经编写了一个自定义bean验证器,但是不知何故,它不起作用。即使传递查询参数的任何随机值,它也不会验证并抛出错误。

@Repeatable(ValuesAllowedMultiple.class)
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {ValuesAllowedValidator.class})
public @interface ValuesAllowed {

    String message() default "Field value should be from list of ";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};

    String propName();
    String[] values();
}
public class ValuesAllowedValidator implements ConstraintValidator<ValuesAllowed, Object> {

    private String propName;
    private String message;
    private String[] values;

    @Override
    public void initialize(ValuesAllowed requiredIfChecked) {
        propName = requiredIfChecked.propName();
        message = requiredIfChecked.message();
        values = requiredIfChecked.values();
    }

    @Override
    public boolean isValid(Object object, ConstraintValidatorContext context) {
        Boolean valid = true;
        try {
            Object checkedValue = BeanUtils.getProperty(object, propName);

            if (checkedValue != null) {
                valid = Arrays.asList(values).contains(checkedValue.toString().toLowerCase());
            } 

            if (!valid) {
                context.disableDefaultConstraintViolation();
                context.buildConstraintViolationWithTemplate(message.concat(Arrays.toString(values)))
                        .addPropertyNode(propName).addConstraintViolation();
            }
        } catch (IllegalAccessException e) {
            log.error("Accessor method is not available for class : {}, exception : {}", object.getClass().getName(), e);
            return false;
        } catch (NoSuchMethodException e) {
            log.error("Field or method is not present on class : {}, exception : {}", object.getClass().getName(), e);
            return false;
        } catch (InvocationTargetException e) {
            log.error("An exception occurred while accessing class : {}, exception : {}", object.getClass().getName(), e);
            return false;
        }
        return valid;
    }
}
spring-boot validation controller spring-annotations http-request-parameters
1个回答
0
投票

案例1:如果根本未触发注记ValuesAllowed,则可能是因为未使用@Validated对控制器进行注解。

    @Validated
    @ValuesAllowed(propName = "orderBy", values = { "OpportunityCount", "OpportunityPublishedCount", "ApplicationCount",
                        "ApplicationsApprovedCount" })
    public class OpportunityController {
    @GetMapping("/vendors/list")
    public String getVendorpage(@RequestParam(required = false) String term,..{
    }

情况2:如果触发并引发错误,则可能是因为BeanUtils.getProperty无法解析属性并引发异常。

如果上述解决方案不起作用,则可以尝试将注释移到方法级别,并更新Validator以将有效值列表用于OrderBy参数。这对我有用。下面是示例代码。


    @RestController
    @RequestMapping("/api/opportunity")
    @Validated
    public class OpportunityController {
        @GetMapping("/vendors/list")
        public String getVendorpage(@RequestParam(required = false) String term,
                @RequestParam(required = false) Integer page, @RequestParam(required = false) Integer size,
                @ValuesAllowed(propName = "orderBy") @RequestParam(required = false) String orderBy, @RequestParam(required = false) String sortDir) {
            return "success";
        }
    }

    @Retention(RetentionPolicy.RUNTIME)
    @Constraint(validatedBy = { ValuesAllowed.Validator.class })
    public @interface ValuesAllowed {

        String message() default "Field value should be from list of ";

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

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

        String propName();

        class Validator implements ConstraintValidator<ValuesAllowed, String> {
            private String propName;
            private String message;
            private String[] values = { "OpportunityCount", "OpportunityPublishedCount", "ApplicationCount",
                    "ApplicationsApprovedCount" };

            @Override
            public void initialize(ValuesAllowed requiredIfChecked) {
                this.propName = requiredIfChecked.propName();
                message = requiredIfChecked.message();
            }

            public boolean isValid(String value, ConstraintValidatorContext context) {
                Boolean valid;
                valid = Arrays.asList(values).contains(value);


                if (!valid) {
                    context.disableDefaultConstraintViolation();
                    context.buildConstraintViolationWithTemplate(message.concat(Arrays.toString(values)))
                            .addPropertyNode(this.propName).addConstraintViolation();
                }
                return valid;
            }
        }
    }
© www.soinside.com 2019 - 2024. All rights reserved.