Spring boot 在控制器和服务方法之间使用中间件服务方法时,Spring boot跳过自定义验证
当我从控制器直接调用服务方法时,@CustomValidation工作并引发异常 这里是控制器方法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
@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;
}
}