• spring boot参数验证


    必须要知道

    • 简述 JSR303/JSR-349,hibernate validation,spring validation 之间的关系
      JSR303 是一项标准,JSR-349 是其的升级版本,添加了一些新特性,他们规定一些校验规范即校验注解,如 @Null,@NotNull,@Pattern,他们位于 javax.validation.constraints 包下,只提供规范不提供实现;
      hibernate validation 是对这个规范的实践,他提供了相应的实现,并增加了一些其他校验注解,如 @Email,@Length,@Range 等等,他们位于 org.hibernate.validator.constraints 包下;
      spring validation,是对 hibernate validation 进行了二次封装,在 springmvc 模块中添加了自动校验,并将校验信息封装进了特定的类中;

    spring mvc对spring validation的应用

    get请求 参数验证

    @RestController
    @RequestMapping("/beavalidate")
    public class BeanValidateController {
    
        @GetMapping("/testget")
        public ResultBody testGet(@Valid @NotBlank @RequestParam("name") String name){
            return ResultBody.successBody("get方式验证成功!");
        }
    }
    

    post请求 参数验证

    @RestController
    @RequestMapping("/beavalidate")
    public class BeanValidateController {
    
        @PostMapping("/testpost")
        public ResultBody testPost(@Valid  @RequestBody TagAddForm tagAddForm){
            return ResultBody.successBody("验证成功!");
        }
    }
    

    参数验证异常统一处理

    如果我们没有对验证错误进行处理,调用接口的客户端无法知道到底是什么参数发生了错误,
    还有就是如果前后端分离我们一般都是规定json格式传输数据,所以我们最好针对这个错误进行处理并返回格式化的内容。

    定义错误相关的枚举

    public interface IResult extends Serializable {
        
        Integer getCode();
    
        String getMessage();
    }
    
    public enum ResultEnum implements IResult {
        /**
         * 成功
         */
        SUCCESS(10000, "成功"),
        /**
         * 请求参数异常
         */
        ARGUMENT_EXCEPTION(10001, "请求信息异常");
    	
        private Integer code;
        private String message;
    
        ResultEnum(Integer code, String msg) {
            this.code = code;
            this.message = msg;
        }
    
        @Override
        public Integer getCode() {
            return code;
        }
    
        @Override
        public String getMessage() {
            return message;
        }
    
        public void setMessage(String message) {
            this.message = message;
        }
    }
    

    定义统一的json对象

    @Data
    public class ResultBody<T> {
        /**
         * 错误码
         */
        private Integer code;
    
        /**
         * 提示信息
         */
        private String message;
    
        /**
         * 具体数据
         */
        private T body;
    
        private ResultBody() {
    
        }
    
        /**
         * 构造成功包体
         *
         * @return 成功的包体
         */
        public static ResultBody successBody() {
            return dowith(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMessage(), new HashMap<>(1));
        }
    
        /**
         * 构造成功的包体
         *
         * @param body 包体中body的内容
         * @return 成功的包体
         */
        public static ResultBody successBody(Object body) {
            return dowith(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMessage(), body);
        }
    
        /**
         * 构造调用失败的包体
         *
         * @param result 错误码和提示信息内容
         * @return 失败的包体
         */
        public static ResultBody errorBody(IResult result) {
            return dowith(result.getCode(), result.getMessage(), new HashMap<>(1));
        }
    
        /**
         * 构造调用失败的包体
         *
         * @param result 错误码和提示信息内容
         * @param body   包体内容
         * @return 失败的包体
         */
        public static ResultBody errorBody(IResult result, Object body) {
            return dowith(result.getCode(), result.getMessage(), body);
        }
    
        /**
         * 构造调用失败的包体
         *
         * @param result 错误码和提示信息内容
         * @return 失败的包体
         */
        public static ResultBody errorBody(IResult result, String message) {
            return dowith(result.getCode(), message, null);
        }
    
        /**
         * 构造调用失败的包体
         *
         * @param result 错误码和提示信息内容
         * @param body   包体内容
         * @return 失败的包体
         */
        public static ResultBody errorBody(IResult result, Object body, String message) {
            return dowith(result.getCode(), message, body);
        }
    
    }
    
    

    定义异常处理器

    @ControllerAdvice
    public class ValidationExceptionHandler {
        
    	/**
    	 * 处理post方式参数验证异常
         * @param e 
         * @return
         */
    	@ExceptionHandler({MethodArgumentNotValidException.class})
        @ResponseBody
        public ResultBody notValidException(MethodArgumentNotValidException e) {
            log.error("API参数校验异常:{}", e);
            return this.wrapperBindingResult(e.getBindingResult());
        }
    	
    	/**
    	 * 处理get方式参数验证异常
         * @param e 
         * @return
         */
    	@ResponseBody
        @ExceptionHandler({MissingServletRequestParameterException.class})
        public ResultBody requestMissingParamsErrorHandler(MissingServletRequestParameterException e) {
            log.error("MissingServletRequestParameterException:{}", e);
            String errorMessage = e.getMessage();
            ResultEnum resultEnum = ResultEnum.ARGUMENT_EXCEPTION;
    
            return ResultBody.errorBody(resultEnum);
        }
    	
    	private ResultBody wrapperBindingResult(BindingResult bindingResult) {
            ResultEnum resultEnum = ResultEnum.ARGUMENT_EXCEPTION;
            StringBuilder errorMessage = new StringBuilder();
            if ("prod".equals(this.profile)) {
                errorMessage.append("请求信息异常");
            } else {
                Iterator var4 = bindingResult.getFieldErrors().iterator();
    
                while(var4.hasNext()) {
                    FieldError fieldError = (FieldError)var4.next();
                    errorMessage.append(fieldError.getField()).append(fieldError.getDefaultMessage()).append(";");
                }
            }
    
            resultEnum.setMessage(errorMessage.toString());
            return ResultBody.errorBody(resultEnum);
        }
    }
    

    效果

    • get方式参数验证

    • post方式参数验证:

    非mvc环境下使用验证

    在一些情况下我们并不是只是验证http请求参数的绑定,我们还需要java方法之间调用的参数验证。
    不适用验证框架我们一般都是手动验证,但是手动验证是很费力的,下面就介绍一下在非mvc的情况下使用spring validation框架进行验证。

    手动验证

    定义bean添加验证注解

    
    @Data
    public class TagAddForm {
    
        @NotEmpty(message = "标签名称不能为空")
        private String name;
    
        @Min(value = 1,message = "标签类型不能为空")
        private int type;
    
    }
    

    编写手动验证逻辑

    @Component
    public class TagValidate {
    
    
        /**
         * 验证bean的参数
         * <p>
         *     手动验证
         * </p>
         */
        public void validateBean(){
            TagAddForm tagAddForm=new TagAddForm();
            ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
            Validator validator = factory.getValidator();
            Set<ConstraintViolation<TagAddForm>> violations = validator.validate(tagAddForm);
            //为空代表验证通过
            if (violations.size()==0){
                return;
            }
            for(ConstraintViolation<TagAddForm> violation: violations) {
                System.out.println((violation.getMessage()));
            }
        }
    
    
    }
    
    

    单元测试

    @SpringBootTest
    @RunWith(SpringRunner.class)
    public class TestValidate {
        @Autowired
        private TagValidate tagValidate;
        @Autowired
        private UserValidate userValidate;
    
        @Test
        public void test(){
            tagValidate.validateBean();
        }
    }
    

    结果:

    自动验证

    业务类编写

    在类上添加注解:@Validated 在方法上添加:@Valid注解

    import org.springframework.stereotype.Component;
    import org.springframework.validation.annotation.Validated;
    
    import javax.validation.Valid;
    
    @Validated
    @Component
    public class UserValidate {
    
        public void add(@Valid TagAddForm tagAddForm){
            System.out.println("添加标签");
        }
    }
    

    测试

    @SpringBootTest
    @RunWith(SpringRunner.class)
    public class TestValidate {
        @Autowired
        private UserValidate userValidate;
    
    
        @Test
        public void test2(){
             //new一个 TagAddForm对象作为参数并没有为其赋值
            TagAddForm tagAddForm=new TagAddForm();
            userValidate.add(tagAddForm);
        }
    }
    

    结果

  • 相关阅读:
    Redis 详解 (一) StackExchange.Redis Client
    redis在.net架构中的应用(1)--利用servicestack连接redis
    .NET中使用Redis:http://www.cnblogs.com/yangecnu/p/Introduct-Redis-in-DotNET.html
    SQL Server日期函数总结
    SQL Server 日期和时间函数
    16Aspx源码论坛
    方差和偏差的区别
    写在中秋节的前?秒
    装系统那些事儿-1-电脑的启动流程
    查找重复的数
  • 原文地址:https://www.cnblogs.com/wangsen/p/11671941.html
Copyright © 2020-2023  润新知