在struts中,当用户在action表中中配置了validate属性为true时(默认为true), struts在用户提交的数据封装到ActionForm中后(这个Form会存到action标签的scope属性所指定的容器中,名称为form-bean标签中指定的name属性名)会自动对这些数据进行校验,负责这部分操作的函数是
ActionErrors validate(ActionMapping mapping, HttpServletRequest request) ,
此函数返回一个ActionErrors对象,当这个对象为空时,说明校验成功,要是这个对象不为空,则说明校验失败。开发者可以在这个function中天剑相应的校验代码,ActionErrors封装了相关错误属性的错误信息。要是校验失败,则会返回到Input指定的页面,否则会调用ActionServlet查找到的对应Action进行下一步操作。
在Struts中,对表单数据校验时,对错误信息的显示是可以通过errors标签来回显:回显方式如下
<html:errors property="xxx" />
proterty是指定对应表单相关属性的错误信息。其原理是当检验遇到有些不合格的信息时,将会创建一个ActionErrors的对象,并将此错误信息封装到其中,而这个ActionErrors将被添加到pageContex域中,之后在显示错误信息时,会从此域中获取此ActionErrors对象,并从中解析出对应属性的错误信息。
只的注意的是,ActionServlet在用用户提交的数据填充UserFormBean对象前(即调用bean相关set方法),会先调用actionForm的reset方法,因此可以用此方法来清空对应的FormBean对象。
下面是手动编写的一个UserFormBean
userFormBean
package cn.itcast.web.formbean;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;
import org.apache.commons.beanutils.locale.converters.DateLocaleConverter;
import cn.itcast.global.Gender;
import cn.itcast.global.Interest;
public class UserFormBean extends ActionForm {
private String username;
private String password;
private String password2;
private String gender; //request上传过来的所有参数类型都将是String类型
private String emails;
private String birthday;
private String[] interest;//爱好,对应可以选择多种,request上传过来的是一个数组
private String city;
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPassword2() {
return password2;
}
public void setPassword2(String password2) {
this.password2 = password2;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getEmails() {
return emails;
}
public void setEmails(String emails) {
this.emails = emails;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
public String[] getInterest() {
return interest;
}
public void setInterest(String[] interest) {
this.interest = interest;
}
@Override
public ActionErrors validate(ActionMapping mapping,
HttpServletRequest request) {
// TODO Auto-generated method stub
ActionErrors ae = new ActionErrors();
if(isEmpty(this.username)){
addErrorMessage(ae, "username", "用户名不能为空");
}else if(!this.username.matches("[a-zA-Z]{3,9}")){
//3-8位字母
addErrorMessage(ae, "username", "用户名需要为3-8为字母");
}
if(isEmpty(this.password)){
addErrorMessage(ae, "password", "密码不能为空");
}
if(isEmpty(this.password2) || !this.password2.equals(this.password)){
addErrorMessage(ae, "password2", "密码两次输入不一致");
}
if(isEmpty(this.gender)){
addErrorMessage(ae, "gender", "性别不能为空,请选择性别");
}else{
try{
//判断一个枚举是否有效,可以通过将此值强转成此枚举型,要是不是会暴异常
Gender.valueOf(this.gender.toUpperCase());
}catch(Exception e){
addErrorMessage(ae, "gender", "请选择有效的性别");
}
}
if(isEmpty(this.emails)){
addErrorMessage(ae, "emails", "邮箱不能为空");
}else{
if(!this.emails.matches("\\w+@\\w+(\\.+\\w+)+")){
addErrorMessage(ae, "emails", "邮箱格式不对");
}
}
if(isEmpty(this.birthday)){
addErrorMessage(ae, "birthday", "生日不能为空");
}else{
try{
DateLocaleConverter convert = new DateLocaleConverter();//通过此转化器,将字符串形式的日期YYYY-MM-DD转化成Date,要是格式不对,会暴异常
convert.convert(this.birthday);
}catch(Exception e){
addErrorMessage(ae, "birthday", "生日格式无效");
}
}
if(interest==null || interest.length==0){
addErrorMessage(ae, "interest", "请选择您所感兴趣的东西");
}else{
for(String in : interest){
try{
Interest.valueOf(in.toUpperCase());
}catch(Exception e){
addErrorMessage(ae, "interest", "请选择您所感兴趣的东西");
}
}
}
if(isEmpty(this.city)){
addErrorMessage(ae, "city", "请选择您所感兴趣的东西");
}
return ae;
}
private boolean isEmpty(String value){
if(value==null || value.trim().equals("")){
return true;
}
return false;
}
private void addErrorMessage(ActionErrors ae, String key, String message){
ActionMessage am = new ActionMessage(message, false);
ae.add(key, am);
}
}
Register.jsp 是注册显示页面,此页面涉及到数据回显等内容。数据回显包含两部分,一部分是提交校验单本身输入的内容回显,可以利用UserFormBean对象(它是由ActionServlet创建的ActionForm对象,封装了用户提交的数据,并存在action标签的scop属性指定的域中)来进行回显。另一部分是校验的错误提示信息回显,此部分内容可以由<html:errors>标签来完成。
<%@page import="cn.itcast.global.Interest"%>
<%@page import="cn.itcast.global.Location"%>
<%@page import="cn.itcast.global.Gender"%>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>注册页面</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/Register.do" method="post">
用户名: <input type="text" value="${UserFormBean.username }" name="username" />
<html:errors property="username" /> <br />
密码: <input type="password" name="password" />
<html:errors property="password" /><br />
确认密码: <input type="password" name="password2" />
<html:errors property="password2" /><br />
性别: <c:forEach var="g" items="<%=Gender.values() %>">
<input type="radio" name="gender" value="${g.name }"
${UserFormBean.gender==g.name?'checked':'' }/>${g.value }
</c:forEach>
<html:errors property="gender" /> <br />
邮箱: <input type="text" name="emails" value="${UserFormBean.emails }" />
<html:errors property="emails" /> <br />
生日: <input type="text" name="birthday" value="${UserFormBean.birthday }"/>
<html:errors property="birthday" /><br />
爱好:<c:forEach var="int" items="<%=Interest.values() %>">
<input type="checkbox" name="interest" value=${int.name }
${fn:contains(fn:join(UserFormBean.interest, ","), int.name)?'checked':''}/>${int.value }
</c:forEach>
<html:errors property="interest" /><br />
居住城市: <select name="city" >
<option value=" " selected="selected">请选择居住城市</option>
<c:forEach var="c" items="<%=Location.values() %>">
<option value="${c.name }" ${UserFormBean.city==c.name?'selected':''}>
${c.value }
</option>
</c:forEach>
</select>
<html:errors property="city" /><br />
<input type="submit" value="注册" />
</form>
</body>
</html>
这个jsp页面在显示性别及爱好时,采用了一些相对较好的方法。它没有将jsp中相关爱好写死,而是通过配置相关文件(这里是枚举类)来填写相关爱好,这样就可以保证当爱好发生变化时,jsp页面无需修改。如上代码,通过枚举类的values()方法可以获取到这个类的所有枚举值,枚举也是一个类,下面是定义的几个类:
package cn.itcast.global;
public enum Gender {
MALE("male", "男"), FEMALE("female", "女");
private String name;
private String value;
private Gender(String name, String value){
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
package cn.itcast.global;
public enum Interest {
SING("sing", "唱歌"),
DANCE("dance", "跳舞"),
BASKBALL("baskball", "篮球"),
FOOTBALL("football", "足球");
private String name;
private String value;
private Interest(String name, String value){
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
package cn.itcast.global;
public enum Location {
BEIJING("beijing", "北京"),
GUANZHOU("guangzhou", "广州"),
SHANGHAI("shanghai", "上海"),
SHENZHENG("shenzheng", "深圳");
private String name;
private String value;
private Location(String name, String value){
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
对于jsp显示页面中的表单标签,struts框架也提供了一个Form标签,如:<html:form>,使用此标签相对于html标签来说有一下几点好处:
1.不用编写${pageContext.request.contextPath}来指定context路径
2.指定的action不用带".do"后缀
此标签会生成一个html的form标签代码,同时也会将UserFormBean对象以key值org.apache.struts.taglib.html.BEAN存到pageContext域中,这样在表单数据回显时,会从此表单中提取对应属性的值。
针对上面使用scriptlet标签来回显表单数据,struts提供了相关标签:
<html:text property="xx" /> ------> <input type="text" name="xxx" />
<html:password property="xxx" /> ----><input type="password" name="xxx"/>
<html:radio>
<html:checkbox>
<html:mul
<html:select property="xxx" /> -----> <select name="xxx" >
<html:textarea property="xxx" /> -----> <textarea name="xxx" >
等标签,这些标签功能除了相当于scriptlet对应标签功能外,还具有回显相关数据功能。
因此上面jsp代码,可以用下面的代码替换:
<%@page import="cn.itcast.global.Interest"%>
<%@page import="cn.itcast.global.Location"%>
<%@page import="cn.itcast.global.Gender"%>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>注册页面</title>
</head>
<body>
<html:form action="/Register" >
用户名: <html:text property="username" />
<html:errors property="username" /> <br />
密码: <html:password property="password" redisplay="false"/>
<html:errors property="password" /><br />
确认密码: <html:password property="password2" redisplay="false"/>
<html:errors property="password2" /><br />
性别: <c:forEach var="g" items="<%=Gender.values() %>">
<html:radio property="gender" value="${g.name }" />${g.value }
</c:forEach>
<html:errors property="gender" /> <br />
邮箱: <html:text property="emails" />
<html:errors property="emails" /> <br />
生日: <html:text property="birthday"/>
<html:errors property="birthday" /><br />
爱好:<c:forEach var="int" items="<%=Interest.values() %>">
<html:multibox property="interest" value="${int.name }" />${int.value }
</c:forEach>
<html:errors property="interest" /><br />
居住城市: <html:select property="city" >
<html:option value=" ">请选择居住城市</html:option>
<c:forEach var="c" items="<%=Location.values() %>">
<html:option value="${c.name }">${c.value }</html:option>
</c:forEach>
</html:select>
<html:errors property="city" /><br />
<html:submit value="注册" /><html:reset value="清空" />
</html:form>
</body>
</html>