当前位置: 首页 > news >正文

jquery validate表单校验_SpringValid优雅校验入参

作者 | 阿呆很呆非常呆

来源 | urlify.cn/Jraqea

一、简介

  后台业务入口类Controller,对于入参的合法性校验,可以简单粗暴的写出一堆的 if 判断,如下:

@RestController@RequestMapping("user")public class UserController {    @PostMapping("saveUser")    public String saveUser(UserInfoVo userInfoVo){        if(StrUtil.isBlank(userInfoVo.getUserName())){            return "userName is not null";        }        if(StrUtil.isBlank(userInfoVo.getPwd())){            return "pwd is not null";        }        return "save success";    }}

二、重要说明

   2.1、springboot在2.3之后,spring-boot-starter-web的依赖项已经去除了validate依赖,推荐导入依赖:

                 org.springframework.boot            spring-boot-starter-validation        

   2.2、关于 @Valid 和 @Validated

    @Validated 是Spring Validation验证框架对JSR-303规范的一个扩展, javax提供@Valid 是标准的JSR-303规范。使用基本无区别,但是在Group分组使用上还是使用 @Validated方便。

    嵌套验证上,必须在待验证的vo中的嵌套实体属性上增加@Valid。

三、实验出真知

  3.1、牛刀小试

    定义VO,在需要校验的字段上加上相应注解

@Datapublic class UserInfoVo {    @NotBlank(message = "userName is not null")    private String userName;    @NotNull(message = "age is not null")    private Integer age;    @NotBlank(message = "pwd is not null")    private String pwd;}

   Controller入参加上@Valid、校验结果BindingResult:

@RestController@RequestMapping("user")public class UserController {    @PostMapping("saveUser")    public String saveUser(@Valid UserInfoVo userInfoVo, BindingResult bindingResult){        if(bindingResult.hasErrors()){            return bindingResult.getAllErrors().get(0).getDefaultMessage();        }        return "save success";    }}

  通过工具访问,可看到如果入参不符合,会有相应message返回

8a82ec7030b0e6ec7518e577dc8fce67.png

以上就完成了一个最简单的优雅校验过程,其中内置常用校验类型:

空检查@Null       验证对象是否为null@NotNull    验证对象是否不为null, 无法查检长度为0的字符串@NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.@NotEmpty 检查约束元素是否为NULL或者是EMPTY. Booelan检查@AssertTrue     验证 Boolean 对象是否为 true @AssertFalse    验证 Boolean 对象是否为 false  长度检查@Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内 @Length(min=, max=) Validates that the annotated string is between min and max included.  日期检查@Past       验证 Date 和 Calendar 对象是否在当前时间之前 @Future     验证 Date 和 Calendar 对象是否在当前时间之后 @Pattern    验证 String 对象是否符合正则表达式的规则 数值检查,建议使用在Stirng,Integer类型,不建议使用在int类型上,因为表单值为“”时无法转换为int,但可以转换为Stirng为"",Integer为null@Min            验证 Number 和 String 对象是否大等于指定的值 @Max            验证 Number 和 String 对象是否小等于指定的值 @DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度@DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度@Digits     验证 Number 和 String 的构成是否合法 @Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。@Range(min=, max=) Checks whether the annotated value lies between (inclusive) the specified minimum and maximum.@Range(min=10000,max=50000,message="range.bean.wage")private BigDecimal wage; @CreditCardNumber信用卡验证@Email  验证是否是邮件地址,如果为null,不进行验证,算通过验证。@ScriptAssert(lang= ,script=, alias=)@URL(protocol=,host=, port=,regexp=, flags=)

  3.2、第一次改版

  入参很多的情况下,可能会同时产生多个不同的错误校验,那么如果每次只是返回一个错误提示,每次客户端改一个,那么体验是极差的。基于此,封装返回类,提供统一返回。

@Data@NoArgsConstructor@RequiredArgsConstructorpublic class ResponseData {    @NonNull    private Integer code;    @NonNull    private String message;    private T data;    public static ResponseData success() {        return new ResponseData(HttpStatus.OK.value(), "SUCCESS");    }    public static ResponseData success(Object data) {        ResponseData entity = success();        entity.setData(data);        return entity;    }    public static ResponseData fail(Integer code, String msg) {        return new ResponseData(code, msg);    }    public static ResponseData fail(Integer code, String msg, Object data) {        ResponseData entity = fail(code, msg);        entity.setData(data);        return entity;    }}
@RestController@RequestMapping("user")public class UserController {    @PostMapping("saveUser")    public ResponseData saveUser(@Valid UserInfoVo userInfoVo, BindingResult bindingResult){        if(bindingResult.hasErrors()){            List collect = bindingResult.getFieldErrors().stream().map(item -> item.getDefaultMessage()).collect(Collectors.toList());            return ResponseData.fail(900, "req param invalid", collect);        }        return ResponseData.success();    }}

  3.3、第二次改版

    上述改版,已经能够一次性的返回所有未校验通过异常,但是,每个方法中都这么来一遍,还是挺麻烦的。下面利用统一异常处理参数校验,改造完成后Controller中专注于业务处理即可

@RestController@RequestMapping("user")public class UserController {    @PostMapping("saveUser")    public ResponseData saveUser(@Valid UserInfoVo userInfoVo){        return ResponseData.success();    }}@RestControllerAdvicepublic class GlobalExceptionHandler {    private static final Integer BAD_REQUEST_CODE = 900;    private static final String BAD_REQUEST_MSG = "req param invalid";    @ExceptionHandler(BindException.class)    public ResponseData bindExceptionHandler(BindException exception){        List collect = exception.getAllErrors().stream().map(item -> item.getDefaultMessage())                .collect(Collectors.toList());        return ResponseData.fail(BAD_REQUEST_CODE, BAD_REQUEST_MSG, collect);    }    @ExceptionHandler(Exception.class)    public ResponseData exceptionHandler(Exception exception){        return ResponseData.fail(500, exception.getMessage());    }}

  3.4、分组校验

  通常,存在场景:name参数在注册接口必须非空,但是修改接口无所谓。那么此时,分组group很好解决问题

/** * @author cfang 2020/9/23 10:47 * * 关于 extends Default * 继承 Default 的话,所有定义校验规则的都会校验 * 不继承的话,则只校验加了group信息的校验字段 */public interface UserGroup extends Default{}@Datapublic class UserInfoVo {    @NotBlank(message = "userName is not null", groups = UserGroup.class)    private String userName;    @NotNull(message = "age is not null")    private Integer age;    @NotBlank(message = "pwd is not null")    private String pwd;}@RestController@RequestMapping("user")public class UserController {    @PostMapping("saveUser")    public ResponseData saveUser(@Validated({UserGroup.class}) UserInfoVo userInfoVo){        return ResponseData.success();    }    @PostMapping("updateUser")    public ResponseData updateUser(@Valid UserInfoVo userInfoVo){        return ResponseData.success();    }    @InitBinder    public void init(HttpServletRequest request, DataBinder dataBinder){        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");        dateFormat.setLenient(false); //是否校验转化日期格式,true-转化日期,false-参数错误则直接异常。eg. 2020-55-10, true->2024-10-10 , false-异常报错。默认值true        dataBinder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));    }}

  3.5、递归校验

@Datapublic class AddressInfoVo {    @NotBlank(message = "street is not null")    private String street;}@Datapublic class UserInfoVo {    @NotBlank(message = "userName is not null", groups = UserGroup.class)    private String userName;    @NotNull(message = "age is not null")    private Integer age;    @NotBlank(message = "pwd is not null")    private String pwd;    @Past(message = "predate is invalid")    @NotNull(message = "predate is not null")    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone="GMT+8")    private Date preDate;    @Valid    private AddressInfoVo infoVo;}@RestController@RequestMapping("user")public class UserController {    @PostMapping("saveUser")    public ResponseData saveUser(@Validated({UserGroup.class}) @RequestBody UserInfoVo userInfoVo){        return ResponseData.success();    }    @PostMapping("updateUser")    public ResponseData updateUser(@Valid @RequestBody UserInfoVo userInfoVo){        return ResponseData.success();    }    @InitBinder    public void init(HttpServletRequest request, DataBinder dataBinder){        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");        dateFormat.setLenient(false);        dataBinder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));    }}@RestControllerAdvicepublic class GlobalExceptionHandler {    private static final Integer BAD_REQUEST_CODE = 900;    private static final String BAD_REQUEST_MSG = "req param invalid";    @ExceptionHandler(BindException.class)    public ResponseData bindExceptionHandler(BindException exception){        List collect = exception.getAllErrors().stream().map(item -> item.getDefaultMessage())                .collect(Collectors.toList());        return ResponseData.fail(BAD_REQUEST_CODE, BAD_REQUEST_MSG, collect);    }    @ExceptionHandler(MethodArgumentNotValidException.class)    public ResponseData argInvalidExceptionHandler(MethodArgumentNotValidException exception){        List collect = exception.getBindingResult().getFieldErrors().stream().map(item -> item.getDefaultMessage())                .collect(Collectors.toList());        return ResponseData.fail(BAD_REQUEST_CODE, BAD_REQUEST_MSG, collect);    }    @ExceptionHandler(Exception.class)    public ResponseData exceptionHandler(Exception exception){        return ResponseData.fail(500, exception.getMessage());    }}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • python 双向链表_双向链表及创建(C语言)详解
  • 关于提高自己JAVA水平的十大技术讨论(转)
  • python语言格式化_python语言-字符串格式
  • 写给那些正在找工作的朋友
  • js 文件不让通过地址访问_Flask Vue.js全栈开发|第2章:通过axios访问Flask RESTful API
  • 串行接口SPI接口应用设计
  • docker compose 安装_利用docker-compose安装elasticsearch时启动失败的异常解决
  • 清华计算机系旁听有感
  • python中怎样寻找某一时间序列的极值_Python的10个基础知识点,新手必须背下来...
  • 可变长字符串以及数字与字符串的互转
  • mac mysql可视化工具_tableau 连接mysql的操作步骤
  • python pprint_Python3内置模块之pprint让打印比print更美观
  • JBoss目录结构说明和功能介绍
  • jqgrid使用本地静态数据创建网格的例子_第68集 python机器学习:网格搜索管道中的属性...
  • 探讨C#2.0对象模型
  • Android单元测试 - 几个重要问题
  • Codepen 每日精选(2018-3-25)
  • ES6 学习笔记(一)let,const和解构赋值
  • export和import的用法总结
  • JDK9: 集成 Jshell 和 Maven 项目.
  • Linux后台研发超实用命令总结
  • October CMS - 快速入门 9 Images And Galleries
  • React 快速上手 - 06 容器组件、展示组件、操作组件
  • spring + angular 实现导出excel
  • Terraform入门 - 3. 变更基础设施
  • 分享几个不错的工具
  • 规范化安全开发 KOA 手脚架
  • 前端攻城师
  • 如何胜任知名企业的商业数据分析师?
  • 一份游戏开发学习路线
  • [地铁译]使用SSD缓存应用数据——Moneta项目: 低成本优化的下一代EVCache ...
  • #etcd#安装时出错
  • (02)Cartographer源码无死角解析-(03) 新数据运行与地图保存、加载地图启动仅定位模式
  • (09)Hive——CTE 公共表达式
  • (1综述)从零开始的嵌入式图像图像处理(PI+QT+OpenCV)实战演练
  • (C语言)字符分类函数
  • (创新)基于VMD-CNN-BiLSTM的电力负荷预测—代码+数据
  • (附源码)springboot码头作业管理系统 毕业设计 341654
  • (力扣记录)1448. 统计二叉树中好节点的数目
  • (六)Flink 窗口计算
  • (十二)python网络爬虫(理论+实战)——实战:使用BeautfulSoup解析baidu热搜新闻数据
  • (原)Matlab的svmtrain和svmclassify
  • .class文件转换.java_从一个class文件深入理解Java字节码结构
  • .Family_物联网
  • .NET 跨平台图形库 SkiaSharp 基础应用
  • .net 无限分类
  • .Net7 环境安装配置
  • .net8.0与halcon编程环境构建
  • .NET版Word处理控件Aspose.words功能演示:在ASP.NET MVC中创建MS Word编辑器
  • @ 代码随想录算法训练营第8周(C语言)|Day53(动态规划)
  • @Autowired 和 @Resource 区别的补充说明与示例
  • @Bean有哪些属性
  • @GetMapping和@RequestMapping的区别
  • @NotNull、@NotEmpty 和 @NotBlank 区别
  • @selector(..)警告提示