Spring boot 在控制器和服务方法之间使用中间件服务方法时,Spring boot跳过自定义验证

Spring boot 在控制器和服务方法之间使用中间件服务方法时,Spring boot跳过自定义验证,spring-boot,validation,Spring Boot,Validation,当我从控制器直接调用服务方法时,@CustomValidation工作并引发异常 这里是控制器方法 @PostMapping("doSomething") public CustomInfo doSomething(@RequestBody(required = true) MyParam param) { CustomInfo info; try { info = myService.doSomething(param); } catch (Except

当我从控制器直接调用服务方法时,@CustomValidation工作并引发异常

这里是控制器方法

@PostMapping("doSomething")
public CustomInfo doSomething(@RequestBody(required = true) MyParam param) {
    CustomInfo info;
    try {
        info = myService.doSomething(param);
    } catch (Exception e) {
        info = new CustomInfo();
        info.setMessage(e.getMessage());
    }

    return info;
}
这里有一个服务方法

public CustomInfo doSomething(@CustomValidation MyParam param) {
    //do something
}

但如果在控制器的中间使用另一种方法和验证方法,则跳过验证。

下面是中间件方法示例。假设我们正在从控制器调用doSomething1方法

public CustomInfo doSomething1(MyParam param) {
    return this.doSomething(param);
}
为什么它会跳过验证?或者我该如何修复它

编辑

这是服务舱

@Service
@Validated
public class MyService {
    //doSomething1 method
    //doSomething method
}
这是控制器类

@RestController
@RequestMapping("rest/myRest")
public class MyRestController {
    //doSomething caller method
}
这是我的自定义验证注释,用于检查基于xsd模式的类中的必填字段

@Documented
@Constraint(validatedBy = ParseRequiredFieldValidator.class)
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface ParseRequiredField {
    String message() default "Please fill all required fields";

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

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

    String[] ignoreFields() default {};
}
@已记录
@约束(validatedBy=ParseRequiredFieldValidator.class)
@目标({ElementType.PARAMETER})
@保留(RetentionPolicy.RUNTIME)
public@interface ParseRequiredField{
字符串消息()默认为“请填写所有必填字段”;
类[]组()默认值{};
Class targetClass=value.getClass();
List ignoreFields=Arrays.asList(constraint.ignoreFields());
StringBuilder错误=新建StringBuilder();
Field[]fields=targetClass.getDeclaredFields();
用于(字段:字段){
如果(!ignoreFields.contains(field.getName())){
XmlElement annotation=field.getAnnotation(XmlElement.class);
if(annotation!=null&&(annotation.required()&&&!annotation.nillable()){
试一试{
字段。setAccessible(true);
if(field.get(value)==null){
if(errors.length()!=0){
错误。追加(“”);
}
String message=String.format(“%s:必填字段“%s”为空。”,
targetClass.getSimpleName(),
field.getName());
错误。追加(消息);
}
}捕获(例外e){
//e、 printStackTrace();
}
}
}
}
if(errors.length()!=0){
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(errors.toString())
.addConstraintViolation();
返回false;
}
返回true;
}
}

这样的验证是使用AOP实现的。Spring使用基于代理的aop,因此自调用无法工作。它们不通过代理,因此验证将不起作用,这同样适用于事务,例如。@M.Deinum是正确的。我认为您的中间件服务属于不同的类。它不会像那样工作,您需要将中间件服务移动到另一个bean,或者用您的自定义验证器对其进行注释。谢谢。现在我知道原因了
public class ParseRequiredFieldValidator implements ConstraintValidator<ParseRequiredField, Object> {

    private ParseRequiredField constraint;

    @Override
    public void initialize(ParseRequiredField constraint) {
        this.constraint = constraint;
    }

    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {
        Class<?> targetClass = value.getClass();
        List<String> ignoreFields = Arrays.asList(constraint.ignoreFields());

        StringBuilder errors = new StringBuilder();
        Field[] fields = targetClass.getDeclaredFields();
        for (Field field : fields) {
            if(!ignoreFields.contains(field.getName())) {
                XmlElement annotation = field.getAnnotation(XmlElement.class);
                if (annotation != null && (annotation.required() && !annotation.nillable())) {
                    try {
                        field.setAccessible(true);
                        if (field.get(value) == null) {
                            if (errors.length() != 0) {
                                errors.append(" ");
                            }
                            String message = String.format("%s: required field '%s' is null.",
                                    targetClass.getSimpleName(),
                                    field.getName());

                            errors.append(message);
                        }
                    } catch (Exception e) {
                        //e.printStackTrace();
                    }
                }
            }
        }

        if (errors.length() != 0) {
            context.disableDefaultConstraintViolation();
            context.buildConstraintViolationWithTemplate(errors.toString())
                    .addConstraintViolation();
            return false;
        }

        return true;
    }
}