首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >请求反序列化过程中的自定义声明spring验证

请求反序列化过程中的自定义声明spring验证
EN

Stack Overflow用户
提问于 2019-11-22 10:07:50
回答 4查看 2.5K关注 0票数 2

我正在寻找注释pojo类的注释,在请求反序列化过程中需要对该类进行验证。我正在搜索要作为参数类传递的注释,这将验证我的pojo。

实现可以如下所示:

代码语言:javascript
运行
复制
@ValidateAnnotation(class = ExampleClassValidator.class)
public class ExampleClass {
    private String name;
}

有人知道那种方法的spring注释或者提供声明性验证的依赖吗?我之所以问这个问题,是因为在文档中找不到任何类似的解决方案。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2019-12-02 19:56:23

可以使用@InitBinder根据方法的目标配置验证器。下面是一个简单的例子:

注释类:

代码语言:javascript
运行
复制
package test.xyz;


import org.springframework.validation.Validator;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface ValidateAnnotation {
    Class<? extends Validator> value();
}

要验证的示例类:

代码语言:javascript
运行
复制
package test.xyz;

@ValidateAnnotation(ExampleClassValidator.class)
public class ExampleClass {
}

验证器类:

代码语言:javascript
运行
复制
package test.xyz;

import org.springframework.validation.Errors;

public class ExampleClassValidator implements org.springframework.validation.Validator {
    @Override
    public boolean supports(Class<?> aClass) {
        return ExampleClass.class.isAssignableFrom(aClass);
    }

    @Override
    public void validate(Object o, Errors errors) {

    }
}

最后是带有@InitBinder定义的控制器类:

代码语言:javascript
运行
复制
import org.springframework.stereotype.Controller;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import test.xyz.ExampleClass;
import test.xyz.ValidateAnnotation;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.Collections;

@Controller
public class ExampleController {
    @RequestMapping(value="test-endpoint", method= RequestMethod.GET)
    public @ResponseBody
    Object testMethod(@Valid ExampleClass exampleClass, Errors errors) {
        return Collections.singletonMap("success", true);
    }


    @InitBinder
    public void initBinder(WebDataBinder binder, HttpServletRequest request) throws IllegalAccessException, InstantiationException {
        Class<?> targetClass = binder.getTarget().getClass();
        if(targetClass.isAnnotationPresent(ValidateAnnotation.class)) {
            ValidateAnnotation annotation = targetClass.getAnnotation(ValidateAnnotation.class);
            Class<? extends Validator> value = annotation.value();
            Validator validator = value.newInstance();
            binder.setValidator(validator);
        }
    }
}

解释:

您可以使用WebDataBinder的getTarget方法访问要验证的目标。从那里可以简单地检查类上的注释,获取验证器类,并将其设置在绑定器上。我相信您也可以使用@ControllerAdvice注释来配置全局InitBinder。作为免责声明,我不知道是否建议访问InitBinder中的绑定器目标,但是我已经这样做过几次,但我没有遇到任何问题。

票数 1
EN

Stack Overflow用户

发布于 2019-11-25 22:12:34

对于正常的验证,您可以使用来自javax.validation.constraints包的注释对类进行注释,比如javax.validation.constraints.NotEmpty。对于自定义验证,您可以自己编写注释,该注释将调用您编写的自定义验证器。

例如,如果您想要创建一个验证器,以确保一个字段的长度为9个字符,则可以执行以下操作:

首先,创建自定义验证注释。

代码语言:javascript
运行
复制
@Documented
@Constraint(validatedBy = NineCharactersValidator.class)
@Target( { ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface NineCharactersOnly {
    String message() default "This field must contain exactly nine characters";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

接下来,创建您的自定义验证程序:

代码语言:javascript
运行
复制
public class NineCharactersValidator implements ConstraintValidator<NineCharactersOnly, String> {

    @Override
    public void initialize(NineCharactersOnly contactNumber) {
    }

    @Override
    public boolean isValid(String contactField, ConstraintValidatorContext cxt) {
        return contactField != null && contactField.length() == 9;
    }
}

接下来,在需要对pojo进行约束的字段上使用注释。

代码语言:javascript
运行
复制
public class ExampleClass {
    @NineCharactersOnly
    private String fieldThatMustBeNineCharacters;
}

接下来,将控制器中的方法参数标记为@Valid,这样它们将被Spring验证:

代码语言:javascript
运行
复制
@RestController
public class CustomValidationController {

    @PostMapping("/customValidationPost")
    public ResponseEntity<String> customValidation(@Valid ExampleClass exampleClass, BindingResult result, Model m) {
        // we know the data is valid if we get this far because Spring automatically validates the input and 
        // throws a MethodArgumentNotValidException if it's invalid and returns an HTTP response of 400 (Bad Request).
        return ResponseEntity.ok("Data is valid");
    }   
}

最后,如果您希望使用自定义逻辑来处理验证错误,而不是仅仅发送400,则可以创建自定义验证处理程序方法。

代码语言:javascript
运行
复制
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public Map<String, String> handleValidationException(MethodArgumentNotValidException e) {
    Map<String, String> errors = new HashMap<>();
    d.getBindingResult().getAllErrors().forEach((error) -> {
        String fieldName = ((FieldError) error).getField();
        String errorMessage = error.getDefaultMessage();
        errors.put(fieldName, errorMessage);
    });

    return errors;
}
票数 0
EN

Stack Overflow用户

发布于 2019-12-02 10:36:47

也许编写自定义注释和使用Spring将对您有所帮助。春季AOP很简单。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58991908

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档