Struts 学习笔记2(输入校验、国际化、异常处理)
项目文件结构
项目源文件下载地址:http://dl.dbank.com/c05qyg3yir
Struts2的输入校验
Struts2输入校验、执行流程:
1)首先进行类型转换
2)然后进行输入校验(执行validate方法)
3)如果在上述过程中出现了任何错误,都不会再去执行 execute方法,会转向 struts.xml 中该 action 的名为 input 的 result 所对应的页面。
要点:
1. ActionSupport 类的 addActionError()方法的实现:首先创建一个ArrayList对象,然后将错误消息添加到该 ArrayList对象中。
2. 当调用 getActionErrors()方法返回 Action 级别的错误信息列表时,返回的实际上是集合的一个副本而不是集合本身,因此对集合副本调用 clear()方法清除的依旧是副本中的元素而非原集合中的元素,此时原集合中的内容没有收到任何的影响。换句话说,Action级别的错误信息列表对开发者来说是只读的。
3. Field Error 级别的错误信息底层是用 LinkedHashMap 实现的,该Map 的 key 是 String 类型,value 是 List<String>类型,这就表示一个 Field Name 可以对应多条错误信息,这些错误信息都放置在List<String>集合当中。
register.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
………………………………
<body>
<h2><font color="blue">用户注册</font></h2>
<s:actionerror cssStyle="color:red"/>
----------------------------------------
<s:fielderror cssStyle="color:blue"></s:fielderror>
<!--
<form action="register.action">
username: <input type="text" name="username" size="20"><br>
password: <input type="password" name="password" size="20"><br>
repassword: <input type="password" name="repassword" size="20"><br>
age: <input type="text" name="age" size="20"><br>
birthday: <input type="text" name="birthday" size="20"><br>
graduation: <input type="text" name="graduation" size="20"><br>
<input type="submit" value="submit"/>
</form>
-->
<s:form action="register.action" theme="simple"><!—-加theme="simple修饰以简单表单呈现-->
username: <s:textfield name="username" label="username"></s:textfield><br>
password: <s:password name="password" label="password"></s:password><br>
repassword: <s:password name="repassword" label="repassword"></s:password><br>
age: <s:textfield name="age" label="age"></s:textfield><br>
birthday: <s:textfield name="birthday" label="birthday"></s:textfield><br>
graduation: <s:textfield name="graduation" label="graduation"></s:textfield><br>
<s:submit value="submit"></s:submit>
</s:form>
</body>
</html>
RegisterAction.java
package com.shengsiyuan.struts2;
import java.util.Calendar;
import java.util.Date;
import com.opensymphony.xwork2.ActionSupport;
public class RegisterAction extends ActionSupport
{
private String username;
private String password;
private String repassword;
private int age;
private Date birthday;
private Date graduation;
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 getRepassword()
{
return repassword;
}
public void setRepassword(String repassword)
{
this.repassword = repassword;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
public Date getBirthday()
{
return birthday;
}
public void setBirthday(Date birthday)
{
this.birthday = birthday;
}
public Date getGraduation()
{
return graduation;
}
public void setGraduation(Date graduation)
{
this.graduation = graduation;
}
@Override
public String execute() throws Exception
{
return SUCCESS;
}
@Override
public void validate()
{
if(null == username || username.length() < 4 || username.length() > 6)
{
this.addActionError("username invalid"); //Action级别的错误
this.addFieldError("username", "username invalid in field");//field级别的错误
}
if(null == password || password.length() < 4 || password.length() > 6)
{
this.addActionError("password invalid");
}
else if(null == repassword || repassword.length() < 4 || repassword.length() > 6)
{
this.addActionError("repassword invalid");
}
else if(!password.equals(repassword))
{
this.addActionError("the passwords not the same");
}
if(age < 10 || age > 50)
{
this.addActionError("age invalid");
}
if(null == birthday)
{
this.addActionError("birthday invalid");
}
if(null == graduation)
{
this.addActionError("graduation invalid");
}
if(null != birthday && null != graduation)
{
Calendar c1 = Calendar.getInstance(); //获取日期
c1.setTime(birthday);
Calendar c2 = Calendar.getInstance();
c2.setTime(graduation);
if(!c1.before(c2)) //如果c1不在c2前
{
this.addActionError("birthday should be before graduation");
}
}
//this.getFieldErrors().clear(); //clear()方法清空的只是副本
//this.getActionErrors().clear();
//this.clearActionErrors(); //清除Action级别的错误消息
//this.clearFieldErrors(); //清除field级别的错误消息
System.out.println("invoked!!!");
}
}
struts.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="struts2" extends="struts-default">
<action name="login" class="com.shengsiyuan.struts2.LoginAction" method="myExecute"> <!-- 指定执行myExecute方法 -->
<result name="success">/result.jsp</result><!-- 结果为success时,跳转到result.jsp -->
</action>
<action name="userAction" class="com.shengsiyuan.struts2.UserAction">
<result name="success">/output.jsp</result>
</action>
<action name="userAction2" class="com.shengsiyuan.struts2.UserAction2">
<result name="success">/output.jsp</result>
</action>
<action name="register" class="com.shengsiyuan.struts2.RegisterAction">
<result name="success">/registerResult.jsp</result>
<result name="input">/register.jsp</result>
</action>
</package>
</struts>
截图
提交之前截图
以html标签提交之后的截图
以struts标签,且未加theme="simple"属性提交的结果
若使用<s:form action="register.action" theme="simple">则呈现的结果同以html提交一样。不管是Action级别的,还是field级别的,在执行excute方法时,只要对应的错误容器中有错误消息,则转到input对应的页面,如果容器中没有错误消息,则继续往下执行。
----------------------------------------------------------
在tomcat中手动添加web项目:
…………
<Context path="/myWebSite" docBase="D:/Workspace/servlet/myWebSite" reloadable="true"/>
-------------------------------------------------------------
username: <input type="text" name="username"><br>
password: <input type="password" name="password"><br>
age: <input type="text" name="age"><br>
date: <input type="text" name="date"><br>
<input type="submit" value="submit">
package com.shengsiyuan.struts2;
import com.opensymphony.xwork2.ActionSupport;
import com.shengsiyuan.exception.PasswordException;
import com.shengsiyuan.exception.UsernameException;
public class LoginAction extends ActionSupport
public void setDate(Date date)
public void setUsername(String username)
public void setPassword(String password)
public String execute() throws Exception
throw new UsernameException("username invalid");
throw new PasswordException("password invalid");
//自定的execute方法,在struts.xml中指定了LoginAction中的method方法为myExecute
public String myExecute() throws Exception
System.out.println("myExecute invoked!!");
public void validateMyExecute() //此验证方法规定为将myExecute()方法名首字母大写后,再加前缀validate构成
System.out.println("validateMyExecute invoked!!");
this.addActionError("action error");
//System.out.println("validate invoked!");
//this.addActionError("action error");
注:如果去除了struts.xml文件中的method="myExecute",则对应的自定义的校验方法将无效。
<action name="login" class="com.shengsiyuan.struts2.LoginAction " method="myExecute">
<result name="success">/result.jsp</result>
1) 新建一个以 Action 名命名的 properties 文件 , 如RegisterAction.properties。 属性文件名要求为对应的Action文件名字。
2) 然后在该属性文件中指定每一个出错字段的错误消息 invalid.fieldvalue.birthday=birthday invalid !!
Tip: jdk提供的一款中文转换为unicode编码的工具,在jdk的bin目录下,native2ascii。在命令行下使用,使用方法如下:
<?xml version="1.0" encoding="UTF-8"?>
"-//OpenSymphony Group//XWork Validator 1.0.2//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
<!ELEMENT validators (field|validator)+><!—字段优先与校验器优先两种-->
<!ELEMENT field (field-validator+)>
<!ELEMENT field-validator (param*, message)>
short-circuit (true|false) "false"
<!ELEMENT validator (param*, message)>
short-circuit (true|false) "false"
<?xml version="1.0" encoding="UTF-8"?>
<field name="username"><!-- 对username设置校验规则 -->
<field-validator type="requiredstring"><!-- 字符串必填规则设置 -->
<param name="trim">false</param><!-- 不清除空格 -->
<message>username can't be blank!</message><!-- 当校验失败提示的错误消息 -->
<field-validator type="stringlength"><!-- 字符串长度规则设置 -->
<param name="minLength">4</param><!-- 最小长度 -->
<param name="maxLength">6</param><!-- 最大长度 -->
<param name="trim">false</param>
<!—读取属性文件,使用国际化,当校验失败提示的错误消息 --
<message key="username.invalid"></message>>
<field-validator type="requiredstring">
<message>password can't be blank!</message>
<field-validator type="stringlength">
<param name="minLength">4</param>
<param name="maxLength">6</param>
<message>length of password should be between ${minLength} and ${maxLength}</message>
<field-validator type="required">
<message>age can't be blank!</message>
<message>age should be between ${min} and ${max}</message>
<field-validator type="required">
<message>birthday can't be blank!</message>
<param name="min">2005-1-1</param>
<param name="max">2007-12-31</param>
<message>birthday should be between ${min} and ${max}</message>
<?xml version="1.0" encoding="UTF-8"?>
<validator type="requiredstring">
<param name="fieldName">username</param>
<message>username can't be blank!</message>
<validator type="stringlength">
<param name="fieldName">username</param>
<param name="minLength">4</param>
<param name="maxLength">6</param>
<message>length of username should be between ${minLength} and ${maxLength}</message>
<field-validator type="required">
<message>birthday can't be blank!</message>
<param name="min">2005-1-1</param>
<param name="max">2007-12-31</param>
<message>birthday should be between ${min} and ${max}</message>
打开com.opensymphony.xwork2.validator.validators可以发现一个default.xml文件,打开可以发现其中定义了各种校验器,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
"-//OpenSymphony Group//XWork Validator Config 1.0//EN"
"http://www.opensymphony.com/xwork/xwork-validator-config-1.0.dtd">
<!-- START SNIPPET: validators-default -->
<validator name="int" class="com.opensymphony.xwork2.validator.validators.IntRangeFieldValidator"/>
<validator name="email" class="com.opensymphony.xwork2.validator.validators.EmailValidator"/>
<validator name="url" class="com.opensymphony.xwork2.validator.validators.URLValidator"/>
<validator name="regex" class="com.opensymphony.xwork2.validator.validators.RegexFieldValidator"/>
<!-- END SNIPPET: validators-default -->
username.invalid=username invalid
username.invalid=\u7528\u6237\u540D\u4E0D\u5408\u6CD5\uFF01
对于国际化的资源文件,其命名规则是: package_语言名_国家名,比如package_zh_CN,package_en_US 。
public static void main(String[] args)
Locale[] locales = Locale.getAvailableLocales();
System.out.println(locale.getDisplayCountry() + " : "
+ locale.getCountry()); //显示国家及国家代码
// System.out.println(locale.getDisplayLanguage() + " : " + locale.getLanguage());
在src目录(classpath)下,建立三个资源文件,分别如下(注 i18n即为资源文件的base name):
import java.util.ResourceBundle;
public static void main(String[] args)
System.out.println(Locale.getDefault());
//绑定一个base name 为i18n的资源文件,Locale使用FRANCE(法国)
ResourceBundle bundle = ResourceBundle.getBundle("i18n", Locale.FRANCE);
String value = bundle.getString("hello");
import java.text.MessageFormat;
import java.util.ResourceBundle;
public static void main(String[] args)
Locale locale = Locale.CHINA; //将locale定义为CHINA
ResourceBundle bundle = ResourceBundle.getBundle("i18n", locale);
String value = bundle.getString("hello");
//格式化字符串对象,并传入参数,后边的Object数组对象表示要插入到占位符上的具体的对象
String result = MessageFormat.format(value, new Object[]{"维唯为为"});
注意:调整浏览器的语言和字符编码选项后,要注意,程序中输入的日期格式,也要做相应的改变,不然会出现日期类型转换错误。字符串国际化的同时,也要注意,日期的国际化。
在第三层建一个包,取名exception ,并在包中建两个类,分别取名为:
package com.shengsiyuan.exception;
public class UsernameException extends Exception
public UsernameException(String message)
public void setMessage(String message)
package com.shengsiyuan.exception;
public class PasswordException extends Exception
public PasswordException(String message)
public void setMessage(String message)
public String execute() throws Exception
throw new UsernameException("username invalid");
throw new PasswordException("password invalid");
<package name="struts2" extends="struts-default">
<action name="login" class="com.shengsiyuan.struts2.LoginAction">
<result name="usernameInvalid">/usernameInvalid.jsp</result>
<result name="passwordInvalid">/passwordInvalid.jsp</result>
<result name="success">/result.jsp</result>
<package name="struts2" extends="struts-default">
<result name="usernameInvalid">/usernameInvalid.jsp</result>
<result name="passwordInvalid">/passwordInvalid.jsp</result>