SpringMVC学习系列-后记 结合SpringMVC和Hibernate-validator,根据后台验证规则自动生成前台的js验证代码
在SpringMVC学习系列(6) 之 数据验证中我们已经学习了如何结合Hibernate-validator进行后台的数据合法性验证,但是通常来说后台验证只是第二道保险,为了更好的用户体验会现在前端进行js验证,验证通过之后数据才能提交到后台,那么我们不可避免的要在前端的页面中写对应的js验证代码。
但是这样就需要进行一些很麻烦且重复的操作:
1.首先要保证前端和后台的验证规则要相同,避免出现前端验证通过,提交后又出现验证失败的情况。
2.其次要保证前端和后台的验证规则要同步,即修改一边的验证规则后要修改另一边对应的验证规则。
3.要保证错误提示信息的一致和相应的国际化问题。(其实这个问题在js验证代码中提示错误信息的地方,绑定国际化信息可以解决,只是比较啰嗦。)
好吧~~~以上这些都不是主要原因,主要原因是我太懒了不想在每个页面中再一个一个写对应的js验证代码,那么如何才能让后台根据我们定义的模型验证规则自动生成前端的js验证代码呢?
下面一步一步来:
首先我想像spring mvc的form标签一样<form:form modelAttribute="contentModel" method="post">,这样指定一下就可以生成对应的前端代码,简洁优雅,多爽!,那么我们就要先自定义taglib标签。
1.添加一个类,这里就叫JsValidateTag,我是定义在com.demo.test包下面的。
2.在WebContent/WEB-INF目录下面添加一个xml文件,我这里名称叫test.tld内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0"> <description>Test</description>
<tlib-version>1.0</tlib-version>
<short-name>test</short-name>
<uri>http://www.mytest.org/tags/test</uri> <tag>
<description></description>
<name>jsValidate</name>
<tag-class>com.demo.test.JsValidateTag</tag-class>
<body-content>empty</body-content>
<attribute>
<description>Path to property for data binding</description>
<name>modelAttribute</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag> </taglib>
上面的内容很简单,就是定义了一个叫jsValidate的标签,对应的类是com.demo.test.JsValidateTag就是我们之前新建的那个,然后有一个叫modelAttribute的参数。
3.接下来在我们新建的类里面实现具体的处理逻辑,代码如下:
package com.demo.test; import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.jsp.JspException;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;
import org.hibernate.validator.constraints.Range;
import org.springframework.web.servlet.tags.form.AbstractFormTag;
import org.springframework.web.servlet.tags.form.TagWriter; /**
*
* 自动生成前台js验证代码
* @author liukemng@sina.com
*
*/
@SuppressWarnings("serial")
public class JsValidateTag extends AbstractFormTag {
@SuppressWarnings("unused")
private TagWriter tagWriter;
private String modelAttribute; public void setModelAttribute(String modelAttribute) {
this.modelAttribute = modelAttribute;
} public String getModelAttribute() throws JspException {
String resolvedModelAttribute = (String) evaluate("modelAttribute", this.modelAttribute);
return (resolvedModelAttribute != null ? resolvedModelAttribute : "");
} @Override
protected int writeTagContent(TagWriter tagWriter) throws JspException {
Object model;
if(getRequestContext().getModel()!=null)
model=getRequestContext().getModel().get(getModelAttribute());
else
model=this.pageContext.getRequest().getAttribute(getModelAttribute());
if(model!=null){
Map<String, List<String[]>> fieldValidateMap=new HashMap<String, List<String[]>>(); try {
Field[] theFields=model.getClass().getDeclaredFields();
if(theFields!=null&& theFields.length>0){
for(Field field : theFields){
String fieldName=field.getName();
List<String[]> fieldValidateList=new ArrayList<String[]>();
NotEmpty notEmpty=field.getAnnotation(NotEmpty.class);
if(notEmpty!=null){
String messageName=notEmpty.message();
fieldValidateList.add(new String[]{"required","true",getRequestContext().getMessage(messageName.substring(1, messageName.length()-1))});
} Email email=field.getAnnotation(Email.class);
if(email!=null){
String messageName=email.message();
fieldValidateList.add(new String[]{"email","true",getRequestContext().getMessage(messageName.substring(1, messageName.length()-1))});
} Range range=field.getAnnotation(Range.class);
if(range!=null){
String messageName=range.message();
fieldValidateList.add(new String[]{"range","["+range.min()+","+range.max()+"]",getRequestContext().getMessage(messageName.substring(1, messageName.length()-1))});
} if(fieldValidateList.size()>0){
fieldValidateMap.put(fieldName, fieldValidateList);
}
}
}
}catch (SecurityException e1) {
e1.printStackTrace();
} if(fieldValidateMap.size()>0){
StringBuilder rulesBuilder=new StringBuilder();
StringBuilder messagesBuilder=new StringBuilder(); rulesBuilder.append("rules:{");
messagesBuilder.append("messages:{"); int i=0;
Iterator<Entry<String, List<String[]>>> iterator=fieldValidateMap.entrySet().iterator();
while(iterator.hasNext()){
Entry<String, List<String[]>> entry=iterator.next();
rulesBuilder.append(entry.getKey()).append(":{");
messagesBuilder.append(entry.getKey()).append(":{"); int j=0;
for(String[] array : entry.getValue()){
rulesBuilder.append(array[0]).append(":").append(array[1]);
messagesBuilder.append(array[0]).append(":\"").append(array[2]).append("\""); if(j<entry.getValue().size()-1){
rulesBuilder.append(",");
messagesBuilder.append(",");
}
j++;
} rulesBuilder.append("}");
messagesBuilder.append("}"); if(i<fieldValidateMap.size()-1){
rulesBuilder.append(",");
messagesBuilder.append(",");
}
i++;
} rulesBuilder.append("},");
messagesBuilder.append("}");
tagWriter.startTag("script");
tagWriter.writeAttribute("type", "text/javascript");
tagWriter.appendValue("$(function() {");
tagWriter.appendValue("$(\"#");
tagWriter.appendValue(getModelAttribute());
tagWriter.appendValue("\").validate({");
//在失去焦点时验证
tagWriter.appendValue("onfocusout:function(element){$(element).valid();},");
tagWriter.appendValue(rulesBuilder.toString());
tagWriter.appendValue(messagesBuilder.toString());
tagWriter.appendValue("});");
tagWriter.appendValue("});");
tagWriter.endTag(true);
}
} this.tagWriter=tagWriter;
return EVAL_BODY_INCLUDE;
} @Override
public void doFinally() {
super.doFinally();
this.tagWriter = null;
}
}
4.接下来在页面中引用我们自定义的标签:
<%@ taglib prefix="test" uri="http://www.mytest.org/tags/test" %>
并指定模型名称:
<test:jsValidate modelAttribute="contentModel"></test:jsValidate>
页面整体内容如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="test" uri="http://www.mytest.org/tags/test" %> <html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script src="<c:url value='/js/jquery-1.10.2.min.js'/>" type="text/javascript"></script>
<script src="<c:url value='/js/jquery.validate.min.js'/>" type="text/javascript"></script>
</head>
<body>
<form:form modelAttribute="contentModel" method="post"> <form:errors path="*"></form:errors><br/><br/> name:<form:input path="name" /><br/>
<form:errors path="name"></form:errors><br/> age:<form:input path="age" /><br/>
<form:errors path="age"></form:errors><br/> email:<form:input path="email" /><br/>
<form:errors path="email"></form:errors><br/> <input type="submit" value="Submit" /> </form:form>
</body>
<test:jsValidate modelAttribute="contentModel"></test:jsValidate>
</html>
好了运行测试看看效果吧:

啊哈哈哈哈哈~~~,已经生成好了~~~
注:以上的代码只实现了@NotEmpty、@Range、@NotEmpty三个注解对应的js验证规则,其它注解的js验证规则在JsValidateTag类中添加相应的逻辑即可。
项目源码下载:http://pan.baidu.com/s/1c0pVzFy
SpringMVC学习系列-后记 结合SpringMVC和Hibernate-validator,根据后台验证规则自动生成前台的js验证代码的更多相关文章
- SpringMVC学习系列-后记 解决GET请求时中文乱码的问题
SpringMVC学习系列-后记 解决GET请求时中文乱码的问题 之前项目中的web.xml中的编码设置: <filter> <filter-name>CharacterEnc ...
- SpringMVC学习系列-后记 开启项目的OpenSessionInView
在系列的 SpringMVC学习系列(12) 完结篇 的示例项目中,由于当时考虑到OpenSessionInView会对性能有一定的影响,所以就没有配置项目的OpenSessionInView.在ma ...
- SpringMVC学习系列(11) 之 表单标签
本篇我们来学习Spring MVC表单标签的使用,借助于Spring MVC提供的表单标签可以让我们在视图上展示WebModel中的数据更加轻松. 一.首先我们先做一个简单了例子来对Spring MV ...
- SpringMVC学习系列(6) 之 数据验证
在系列(4).(5)中我们展示了如何绑定数据,绑定完数据之后如何确保我们得到的数据的正确性?这就是我们本篇要说的内容 —> 数据验证. 这里我们采用Hibernate-validator来进行验 ...
- SpringMVC学习系列 之 表单标签
http://www.cnblogs.com/liukemng/p/3754211.html 本篇我们来学习Spring MVC表单标签的使用,借助于Spring MVC提供的表单标签可以让我们在视图 ...
- SpringMVC学习系列- 表单验证
本篇我们来学习Spring MVC表单标签的使用,借助于Spring MVC提供的表单标签可以让我们在视图上展示WebModel中的数据更加轻松. 一.首先我们先做一个简单了例子来对Spring MV ...
- springmvc学习笔记--ueditor和springmvc的集成
前言: 在web开发中, 富文本的编辑器真心很重要. 有电商店铺的打理, 新闻稿/博客文章/论坛帖子的编辑等等, 这种所见即所的编辑方式, 大大方便了非技术人员从事互利网相关的工作. 因为手头有个小项 ...
- springmvc学习笔记---idea创建springmvc项目
前言: 真的是很久没搞java的web服务开发了, 最近一次搞还是读研的时候, 想来感慨万千. 英雄没落, Eclipse的盟主地位隐隐然有被IntelliJ IDEA超越的趋势. Spring从2. ...
- SpringMVC学习(三)———— springmvc的数据校验的实现
一.什么是数据校验? 这个比较好理解,就是用来验证客户输入的数据是否合法,比如客户登录时,用户名不能为空,或者不能超出指定长度等要求,这就叫做数据校验. 数据校验分为客户端校验和服务端校验 客户端校验 ...
随机推荐
- 适合于小团队产品迭代的APP测试流程
一.测试周期 测试周期一般为2~3天,根据项目情况以及版本质量可适当缩短或延长测试时间.正式测试前先向主管或产品经理确认项目排期. 二.测试资源 测试任务开始前,检查各项测试资源. 产品功能需求文档. ...
- Objective-C 语法之 static 关键字
转:http://www.apkbus.com/android-593-1.html 学习过Java 或者 C 语言的朋友应该很清楚static关键字吧?在某个类中声明一个static 静态变量, 其 ...
- DNS劫持
忽然发现我最喜欢的chrome 一直有广告,好些论坛都有大量的广告,原以为是重了什么插件了,找了也没发现,有可能是DNS劫持. 打开路由器,找到 dns 设置里面把里面的全部去掉.然后把 192.16 ...
- Android 图片的裁剪与相机调用
有时候我们需要的图片并不适合我们想要的大小, 那么我们就可以用到系统自带的图片裁剪功能, 把规定范围的图像给剪出来. 贴上部分代码: //调用图库 Intent intent = new Intent ...
- BZOJ 4726: [POI2017]Sabota? 树形dp
4726: [POI2017]Sabota? 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=4726 Description 某个公司有n ...
- IOS中的网络编程
在移动互联网时代,几乎所有应用都需要用到网络下载,比如图片的加载,音乐的下载,安装包的下载,等等,下面我们来看看如何进行下载 一.文件的下载我们用get来请求数据,并对请求的二进制数据进行解析存入文件 ...
- c++标准库
Technical Report 1不是正式的库只是一个草案,作为C++ 2003标准的附加库被大多数编译器厂商所支持,它是个过渡性质的库,其实现将会作为C++11标准的一部分.很多编译器对C++11 ...
- Discuz!开发手册
如何使用Discuz开发手册? 1.首先建议你了解Discuz目录结构-全局篇 通过对目录结构的了解,会在以后的创作道路上提供坚实的基础! 2.你还需要了解Discuz! X3.1数据字典 3.创建自 ...
- dubbo 2.5.4-SNAPSHOT dubbo-admin 报错
问题描述: RROR context.ContextLoader - Context initialization failed org.springframework.beans.factory.B ...
- 提高 Android 代码质量的4个工具
在这篇文章中,我将通过不同的自动化工具如CheckStyle,FindBugs,PMD以及Android Lint来介绍(如何)提高你的安卓代码质量.通过自动化的方式检查你的代码非常有用,尤其当你在一 ...