在SpringMVC學習系列(6) 之 數據驗證中咱們已經學習瞭如何結合Hibernate-validator進行後臺的數據合法性驗證,可是一般來講後臺驗證只是第二道保險,爲了更好的用戶體驗會如今前端進行js驗證,驗證經過以後數據才能提交到後臺,那麼咱們不可避免的要在前端的頁面中寫對應的js驗證代碼。javascript
可是這樣就須要進行一些很麻煩且重複的操做:html
1.首先要保證前端和後臺的驗證規則要相同,避免出現前端驗證經過,提交後又出現驗證失敗的狀況。前端
2.其次要保證前端和後臺的驗證規則要同步,即修改一邊的驗證規則後要修改另外一邊對應的驗證規則。java
3.要保證錯誤提示信息的一致和相應的國際化問題。(其實這個問題在js驗證代碼中提示錯誤信息的地方,綁定國際化信息能夠解決,只是比較囉嗦。)jquery
好吧~~~以上這些都不是主要緣由,主要緣由是我太懶了不想在每一個頁面中再一個一個寫對應的js驗證代碼,那麼如何才能讓後臺根據咱們定義的模型驗證規則自動生成前端的js驗證代碼呢?web
下面一步一步來:spring
首先我想像spring mvc的form標籤同樣<form:form modelAttribute="contentModel" method="post">,這樣指定一下就能夠生成對應的前端代碼,簡潔優雅,多爽!,那麼咱們就要先自定義taglib標籤。mvc
1.添加一個類,這裏就叫JsValidateTag,我是定義在com.demo.test包下面的。app
2.在WebContent/WEB-INF目錄下面添加一個xml文件,我這裏名稱叫test.tld內容以下:jsp
<?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