前后端参数校验统一处理方案

9,085 阅读6分钟

前端参数校验方案

前言

因为我自身是后端大数据平台开发的,因为前端资源比较缺,所以做了全栈开发工程师。前端技术方案选择了比较简单和容易入门的vue,基础组件使用ele的基础组件,图标类的就是v-chart,echart,g2,g6都用,图表类的使用顺序优先级也是从前往后的。下面我给出相关的技术框架的链接,供大家参考。

表单校验

我们经常有一些需求,就是前端在向后端提交请求的时候,需要对提交的表单的字段进行校验,比如表名或者名字字段,不能为空,最大不能超过多少字符等这种需求,这种需求后端也要做校验,前端为了有一个好的体验,也是要做校验的,省的用户辛辛苦苦填了那么久的信息,到最后废掉了,还要通过后端接口来看参数不合法的信息,体验不好。

表单组件我们基本是使用ele的表单组件,用起来简单,也支持表单校验功能,但往往我们的需求远比官网提供的例子要复杂的多,下面我总结了几个需求要注意的地方,也就是参数校验容易不生效的地方:

  • form没有绑定rules,form的model和参数里面的对象绑定不一致。
  • form里记得要填写ref,关联该form,然后在提交的函数里记得要写this.$refs['form'].validata((valid)=>{});这样,如果不写的话,即使校验失败,还是会向后提交请求的。
  • 如果表单里的要校验的字段没有提前定义好,或者是整个对象直接复制给form,这里也容易不生效或者不准确的问题,这里特别要注意赋值和深拷贝。

参数校验体验优化

在开发前端过程中,有时候出现了输入框重新赋值后,老的校验结果还在,以至于体验很不好,通过其他操作,前端代码改变赋值,而不是界面操作改变赋值的,这时候change和blur事件都触发不到,老的校验结果还赤裸裸的展示在那里。举个例子:

我们在建表的时候要求表名不能为空,我们设置的校验时间是blur(后来发现设置成change效果一样),我们不输入任何东西,然后离开,这是表名不能为空的校验是生效的,如下图所示:

image
我们点击右上角的DDL建表,在里面输入一段sql之后,点击解析,解析成功之后,会把解析出来的值覆盖到表单里面的表名和字段名,此时注意,表名的字段里的值此时是符合我们的规则的,但是上次的校验结果还在,用户还需要把鼠标放在输入框里,然后离开输入框点击一下,才会重新触发校验,这样的用户体验超级不好。
image
所以要研究如何解决这个问题,功夫不负有心人,研究ele的api的时候,其实是有相关的api的,可以清除上次的校验结果。
image
image

解决方案

如上图所示,clearValidate就是清除表单项的上次校验结果,这里使用参数的,大家用的时候要记住,如果直接调用this.$refs['form'].clearValidate()是清楚表单项所有表单项的上次校验结果,如果只需要清楚特定表单项的老的校验结果,需要将要清除的表单项名字集合填进去即可。比如我会重新给库名和表名赋值,只需要除楚这二个表单项的旧的校验结果即可。

后端参数校验方案

后端开发我们使用springBoot或者springMvc进行开发的,也需要对参数进行校验,比如修改的时候id不为空啊,名称不能为空等,虽然这些靠前端可以保证一些,但是别人也可以绕过前端,直接请求你的后端接口,故意将参数穿的不规范,来破坏你的系统,将你的磁盘用日志打满等各种操作。因为即使在前端已经使用参数校验进行了限制,为了严谨性,还是需要在后端做参数校验的。当然可以在代码中针对每个参数进行代码校验,不为空啊,要大于0啊,字符串长度限制啊,后来就会发现只是参数校验代码就会几百行了,严重影响了业务逻辑,而且在不同的方法里面可能还会有重复的代码等。针对这种问题,我们可以使用基于注解的方式进行参数校验。

注解的范围看个人习惯,如果你的service是只提供给controller使用,没有对外提供rpc服务,那么你的参数校验层在controller层完全没有问题,但是如果你的service服务如果有对外提供rpc服务,也可以考虑将校验加载service的接口上,这样更能保证代码的健壮性。

后端参数分为二种,单个基本类型的包装类,比如Long id,String name这种;还有一种是自定义对象TableApproveBO,我们可能需要该对象里面的某些值进行校验。下面分别为大家介绍:

单个基本类型的包装类进行校验

注意二点:需要在类上方加上validated注解,然后在对应的方法处加上校验规则即可。如下图所示:

image
image

自定义对象的校验

自定义对象可能用在不同的场景,校验规则不一样,比如新增申请单的时候要求id可以为null,但是修改申请单的时候就必须要求修改的申请单的id不能为空,但是二者又是使用的同一个业务对象,这时候我们就是需要使用分组校验了。具体步骤如下:

定义校验分组

  • 首先我们要定义为了分组校验所使用的分组,其实就是一些空的接口。
    image
  • 然后在业务对象上定义校验规则和校验规则所生效的分组,如果不定义分组,则默认所有分组都生效。
    image
  • 最后在需要校验的方法上去加上校验所使用的分组,然后参数校验规则就会生效了。
    image
  • 为了给前端一个友好的提示,需要对参数校验不满足抛出的异常进行统一的处理,使不满足的规则具有易读性,大家可以看到我针对参数校验抛出的异常定义了二个异常处理器,因为不同的参数校验框架,跑出的异常不一样,而且抛出异常里面封装的对象格式不一样。因为我使用了多个参数校验框架,原生的validate-api抛出的是ConstraintViolationException,但是其支持的校验的规则有限,比如针对字符串只支持notNull,但是我们其实想的是NotEmpty,就是不仅仅是null,还不能是空字符串。这之后就要使用spring或者hibernate扩展的校验,这时候每个框架校验抛出的异常就不一样,需要做不同的处理。
    image

遗留问题

还有一种情况就是自定义对象内的二个字段相互依赖校验这种情况,当前还没有合适的方案,就是a字段的校验逻辑依赖于b字段的取值,这种校验需求我还是放在代码里面作为逻辑的的一部分进行校验,还没找到更好的校验方案,如果大家又比较好的方案,可以一起分享。 字段a取值为1的时候,b值必须为空,字段a取值为0的时候,b值不能为空,就是这种校验,欢迎大家一起探讨。