5、Spring技术栈-客户端、服务端数据验证

来源:互联网 发布:关闭淘宝手机验证 编辑:程序博客网 时间:2024/06/02 06:44

在做应用开发的过程中,在涉及到表单提交的地方,例如注册和登录时,往往都会涉及到要对输入的数据进行验证,验证数据的合法性和格式等。本文我们就以博客系统用户注册为例来说说用户注册时在客户端和服务端我们该怎么验证数据的合法性。

首先我们需要说明一下我们提交注册信息时的一个需求,当提交注册信息时,我们希望后台验证必填项是否填写,邮箱和密码格式是否正确,如果提交的数据不能达到要求,那么返回每个字段的错误消息,然后我们根据返回的错误消息提示用户,这里需要注意的是,我们并不希望后台返回给客户端的就是一串提醒的文字,我们希望的是后台返回给我一个错误码或者是一个key,然后我们根据返回的错误码或者key,在客户端显示具体的错误信息和提醒信息。

这样做有个好处就是根据错误码或者key读取客户端资源文件的内容进行提示,如果什么时候提醒文字需要变更,我们就不需要重启Tomcats或者服务,直接更新客户端资源文件,刷新页面即可。

1、服务端数据验证

服务端数据验证目前最优雅的方式应该就是用Annotations 给类或者类的属性加上约束(constraint),在运行时验证数据的方法了。而在Spring MVC中,本身是没有校验功能的,但是它可以使用hibernate-validator框架来实现服务端数据验证的功能,同时整合也非常简单,只需要配置hibernate-validator的依赖即可。

在系统的父级模块blog的pom.xml文件中加入如下依赖(本实例使用6.0.2.Final版本):

<dependency>    <groupId>org.hibernate</groupId>    <artifactId>hibernate-validator</artifactId>    <version>${hibernate_validator_version}</version></dependency>

用户注册时我们需要验证的内容包括登录名、密码、邮箱,验证码的验证我们后续在说。

所以在我们blog_domain模块中,我们在BlogUserBase类的需要验证的属性上分别加上注解。

@NotBlank(message="common.validate.notblank")private String userLoginName;@Length(min=6,max=12,message="common.validate.psw.length")private String userLoginPassword;@NotBlank(message="common.validate.notblank")@Email(message="common.validate.email")private String userEmail;

其中userLoginName加的注解表示登录名不能为空,如果提交的数据中登录名为空,将会返回一个默认消息common.validate.notblank;

userLoginPassword注解表示密码长度大于等于6小于等于12,当密码长度不在这个范围内会返回默认消息common.validate.psw.length;

userEmail注解表示必须为Email格式且不能为空,如果为空则返回默认消息common.validate.notblank,如果不符合邮箱格式则返回common.validate.email。

关于hibernate-validator更多的注解及内容说明请参考http://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#validator-defineconstraints-spec

给实体属性加完注解之后,在注册信息提交的Controller方法中,我们需要给具体的对象加上@Valid注解,同时增加BindingResult参数,加上之后的映射方法如下:

@ResponseBody@RequestMapping(value="/submitRegister",method=RequestMethod.POST)public Resp submitRegister(@Valid BlogUserBase user,BindingResult result,HttpServletRequest request){    if (result.hasErrors()) {        return new Resp(ResCode.VALIDATE_FAILED, result.getFieldErrors());    }else{        return new Resp(ResCode.SUCCESS, "");    }}

我们的注册信息通过Ajax提交,提交之后无论是验证成功或者失败,这些信息都会以Json的格式返回到客户端。所以在映射方法之前我们需要加上@ResponseBody注解,加上这个注解之后,所返回的对象就会通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区返回到客户端。而我们在 4、Spring技术栈-验证码发送功能中已经说过消息转换器的配置,这里就不在赘述了。

在客户端,当点击“立即提交”按钮之后,我们通过Ajax的方式提交表单内容,如果验证成功,我们显示验证成功,如果验证失败,我们在每个字段的后面增加Tip提示,我们需要达到如下效果:

这里写图片描述

要到到以上效果,我们有很多种方法可以实现,第一,我们可以根据返回的数据,一个一个判断返回的消息和字段,然后显示提示:

$.ajax({    type:"POST",    url:"user/submitRegister",    data:$("#register-form").serialize(),    success: function(data){        switch(data.resCode){            case '00':                //注册成功                layer.msg("验证成功");                break;            case '03':{                //验证失败                var jsonData=data.data;                $(jsonData).each(function(i){                var obj=jsonData[i];                var field=obj.field;                var msg =obj.defaultMessage;                if(field=='userLoginName' && msg=='common.validate.notblank'){                    layer.tips("必填项不能为空", "input[name='"+ field +"']", {                            tipsMore: true                    });                }   ... 很多判断 ...                });            }                break;            default:                break;            }        },        error:function(msg){            layer.msg('注册失败,请稍后重试', {icon: 5,anim:6});        }});return false;});

这样做虽然已经能够达到我们的目的,但是这样做有一个弊端,就是如果有很多属性需要验证的话,那么就需要写非常多的if{}else{}判断,很麻烦。那有没有一种方法能够在后台返回属性和消息之后,我根据消息然后通过js去读取预先设定好属性文件里面的内容来直接在对应的输入框后面显示提示呢。

2、jquery.i18n.properties.min.js的使用

在客户端,有没有一种方法能够像Java那样,能够读取一个.properties的资源文件,然后通过类似于Java解析资源文件并获取内容的方法来读取资源文件的内容,答案当然是可以的。这就是我们这里要说的jquery.i18n.properties.min.js的使用。

jQuery.i18n.properties是一款轻量级的jQuery国际化插件,能实现Web前端的国际化,当然我们这里不需要实现国际化,但是我们可以借助这个插件来读取.properties文件,然后读取其中的内容来实现我们的功能。

首先需要在页面中引入jquery.i18n.properties.min.js文件,然后调用初始化方法初始化数据。

我们在\WEB-INF\views\include目录下新建一个i18nMsg.jsp,然后将所有关于jquery.i18n的方法和内容都写在这里面。

<script type="text/javascript" src="js/jquery.i18n.properties.min.js"></script><script type="text/javascript">jQuery.i18n.properties({ name: 'messages', path: 'resources/i18n/', mode: 'map', language: 'zh', cache: false, encoding: 'UTF-8'});function i18nMsg(key){return jQuery.i18n.prop(key);}</script>

jQuery.i18n.properties初始化方法中,我们需要提供.properties文件存放的目录(path),语言(language)等信息,我们这里设置成中文(zh)就行,注意设置成zh,那么在资源文件目录下就需要新建一个messages_zh.properties的文件。

我们这里将资源文件放在\webapp\resources\i18n目录下,我们新建messages_zh.properties和messages.properties两个资源文件,messages.properties是因为您在初始化时设置的name为messages,所以您必须要有一个messages.properties,但是这个文件的内容可以为空,因为具体使用的是messages_zh.properties中的内容。

这样的话,关于jQuery.i18n.properties的引入基本上就完毕了,那么接下来我们看看怎么用,因为我们在做数据验证时,所返回的消息在bean的属性注解中已经设置,如userLoginName如果为空我们就返回common.validate.notblank这个消息,那么我们就以返回的这些消息为key,在messages_zh.properties设置内容,所以在messages_zh.properties文件中写入如下内容。

common.validate.notblank=必填项不能为空common.validate.psw.length=请填写612位密码common.validate.email=请输入正确格式的邮箱

然后在需要使用到读取内容的页面,我们直接使用jsp:include标签把他包含进去就可以了,在注册页面中,我们将i18nMsg.jsp这个文件包含进来。

<jsp:include page="../include/i18nMsg.jsp"/>

然后在Ajax提交表单时,消息返回时,我们就不必一个一个去判断,直接通过返回的消息作为key,直接调用i18nMsg(key)读取内容显示即可。

$.ajax({    type:"POST",    url:"user/submitRegister",    data:$("#register-form").serialize(),    success: function(data){        switch(data.resCode){            case '00':                //注册成功                layer.msg("验证成功");                break;            case '03':{                //验证失败                var jsonData=data.data;                $(jsonData).each(function(i){                var obj=jsonData[i];                var field=obj.field;                var msg =obj.defaultMessage;                layer.tips(i18nMsg(msg), "input[name='"+ field +"']", {                        tipsMore: true                });                 });            }                break;            default:                break;            }        },        error:function(msg){            layer.msg('注册失败,请稍后重试', {icon: 5,anim:6});        }});return false;});

3、LayerUI客户端验证

以上我们说了服务端的验证以及验证信息返回如何提示用户,那么在数据提交到服务器之前,我们也可以先做一道验证,为什么已经有服务端验证了还需要做客户端验证呢,因为客户端验证,可以很快的反应给客户,客户能够及时的做修正,同时客户端验证通过之后的提交的数据一般不会出现太大的问题,能够减少用户的操作和提高数据的有效性。

同时在系统并发量很大的情况下,在客户端对数据做校验,能够在数据提交到服务器之前过滤掉一部分非法数据和非法提交操作,能够很有效的阻止过多的非有效提交并减少服务器压力。

在我们Blog系统所使用的前端框架LayerUI中,该框架提供了很好的前端验证功能,在需要验证的input标签上加上lay-verify属性即可,如需要验证一个必填项,则可以按照下面的做法实现:

<input type="text" name="userLoginName" lay-verify="required" autocomplete="off" placeholder="请输入登录名称" class="layui-input">

更多关于LayerUI客户端验证的功能,可以参考http://www.layui.com/doc/element/form.html,这里只做推荐,不做具体的详细介绍。

具体使用请到GitHub下载源码。

项目源码:https://github.com/Ron-Zheng/blog-system

原创粉丝点击