天天看點

使用Validator做SpringMVC的驗證架構 - 自定義驗證元件

章節清單

  1. 第一章:使用Validator做SpringMVC的驗證架構 - 配置SpringMVC環境
  2. 第二章:使用Validator做SpringMVC的驗證架構 - 使用Validator
  3. 第三章:使用Validator做SpringMVC的驗證架構 - Validator前端驗證
  4. 第四章:使用Validator做SpringMVC的驗證架構 - 自定義驗證元件

前面的幾章已經為大家簡單的介紹了Validator的功能已經使用方法,下面接着為大家介紹怎麼使用Validator自定義驗證元件

Validator架構源碼位址:https://github.com/devefx/validator

1 - 建立背景驗證元件

大家可能發現了,我們前面的注冊功能少了一個很重要的參數,那就是驗證碼。衆所周知驗證是為了防止機器人惡意注冊的,這一步的驗證是需要與伺服器進行資料互動的驗證,不是簡單資料格式判斷就能知道正誤的。下面我讓大家看看Validator架構強大的擴充性

首先修改一下register.jsp,在“個人首頁”下面添加一個”驗證碼“

<tr>
                    <td>個人首頁:</td>
                    <td><input name="homepage"></td>
                </tr>
                <!-- 驗證碼輸入框 -->
                <tr>
                    <td>驗證碼:</td>
                    <td><input name="code" placeholder="請輸入1234"></td>
                </tr>
           

接着我們建立一個“com.devefx.website.validator.constraints”包用來放我們自定義的背景驗證元件,同時建立一個java源碼檔案“CodeValidator”作為驗證碼驗證元件。

CodeValidator.java

package com.devefx.website.validator.constraints;

import java.io.IOException;
import java.io.Writer;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import com.devefx.validation.annotation.BindScript;
import com.devefx.validation.constraints.FieldValidator;
import com.devefx.validation.kit.StrKit;
import com.devefx.validation.script.JavaScript;

/**
 * 自定義驗證碼驗證器.
 */
public class CodeValidator extends FieldValidator {

    private final String sessionKey;

    public CodeValidator(String field, String sessionKey, String errorCode, String errorMessage) {
        super(field, errorCode, errorMessage);
        this.sessionKey = sessionKey;
    }

    @Override
    public boolean isValid(HttpServletRequest request) throws Exception {
        String value = request.getParameter(field);
        // 如果是空,就交個NotEmptyValidator元件
        if (!StrKit.isEmpty(value)) {
            HttpSession session = request.getSession();
            // 為了講解友善(實際項目中可不能這麼幹),我直接把‘1234’當做正确的驗證碼
            return value.equals(/*session.getAttribute(sessionKey)*/"1234");
        }
        return true;
    }
}
           

好了,這樣一個背景驗證元件就開發完成了,接着我們就在RegisterValidator.java中使用吧

RegisterValidator.java

package com.devefx.website.validator;

import com.devefx.validation.Validator;
import com.devefx.validation.constraints.impl.EmailValidator;
import com.devefx.validation.constraints.impl.EqualFieldValidator;
import com.devefx.validation.constraints.impl.LengthValidator;
import com.devefx.validation.constraints.impl.MobileValidator;
import com.devefx.validation.constraints.impl.NotBlankValidator;
import com.devefx.validation.constraints.impl.URLValidator;
import com.devefx.website.validator.constraints.CodeValidator;

public class RegisterValidator extends Validator {
    @Override
    public void setup() {
        // 使用者名驗證
        add(new NotBlankValidator("username", "username", "使用者名不能為空"));
        add(new LengthValidator("username", , , "username", "使用者名長度限制6至20位"));
        // 密碼驗證
        add(new NotBlankValidator("password", "password", "密碼不能為空"));
        add(new LengthValidator("password", , , "password", "密碼長度限制6至20位"));
        add(new EqualFieldValidator("password_safe", "password", "password_safe", "兩次密碼不一緻"));
        // 手機号驗證
        add(new NotBlankValidator("phoneno", "phoneno", "手機号不能為空"));
        add(new MobileValidator("phoneno", "phoneno", "請輸入正确的手機号"));
        // 郵箱驗證
        add(new NotBlankValidator("email", "email", "郵箱不能為空"));
        add(new EmailValidator("email", "email", "請輸入正确的郵箱"));
        // 個人首頁驗證
        add(new URLValidator("homepage", "homepage", "請輸入正确的首頁位址"));
        // 驗證碼驗證
        add(new NotBlankValidator("code", "code", "驗證碼不能為空"));
        add(new CodeValidator("code", "registerCode", "code", "請輸入正确的驗證碼"));
    }
}
           

我們啟動項目試驗一下吧,首先我們輸入一個錯誤的驗證碼

使用Validator做SpringMVC的驗證架構 - 自定義驗證元件

我們可以發現Validator這時候并沒有幫我們立即驗證驗證碼是否正确

使用Validator做SpringMVC的驗證架構 - 自定義驗證元件

上面的圖可以看出:隻有在其他參數正确的情況下,并進行送出的時候才開始檢查出驗證碼有誤,這是因為我們隻為他編寫了背景驗證碼,而沒有前台驗證器的時候實際上分成了兩批驗證。

2 - 編寫前端驗證元件代碼

前端驗證器元件也遵循統一規範,首先我們建立一個“com.devefx.website.validator.constraints.js”包,再建立一個CodeValidator.js檔案

CodeValidator.js

function CodeValidator(field, sessionKey, errorCode, errorMessage) {
    FieldValidator.apply(this, [field, errorCode, errorMessage]);
    this.isValid = function (request, control) {
        var value = request.getParameter(field);
        if (!isEmpty(value)) {
            // 使用異步
            control.async();
            // ajax異步請求
            $.ajax({
                url: "/module/code", // 驗證接口通路位址
                type: "post", // 請求方式
                data: {"sessionKey": sessionKey, "code": value},
                success: function (result) {
                    // 根據接口傳回結果再同步到驗證器
                    if (result == "success") {
                        return control.sync(true);
                    }
                    control.sync(false);
                }
            });
        }
        return true;
    };
}
           

第一行聲明了一個函數,此函數名稱必須與需要綁定的Java驗證元件名稱相同,參數含義與Java驗證元件的構造函數相同

第二行代碼是js中繼承的實作,我們同樣繼承FieldValidator

第三行實作了驗證方法。

isValid(request[, control]) 方法

參數 說明
request 用來擷取請求的參數值
control 可選,當此驗證需要異步執行的時候,用來擷取控制權

參數

request

  類型:Request

  Request提供getParameter(name)方法,可以通過input的name擷取input的value

control

  類型:Object

  提供async、sync(valid)兩個方法,async擷取到控制權;sync(valid)交還控制權同時告知驗證結果

我們可以看到上面定義是前端驗證器需要/module/code接口的支援。

我們在“com.devefx.website”包裡面建立一個Java源碼

ValidatorController.java

package com.devefx.website.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.devefx.validation.ConstraintValidator;
import com.devefx.website.validator.constraints.CodeValidator;

@Controller
@RequestMapping("/module")
public class ValidatorController {
    /**
     * 檢測驗證碼是否輸入正确
     * 
     * @param sessionKey 會話中驗證碼對應的key
     * @return String
     */
    @ResponseBody
    @RequestMapping(value="/code", method=RequestMethod.POST)
    public String codeValidate(HttpServletRequest request,
            @RequestParam("sessionKey") String sessionKey) {
        try {
            ConstraintValidator validator = new CodeValidator("code", sessionKey, null, null);
            // 如果驗證通過
            if (validator.isValid(request)) {
                return "success";
            }
        } catch (Exception e) {
            // ignore
        }
        return "fail";
    }
}
           

注意:上面的sessionKey,我們是為了友善登入、注冊共用才保留的,你們可以根據實際情況決定是否使用

3 - 為背景驗證元件實作并、綁定前端驗證元件

我們修改一下CodeValidator.java檔案,給他實作Script接口,并綁定前端元件

CodeValidator.java

package com.devefx.website.validator.constraints;

import java.io.IOException;
import java.io.Writer;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import com.devefx.validation.Script;
import com.devefx.validation.annotation.BindScript;
import com.devefx.validation.constraints.FieldValidator;
import com.devefx.validation.kit.StrKit;
import com.devefx.validation.script.JavaScript;

/**
 * 自定義驗證碼驗證器.
 */
@BindScript("com/devefx/website/validator/constraints/js/CodeValidator.js")
public class CodeValidator extends FieldValidator implements Script {

    private final Script script;
    private final String sessionKey;

    public CodeValidator(String field, String sessionKey, String errorCode, String errorMessage) {
        super(field, errorCode, errorMessage);
        this.sessionKey = sessionKey;
        script = JavaScript.create(this, field, sessionKey, errorCode, errorMessage);
    }

    @Override
    public boolean isValid(HttpServletRequest request) throws Exception {
        String value = request.getParameter(field);
        // 如果是空,就交個NotEmptyValidator元件
        if (!StrKit.isEmpty(value)) {
            HttpSession session = request.getSession();
            // 為了講解友善(實際項目中可不能這麼幹),我直接把‘1234’當做正确的驗證碼
            return value.equals(/*session.getAttribute(sessionKey)*/"1234");
        }
        return true;
    }

    public void output(Writer out) throws IOException {
        script.output(out);
    }
}
           

通過@BindScript注解将前端驗證元件綁定給背景驗證元件,同時實作Script接口用來輸出前端調用代碼

4 - 注冊自定義元件

做完上面的步驟,我們已經到最後一步了,打開Config.java檔案

Config.java

package com.devefx.website.validator.config;

import com.devefx.validation.web.config.Modules;
import com.devefx.validation.web.config.Routes;
import com.devefx.validation.web.config.ValidatorConfig;
import com.devefx.website.validator.RegisterValidator;
import com.devefx.website.validator.constraints.CodeValidator;

public class Config implements ValidatorConfig {

    public void configModules(Modules modules) {
        // 這裡可以添加自定義驗證元件

        // 注冊自定義元件
        modules.add(CodeValidator.class);
    }

    public void configRoute(Routes routes) {
        // 這裡配置驗證器的通路路線

        // 設定基準路徑
        routes.setBasePath("/validator");

        // 注冊驗證器
        routes.add("/registerValidator.js", RegisterValidator.class);

    }

}
           

大功告成,重新開機一下項目來看看效果吧。

使用Validator做SpringMVC的驗證架構 - 自定義驗證元件

可以看到我們自定義的驗證元件已經能立即進行驗證了。

5 - 後語

上面我隻為大家介紹了一種自定義驗證元件,大家應該還能想到更多用法。

比如:使用者名是否重名驗證、必須登陸驗證、通路權限驗證等等。

基本上Validator全部的功能我已經接受完畢,由于是第一次寫部落格教程,或許很多地方介紹的不夠詳細,如果大家有什麼不明白之處可以通過下面的評論功能或者加入【Java技術交流群】