Java-Struts学习笔记之Struts框架输入校验、国际化及异常处理
项目文件结构
Struts2的输入校验
Struts2输入校验、执行流程:
1)首先进行类型转换
2)然后进行输入校验(执行validate方法)
3)如果在上述过程中出现了任何错误,都不会再去执行 execute方法,会转向 struts.xml 中该 action 的名为 input 的 result 所对应的页面。
要点:
-
ActionSupport 类的 addActionError()方法的实现:首先创建一个ArrayList对象,然后将错误消息添加到该 ArrayList对象中。
-
当调用 getActionErrors()方法返回 Action 级别的错误信息列表时,返回的实际上是集合的一个副本而不是集合本身,因此对集合副本调用 clear()方法清除的依旧是副本中的元素而非原集合中的元素,此时原集合中的内容没有收到任何的影响。换句话说,Action级别的错误信息列表对开发者来说是只读的。
-
Field Error 级别的错误信息底层是用 LinkedHashMap 实现的,该Map 的 key 是 String 类型,value 是 List
类型,这就表示一个 Field Name 可以对应多条错误信息,这些错误信息都放置在List 集合当中。
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”属性提交的结果
若使用
在tomcat中手动添加web项目:
…………
<Context path="/myWebSite" docBase="D:/Workspace/servlet/myWebSite" reloadable="true"/>
</Host>
</Engine>
</Service>
</Server>
java.lang.ClassNotFoundException: javax.el.ELResolver错误解决方法:Remove of classpath server-api.jar and jsp-api.jar
…………
Action级别的自定义方法的输入校验
要点:
-
Action中自定义方法的输入校验。对于通过action的method属性所指定的自定义方法,其对应的自定义输入校验方法名为validateMyExecute(假设自定义的方法名为 myExecute) 。底层是通过反射来调用的。
-
当在Action中指定了自定义的 execute方法时,首先会执行自定义的 execute 方法所对应的输入校验方法,然后再去执行标准的 validate 方法,执行完毕后如果出现了任何错误都不会再去执行自定义的execute方法,流程转向了 input这个名字所对应的页面上。
Login.jsp
…………
<body>
<form action="login.action">
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">
</form>
</body>
</html>
LoginAction
package com.shengsiyuan.struts2;
import java.util.Date;
import com.opensymphony.xwork2.ActionSupport;
import com.shengsiyuan.exception.PasswordException;
import com.shengsiyuan.exception.UsernameException;
public class LoginAction extends ActionSupport
{
private String username;
private String password;
private int age;
private Date date;
public Date getDate()
{
return date;
}
public void setDate(Date date)
{
this.date = date;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
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 execute() throws Exception
{
if(!"hello".equals(username))
{
throw new UsernameException("username invalid");
}
if(!"world".equals(password))
{
throw new PasswordException("password invalid");
}
return SUCCESS;
}
//自定的execute方法,在struts.xml中指定了LoginAction中的method方法为myExecute
public String myExecute() throws Exception
{
System.out.println("myExecute invoked!!");
return SUCCESS;
}
//Action自定义方法的输入校验
public void validateMyExecute() //此验证方法规定为将myExecute()方法名首字母大写后,再加前缀validate构成
{
System.out.println("validateMyExecute invoked!!");
this.addActionError("action error");
}
@Override
public void validate()
{
//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>
</action>
自定义Field级别的错误提示消息
要点:
1) 新建一个以 Action 名命名的 properties 文件 , 如RegisterAction.properties。 属性文件名要求为对应的Action文件名字。
2) 然后在该属性文件中指定每一个出错字段的错误消息 invalid.fieldvalue.birthday=birthday invalid !!
Tip: jdk提供的一款中文转换为unicode编码的工具,在jdk的bin目录下,native2ascii。在命令行下使用,使用方法如下:
struts2校验框架
要点:
Struts2的校验框架(有效的xml文件) 。具体来说分为字段优先校验器与校验器优先校验器。 配置文件的命名规则为:要对哪个Action加入校验框架,即在此个Action所在的包下添加一个名字为 xxxActioh-validation.xml文件。比如给RegisterAction用校验框架校验,则在RegiterAction对应的包下,添加一个名为RegisterAction-validation.xml的文件.
注释掉Action当中的校验方法与自定义的校验方法,配置Action的execute方法为默认的execute方法。 Struts2框架校验执行的先后顺序:
1) 首先执行校验框架(xml文件)
2) 执行自定义方法的校验方法(validateMyExecute)
3) 执行validate方法
对于struts.xml文件的结果配置来说,局部要优于全局。
xwork-validator.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
XWork Validators DTD.
Used the following DOCTYPE.
<!DOCTYPE validators PUBLIC
"-//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+)>
<!ATTLIST field
name CDATA #REQUIRED
>
<!ELEMENT field-validator (param*, message)>
<!ATTLIST field-validator
type CDATA #REQUIRED
short-circuit (true|false) "false"
>
<!ELEMENT validator (param*, message)>
<!ATTLIST validator
type CDATA #REQUIRED
short-circuit (true|false) "false"
>
<!ELEMENT param (#PCDATA)>
<!ATTLIST param
name CDATA #REQUIRED
>
<!ELEMENT message (#PCDATA)>
<!ATTLIST message
key CDATA #IMPLIED
>
RegisterAcion-validation.xml
字段优先校验
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
<validators>
<field name="username"><!-- 对username设置校验规则 -->
<field-validator type="requiredstring"><!-- 字符串必填规则设置 -->
<param name="trim">false</param><!-- 不清除空格 -->
<message>username can't be blank!</message><!-- 当校验失败提示的错误消息 -->
</field-validator>
<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>
</field>
<field name="password">
<field-validator type="requiredstring">
<message>password can't be blank!</message>
</field-validator>
<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>
</field>
<field name="age">
<field-validator type="required">
<message>age can't be blank!</message>
</field-validator>
<field-validator type="int">
<param name="min">10</param>
<param name="max">40</param>
<!—在这里可以用${元素名} 引用上面的子元素-->
<message>age should be between ${min} and ${max}</message>
</field-validator>
</field>
<field name="birthday">
<field-validator type="required">
<message>birthday can't be blank!</message>
</field-validator>
<field-validator type="date">
<param name="min">2005-1-1</param>
<param name="max">2007-12-31</param>
<message>birthday should be between ${min} and ${max}</message>
</field-validator>
</field>
</validators>
校验器优先校验(混合)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
<validator type="requiredstring">
<param name="fieldName">username</param>
<message>username can't be blank!</message>
</validator>
<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>
</validator>
<field name="birthday">
<field-validator type="required">
<message>birthday can't be blank!</message>
</field-validator>
<field-validator type="date">
<param name="min">2005-1-1</param>
<param name="max">2007-12-31</param>
<message>birthday should be between ${min} and ${max}</message>
</field-validator>
</field>
</validators>
打开com.opensymphony.xwork2.validator.validators可以发现一个default.xml文件,打开可以发现其中定义了各种校验器,内容如下:
default.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
"-//OpenSymphony Group//XWork Validator Config 1.0//EN"
"http://www.opensymphony.com/xwork/xwork-validator-config-1.0.dtd">
<!-- START SNIPPET: validators-default -->
<validators>
<validator name="required" class="com.opensymphony.xwork2.validator.validators.RequiredFieldValidator"/>
<validator name="requiredstring" class="com.opensymphony.xwork2.validator.validators.RequiredStringValidator"/>
<validator name="int" class="com.opensymphony.xwork2.validator.validators.IntRangeFieldValidator"/>
<validator name="long" class="com.opensymphony.xwork2.validator.validators.LongRangeFieldValidator"/>
<validator name="short" class="com.opensymphony.xwork2.validator.validators.ShortRangeFieldValidator"/>
<validator name="double" class="com.opensymphony.xwork2.validator.validators.DoubleRangeFieldValidator"/>
<validator name="date" class="com.opensymphony.xwork2.validator.validators.DateRangeFieldValidator"/>
<validator name="expression" class="com.opensymphony.xwork2.validator.validators.ExpressionValidator"/>
<validator name="fieldexpression" class="com.opensymphony.xwork2.validator.validators.FieldExpressionValidator"/>
<validator name="email" class="com.opensymphony.xwork2.validator.validators.EmailValidator"/>
<validator name="url" class="com.opensymphony.xwork2.validator.validators.URLValidator"/>
<validator name="visitor" class="com.opensymphony.xwork2.validator.validators.VisitorFieldValidator"/>
<validator name="conversion" class="com.opensymphony.xwork2.validator.validators.ConversionErrorFieldValidator"/>
<validator name="stringlength" class="com.opensymphony.xwork2.validator.validators.StringLengthFieldValidator"/>
<validator name="regex" class="com.opensymphony.xwork2.validator.validators.RegexFieldValidator"/>
<validator name="conditionalvisitor" class="com.opensymphony.xwork2.validator.validators.ConditionalVisitorFieldValidator"/>
</validators>
<!-- END SNIPPET: validators-default -->
错误消息国际化
在Action所在的包下建立两个属性文件,名字分别叫:
package_en_US.properties
username.invalid=username invalid
package_zh_CN.properties
username.invalid=\用\户\名\不\合\法\!
#用户名不合法
运行结果截图
Struts2国际化
对于国际化的资源文件,其命名规则是: package_语言名_国家名,比如package_zh_CN,package_en_US 。
I18NTest1.java
package com.shengsiyuan.i18n;
import java.util.Locale;
public class I18NTest1
{
public static void main(String[] args)
{
Locale[] locales = Locale.getAvailableLocales();
for (Locale locale : locales)
{
System.out.println(locale.getDisplayCountry() + " : "
+ locale.getCountry()); //显示国家及国家代码
// System.out.println(locale.getDisplayLanguage() + " : " + locale.getLanguage());
}
}
}
I18Ntest2.java
在src目录(classpath)下,建立三个资源文件,分别如下(注 i18n即为资源文件的base name):
i18n_en_US.properties
hello=hello\:{0}
i18n_zh_CN.properties
hello=\你\好\:{0}
i18n.properties
hello=hello world
I18Ntest2.java代码如下 :
package com.shengsiyuan.i18n;
import java.util.Locale;
import java.util.ResourceBundle;
public class I18NTest2
{
public static void main(String[] args)
{
System.out.println(Locale.getDefault());
//绑定一个base name 为i18n的资源文件,Locale使用FRANCE(法国)
ResourceBundle bundle = ResourceBundle.getBundle("i18n", Locale.FRANCE);
//获取hello字符串的值
String value = bundle.getString("hello");
System.out.println(value);
}
}
I18Ntest3.java(传入参数)
package com.shengsiyuan.i18n;
import java.text.MessageFormat;
import java.util.Locale;
import java.util.ResourceBundle;
public class I18NTest3
{
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[]{"维唯为为"});
System.out.println(result);
}
}
注意:调整浏览器的语言和字符编码选项后,要注意,程序中输入的日期格式,也要做相应的改变,不然会出现日期类型转换错误。字符串国际化的同时,也要注意,日期的国际化。
Struts2异常处理及全局异常与结果
要点:
我们既可以在 Action 中定义异常与结果,也可以定义全局的异常与结果,局部总是优于全局的,如果定义成全局,那么可以为所有的 Action 所公用,而局部的异常与结果只能被当前的 Action 所独享,不能为其他Action所共享。
validate主要进行没有业务逻辑的验证,比如判断用户名长名、密码与重复密码是否相同等。而判断用户登录是否成功;
struts2异常处理实例 在第三层建一个包,取名exception ,并在包中建两个类,分别取名为:
PasswordException.java
package com.shengsiyuan.exception;
public class UsernameException extends Exception
{
private String message;
public UsernameException(String message)
{
super(message);
this.message = message;
}
public String getMessage()
{
return message;
}
public void setMessage(String message)
{
this.message = message;
}
}
UsernameException.java
package com.shengsiyuan.exception;
public class PasswordException extends Exception
{
private String message;
public PasswordException(String message)
{
super(message);
this.message = message;
}
public String getMessage()
{
return message;
}
public void setMessage(String message)
{
this.message = message;
}
}
编辑loginAction的execute方法
public String execute() throws Exception
{
if(!"hello".equals(username))
{
throw new UsernameException("username invalid");
}
if(!"world".equals(password))
{
throw new PasswordException("password invalid");
}
return SUCCESS;
}
编辑struts.xml文件
Struts2的处理局部异常机制
…………
<struts>
<package name="struts2" extends="struts-default">
<action name="login" class="com.shengsiyuan.struts2.LoginAction">
<exception-mapping result="usernameInvalid" exception="com.shengsiyuan.exception.UsernameException"></exception-mapping>
<exception-mapping result="passwordInvalid" exception="com.shengsiyuan.exception.PasswordException"></exception-mapping>
<result name="usernameInvalid">/usernameInvalid.jsp</result>
<result name="passwordInvalid">/passwordInvalid.jsp</result>
<result name="success">/result.jsp</result>
</action>
………………
</struts>
Struts2的处理全局异常机制
…………
<struts>
<package name="struts2" extends="struts-default">
<global-results>
<result name="usernameInvalid">/usernameInvalid.jsp</result>
<result name="passwordInvalid">/passwordInvalid.jsp</result>
</global-results>
<global-exception-mappings>
<exception-mapping result="usernameInvalid" exception="com.shengsiyuan.exception.UsernameException"></exception-mapping>
<exception-mapping result="passwordInvalid" exception="com.shengsiyuan.exception.PasswordException"></exception-mapping>
</global-exception-mappings>
………………
</struts>