在開發Java Web程式時,前後校驗邏輯應該是必不可少的一部分。其中,前台校驗更多地是從使用者體驗的角度出發,而背景校驗更多地是從資料安全的角度出發。本博文基于Spring MVC寫了一個前台背景結合校驗的示例,不過沒有使用Spring MVC自帶的校驗架構。示例前台使用Jquery Validation進行校驗,背景使用Hibernate Validation進行校驗,是以示例所需要的校驗邏輯并不依賴于Spring MVC,隻要引入相應的校驗包,即可在任何Java Web環境中實作校驗功能。(使用Spring MVC自帶校驗邏輯進行校驗,改天有空再寫個示例)
如果Jquery Validation使用不熟悉的話,可以檢視我的Jquery Validation實用示例及講解
如果Hibernate Validation使用不熟悉的話,可以檢視我的Hibernate Validation使用示例及講解
下面直接上示例代碼:
一、主要依賴
jquery.validate.js
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.3.Final</version>
</dependency>
二、背景Controller類
該類隻是模拟注冊功能,并有一個使用者名是否存在判斷邏輯,主要是為了展現前背景校驗的用法,是以沒寫其它邏輯,實際情況肯定比這複雜得多。
/**
* 注冊控制器
* @author wdmcygah
*
*/
@Controller
@RequestMapping("/register")
public class RegisterController {
/**
* 注冊頁面展示
*/
@RequestMapping("/show")
public String register(){
return "/register/show";
}
/**
* 注冊方法(主要為了示範使用Hibernate validation進行校驗)
*/
@RequestMapping(value="/create",method=RequestMethod.POST)
public String doRegister(RegisterInfo info,Model model){
//1、進行參數校驗(這裡省略名字重複校驗,隻示範相關用法)
ValidationResult result = ValidationUtils.validateEntity(info);
if( result.isHasErrors() ){
model.addAttribute("errorMsg", result.getErrorMsg());
return "/register/show";
}
//2、注冊邏輯——省略
model.addAttribute("successFlag", "1");
return "/register/show";
}
/**
* 判斷使用者名是否存在
* 較長的描述:
* 1、這裡隻作簡單的示範,若名稱以y開頭則傳回不存在。實際運用中可能是查詢資料庫
* 2、注意這裡用到@ResponseBody注解,表示傳回值不是視圖名,直接将傳回值綁定到response body中
* @param name
* @return
*/
@RequestMapping(value="isNameExists",method=RequestMethod.POST)
@ResponseBody
public String isNameExists( String name ){
if( StringUtils.isEmpty(name) ){
return "false";
}
//隻有以'y'開頭的名字才是不存在的
if( name.startsWith("y") ){
return "true";
}
return "false";
}
}
三、背景校驗工具類
該類對Hibernate Validation方法進行了簡單封裝,實作校驗實體對象的功能,傳回是自定義的校驗對象。
/**
* 校驗工具類
* @author wdmcygah
*
*/
public class ValidationUtils {
private static Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
public static <T> ValidationResult validateEntity(T obj){
ValidationResult result = new ValidationResult();
Set<ConstraintViolation<T>> set = validator.validate(obj,Default.class);
if( CollectionUtils.isNotEmpty(set) ){
result.setHasErrors(true);
Map<String,String> errorMsg = new HashMap<String,String>();
for(ConstraintViolation<T> cv : set){
errorMsg.put(cv.getPropertyPath().toString(), cv.getMessage());
}
result.setErrorMsg(errorMsg);
}
return result;
}
}
四、背景校驗結果類
/**
* 校驗結果
* @author wdmcygah
*
*/
public class ValidationResult {
//校驗結果是否有錯
private boolean hasErrors;
//校驗錯誤資訊
private Map<String,String> errorMsg;
public boolean isHasErrors() {
return hasErrors;
}
public void setHasErrors(boolean hasErrors) {
this.hasErrors = hasErrors;
}
public Map<String, String> getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(Map<String, String> errorMsg) {
this.errorMsg = errorMsg;
}
@Override
public String toString() {
return "ValidationResult [hasErrors=" + hasErrors + ", errorMsg="
+ errorMsg + "]";
}
}
五、背景被校驗對象
/**
* 注冊資訊
* @author wdmcygah
*
*/
public class RegisterInfo {
@NotBlank(message="名字不能為空或者空串")
private String name;
@NotBlank(message="密碼不能為空或者空串")
@Pattern(regexp="(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{5,10}",message="密碼必須是5~10位數字和字母的組合")
private String password;
@NotBlank(message="郵箱不能為空或者空串")
@Email(message="郵箱格式不正确")
private String email;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
六、前台注冊頁面
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html >
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!-- Bootstrap -->
<link href="<%=request.getContextPath()%>/statics/css/bootstrap.min.css" target="_blank" rel="external nofollow"
rel="stylesheet">
<!-- 這裡引入的是校驗提示的樣式 -->
<link href="<%=request.getContextPath()%>/statics/css/valid.css" target="_blank" rel="external nofollow"
rel="stylesheet">
</head>
<body>
<div class="container">
<form action="create.htm" method="post" id="registerForm"
class="form-horizontal" role="form">
<fieldset class="text-center">
<legend> 前背景校驗功能測試頁面 </legend>
<c:choose>
<c:when test="${successFlag=='1'}">
注冊成功!
<button type="button" class="btn btn-primary btn-large"
οnclick="window.location.href='show.htm' ">傳回</button>
</c:when>
<c:otherwise>
<div class="form-group">
<label class="col-sm-4 control-label" for="name">姓名</label>
<div class="col-sm-4">
<input type="text" class="form-control" name="name" id="name">
</div>
<label class="error" for="name">${errorMsg.name}</label>
</div>
<div class="form-group">
<label class="col-sm-4 control-label" for="password">密碼</label>
<div class="col-sm-4">
<input type="password" class="form-control" name="password"
id="password">
</div>
<label class="error" for="password">${errorMsg.password}</label>
</div>
<div class="form-group">
<label class="col-sm-4 control-label" for="email">電子郵箱</label>
<div class="col-sm-4">
<input type="text" class="form-control" name="email" id="email">
</div>
<label class="error" for="email">${errorMsg.email}</label>
</div>
<div class="form-actions ">
<button type="submit" class="btn btn-primary btn-large">送出</button>
<button type="reset" class="btn">取消</button>
</div>
</c:otherwise>
</c:choose>
</fieldset>
</form>
</div>
<!-- js -->
<script
src="<%=request.getContextPath()%>/statics/js/import/jquery-1.11.1.js"></script>
<script
src="<%=request.getContextPath()%>/statics/js/import/jquery.validate.js"></script>
<script
src="<%=request.getContextPath()%>/statics/js/import/bootstrap.min.js"></script>
<!-- 這裡引入的是校驗提示資訊的JS檔案 -->
<script
src="<%=request.getContextPath()%>/statics/js/import/messages_zh.js"></script>
<!-- 這裡引入的是表單校驗的JS檔案 -->
<script
src="<%=request.getContextPath()%>/statics/js/my/register_validation.js"></script>
<!-- 這裡引入的是擴充Jquery validation的自定義JS檔案 -->
<script
src="<%=request.getContextPath()%>/statics/js/my/additional-methods.js"></script>
</body>
</html>
七、前台校驗JS
這裡主要介紹下validate方法中的remote,後面跟的是一個ajax請求,判斷名字是否存在,背景隻用傳回“true”或者“false”,表示校驗是否通過就行了。這個在表單異步校驗的時候非常實用。
$(function() {
$('#registerForm').validate({
rules : {
name : {
required : true,
remote : {
url : "isNameExists.htm", //背景處理程式
type : "post", //資料發送方式
data : { //要傳遞的資料
name : function() {
return $("#name").val();
}
}
}
},
password : {
required : true,
},
email : {
required : true,
email : true
}
},
messages:{
name:{
remote:"名字已經存在"
}
},
success : "valid",
errorClass : "error",
errorPlacement : function(error, element) {
error.appendTo(element.parent().parent());
}
});
});
這裡限于篇幅,隻展示了主要邏輯代碼,若想檢視完整源碼,可以檢視我的Github倉庫:https://github.com/wdmcygah/research-spring。其中倉庫裡面有些與本博文不相關的代碼,注意區分。
代碼在JDK1.8、chrome浏覽器下測試通過。測試通路位址:http://localhost:8080/spring/register/show.htm,如果想完全地測試背景校驗,需要把文中的JS校驗方法注釋掉,或者把浏覽器的JS禁用。