SpringMVC學習系列-後記 結合SpringMVC和Hibernate-validator,根據後臺驗證規則自動生成前臺的js驗證代碼

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

 

保留版權,如需轉載請註明出處…

相關文章
相關標籤/搜索