星期五, 5月 04, 2007

Spring Framework 筆記 (五)

寫 Web Form 程式在以往最麻煩的地方就是 Form Validation 部份。早期都只能透過 Javascript 來做 client 端的 validation,但是 Javascript 驗證的缺點就是不好維護,而且要做到 reuse 也相對是比較難一些;Spring 在 Form Validation 方面也提供了一套 validcation 的機制,可以輕鬆的達到 Form Validcation。

 

我們使用一個註冊的 Form 來做例子,提供一個 Register Form 讓使用者可以輸入要申請的帳號以及密碼 (得要輸入兩次以便驗證兩次是否都一樣),而申請的帳號如果是 "jacky",就秀出已經註冊過的訊息;若是密碼兩次輸入不一樣,同樣也會秀出密碼不一樣的錯誤訊息。

 

Form HTML 為:

 

<html xmlns="http://www.w3.org/1999/xhtml">

<head>
<meta http-equiv="Content-Language" content="zh-tw" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled 1</title>
</head>

<body>

<form method="post" action="register.do">
<table>
<tr>
<td>account:</td>
<td><input name="login" type="text" /></td>
</tr>
<tr>
<td>Password:</td>
<td><input name="passwd" type="password" /></td>
</tr>
<tr>
<td>Password Again:</td>
<td><input name="passwd2" type="password" /></td>
</tr>

<tr>
<td><input name="Submit1" type="submit" value="Register" /></td>
<td></td>
</tr>
</table>
</form>

</body>

</html>

延伸之前例子的 Member Java Bean,多加入了 passwd2 以及 email attribute。

 



package com.esolution.Model;

public class Member {

private String login;
private String passwd;

private String passwd2;

private String email;

public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getPasswd() {
return passwd;
}
public void setPasswd(String passwd) {
this.passwd = passwd;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPasswd2() {
return passwd2;
}
public void setPasswd2(String passwd2) {
this.passwd2 = passwd2;
}


}

修改 URL Mapping 的設定:


<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/hello.htm">


springappController


</prop>


<prop key="/login.do">


springappSimpleFormController


</prop>
<prop key="/register.do">


memberRegisterController


</prop>
</props>
</property>
</bean>


 


 接著因為我們需要 spring 將 form 上面的欄位資料跟 JavaBean binding 在一起,所以需要 spring taglib 來做 data binding:


 


 


<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %>
<%@ taglib prefix="spring" uri="/spring" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
<meta http-equiv="Content-Language" content="zh-tw" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled 1</title>
</head>

<body>


<spring:bind path="command.*">
<font color="red">

<c:forEach items="${status.errorMessages}" var="error">
<strong><c:out value="${error}"/></strong><br>
</c:forEach>

</font>
</spring:bind>


<form method="post" action="register.do">
<spring:bind path="command">
<table>
<tr>
<td>account:</td>
<td><input name="login" type="text" value="<c:out value='${command.login}'/>"/></td>
</tr>
<tr>
<td>Password:</td>
<td><input name="passwd" type="password" value="<c:out value='${command.passwd}'/>"/></td>
</tr>
<tr>
<td>Password Again:</td>
<td><input name="passwd2" type="password" value="<c:out value='${command.passwd2}'/>"/></td>
</tr>
</spring:bind>


<tr>
<td><input name="Submit1" type="submit" value="Register" /></td>
<td></td>
</tr>
</table>
</form>


</body>


</html>


在上面 JSP Code 中 spring:bind tag 分成兩個部分,錯誤訊息顯示以及 data binding。spring data binding 會使用一個 Command Class 來存 data,而該 command class default 的名稱是 command;例如在上面的例子就是使用 spring:bind tag 將 login、passwd、passwd2 三個 form 欄位跟 Command class binding 在一起 (該 Command class 的名稱叫做 command):若是使用者的輸入驗證沒通過 command.login 、command.passwd、command.passwd2 都會秀出之前使用者輸入的值。至於錯誤訊息顯示的部分 spring 會把錯誤資訊放在 status 變數中。


接著要撰寫 validator 程式:


package com.esolution.Validator;

import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import com.esolution.Model.*;

public class RegisterValidator implements Validator {

public boolean supports(Class clazz) {
return Member.class.isAssignableFrom(clazz);
}

public void validate(Object obj, Errors errors) {
Member member = (Member)obj;
if("jacky".equalsIgnoreCase(member.getLogin())){
errors.rejectValue("login", "existed",null,"The Account is existed");
}

if(! member.getPasswd().equals(member.getPasswd2())){
errors.rejectValue("passwd2", "passwordNotMatch",null, "Passwords does not match");
}

}

}


 Validator 程式主要是要 implemtn Validator  Interface,實做 supports 以及 validate methods:supports 主要是要判別傳進來的 class 參數是否是 Member 或繼承自 Member 的 class;validate method 主要是根據使用者在 form 上面輸入的值來做 validate;在上述程式中我們判斷兩個:一個是假設如果輸入的 login 欄位資料是 jacky,就秀出該帳號已經存在的訊息;若是兩次輸入的密碼不一樣,就秀出密碼不一致的訊息。


rejectValue method 資料如下:


void rejectValue(String field,
String errorCode,
Object[] errorArgs,
String defaultMessage)



field - the field name (may be null or empty String)
errorCode - error code, interpretable as a message key
errorArgs - error arguments, for argument binding via MessageFormat (can be null)
defaultMessage - fallback default message

 

修改 controller 的設定:(加入 validator、formView、commandClass、successView 資料) <bean id="memberRegisterController" class="com.esolution.Controller.MemberRegisterController">
<property name="formView">
<value>register</value>
</property>
<property name="commandClass">
<value>com.esolution.Model.Member</value>
</property>

<property name="successView">
<value>success</value>
</property>

<property name="validator">
<bean class="com.esolution.Validator.RegisterValidator"/>
</property>
</bean>

 



沒有留言: