actionMessages(),actionError()介绍
尽管Struts框架提供了有效的异常处理机制,但不能保证处理所有的错误,这时Struts框架会把错误抛给Web容器,在默认情况下Web容器会向用户浏览器直接返回原始信息。如果想避免直接让用户看到这些原始信息,可以在web.xml中配置<error-page>元素,以下代码演示了如何避免用户看到HTTP 404、HTTP 500错误和Exception异常。
web.xml:
<error-page>
<error-code>404</error-code>
<location>/exception/error404.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/exception/error500.jsp</location>
</error-page>
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/exception/default.jsp</location>
</error-page>
当WEB容器捕获到exception-type或error-code指定的错误时将跳到由location指定的页面。
问题:当form bean 为动态bean时,在action中无法对form bean数据进行验证,因为formbean没有具体实现类。action中无法引用
ActionError/ActionErrors/ActionMessage/ActionMessages:
有时候你需要向用户提供相关处理信息,包括表单验证时发现错误等。
1. 相关类介绍:
ActionMessage:用于保存一个与资源束对应的提示信息。主要构造函数如:
ActionMessage(String message);
ActionMessage(String message,paramater)。
ActionMessages:用于保存多个ActionMessage。并在html:errors 和html:messages中起作用。
主要构造函数:
ActionMessages().
主要方法是add(String property,ActionMessage message)
ActionMessages有一个HashMap类型messages保存多个ActionMessage对象,每个ActionMessage对象都有唯一的一个property标识。这个property可以是自定义的任意字符串,也可以由org.apache.struts.action.ActionMessages.GLOBAL_MESSAGE指定
html:messages/html:errors使用property属性访问某个资源
ActionErrors:用于保存一个与资源束对应的错误信息。用法跟ActionMessages差不多。
ActionError不赞成使用。
2. 版本:
struts1.1中用ActionErrors报告错误,用ActionMessages提供信息。
在struts1.2中使用ActionMessages提供信息和错误,不赞成使用ActionError
struts1.3中已经没有ActionError类了。
3. AtionErrors和ActionMessages的区别
1. ActionErrors是ActionMessages的一个子类,功能几乎相同,不同点在于标签<html:errors/>和<html:messages>的使用上的区别。
html:errors指定了footer和header属性。默认值为errors.header和errors.footer,需要时可以自己指定。如果资源属性文件配置了 errors.header和errors.footer,则任何时候使用html:errors时开头和结尾都是这两个属性对应的资源信息。
而html:message默认情况下没有errors.header和errors.footer值,当然可以自己指定。
2. html:errors可以根据property属性指定显示一个错误信息。html:messages有一个必添项id。html:messages不能直接显示信息,它将选出的信息放入一个用id标识的Iterator对象里,然后在用ben:write或JSTL c:out标签显示每个信息.例如:
<html:messages message="true" id="msg">
<c:out value="${msg}"/><br />
</html:messages>
3. 具体的一个例子:
接受输入页面input.jsp:
<html:form action="/errormessage/input">
phoneNumber : <html:text property="phoneNumber"/> <html:errors property="<%=org.apache.struts.action.ActionMessages.GLOBAL_MESSAGE %>"/><br/>
<html:submit/><html:cancel/>
</html:form>
struts-config.xml:
<form-beans >
<form-bean name="inputForm" type="cn.rolia.struts.form.errorexception.InputForm" />
</form-beans>
<action-mappings >
<action
attribute="inputForm"
input="/errormessage/input.jsp"
name="inputForm"
path="/errormessage/input"
scope="request"
type="com.yourcompany.struts.action.errormessage.InputAction"
validate="false">
<forward name="success" path="/errormessage/success.jsp" />
</action>
</action-mappings>
InputAction.java:
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
cn.rolia.struts.form.errorexception.InputForm inputForm = (cn.rolia.struts.form.errorexception.InputForm) form;// TODO Auto-generated method stub
String phoneNumber = inputForm.getPhoneNumber();
if(phoneNumber.length()<4){
ActionErrors messages = new ActionErrors();
messages.add(org.apache.struts.action.ActionMessages.GLOBAL_MESSAGE,new ActionMessage("error.errormessage.input"));
this.saveErrors(request, messages);
return mapping.getInputForward();
}
return mapping.findForward("success");
}
解说:用户输入手机号码,页面跳转到InputAction控制层进行处理,若输入数据小于4,则创建一个ActionMessage类存储相关错误信息。然后再创建ActionErrors类将此ActionMessage放入ActionErrors。再调用Action的saveErrors方法将此ActionErrors保存的request范围里,然后返回input.jsp页面要求重新输入并用html:errors提示错误信息。
4. Action包含saveErrors()方法和saveMessages()方法。如果创建的ActionErrors则应该调用saveErrors(),若创建的是ActionMessages则应该调用saveMessages()方法。
saveErrors()接收ActionMessages而不是ActionErrors;同时将其保存在request中并用一个由org.apache.struts.Globals.ERROR_KEY指定的常量” org.apache.struts.Globals.ERROR_KEY”标识这个ActionMessages,便于html:errors查找。saveMessages()方法接收ActionMessages同时将其保存在request中并用一个由org.apache.struts.Globals.MESSAGE_KEY指定的常量” org.apache.struts.Globals.MESSAGE_KEY”标识这个ActionMessages,进而让html:messages从常量Globals.ERROR_KEY中遍历获取信息。可以将其属性message设置为true,那么它将从常量Globals.MESSAGE_KEY中遍历获取信息。
5. 默认情况下html:messages从
如果你想将信息保存在session里而不是request,struts1.2提供了
struts1.1没有的saveMessages(HttpSession session, ActionMessages messages)方法和saveErrors(javax.servlet.http.HttpSession session, ActionMessages errors)方法。
InputAction.java:
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
cn.rolia.struts.form.errorexception.InputForm inputForm = (cn.rolia.struts.form.errorexception.InputForm) form;// TODO Auto-generated method stub
String phoneNumber = inputForm.getPhoneNumber();
if(phoneNumber.length()<4){
ActionErrors messages = new ActionErrors();
messages.add(org.apache.struts.action.ActionMessages.GLOBAL_MESSAGE,new ActionMessage("error.errormessage.input"));
this.saveErrors(request.getSession(true), messages);
return mapping.getInputForward();
}
return mapping.findForward("success");
}
--------------------------------------------------
代碼:
package onlyfun.caterpillar;
import javax.servlet.http.*;
import org.apache.struts.action.*;
public class UserForm extends ActionForm {
protected String name;
protected String password;
public void setName(String name) {
this.name = name;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public String getPassword() {
return password;
}
public void reset(ActionMapping mapping, HttpServletRequest req) {
name = null;
password = null;
}
public ActionErrors validate(ActionMapping mapping,
HttpServletRequest request) {
ActionErrors errors = new ActionErrors();
if(getName() == null || getUsername().length() < 1) {
errors.add("name",new ActionError("error.name.required"));
}
if(getPassword() == null || getPassword().length() < 1) {
errors.add("password",new ActionError("error.password.required"));
}
return errors;
}
}
當使用者發送表單,而表單中有欄位沒有填寫時,則請求中會包括參數名稱,但是值為空字串,如果ActionForm具有某些屬性,而表單並沒有發送對應的參數,則不會設定ActionForm中對應的屬性,這些屬性將為null,我們的validate()中主要在檢查這兩個情況。
validate()方法會傳回ActionErrors物件,ActionErrors可以儲存ActionError的訊息,每一個ActionError會查詢資源檔中的key-value對應,當validate()丟回ActionErrors物件時,ActionServlet就不會繼續進行接下來的工作,而是導回structs-config.xml所設定的位置,例如:
代碼:
<global-forwards>
<forward
name="welcome"
path="/Welcome.do"/>
</global-forwards>
<form-beans>
<form-bean
name="userForm"
type="onlyfun.caterpillar.UserForm"/>
</form-beans>
<action-mappings>
<action
path="/Welcome"
type="org.apache.struts.actions.ForwardAction"
parameter="/pages/Welcome.jsp"/>
<action
path="/LoginAction"
type="onlyfun.caterpillar.LoginAction"
name="userForm"
validate="true"
input="/pages/Welcome.jsp">
<forward name="greeting" path="/pages/greeting.jsp"/>
</action>
</action-mappings>
為了要能使用validate()方法,<action>中的validate屬性必須設定為true,而input屬性也是必要的,當validate()傳回ActionErrors時,就會forward至input屬性所設定的位置,ActionErrors中的訊息,我們可以使用<html:errors/>標籤來顯示,待會就會看到。
ActionForm中驗證了屬性為null及空字串的可能,這是資料完整性的驗證,接下來我們要驗證資料的正確性,是否符合我們所設定的名稱與密碼,我們改寫前一個主題的LoginAction,看看寫法有何不同:
代碼:
package onlyfun.caterpillar;
import javax.servlet.http.*;
import org.apache.struts.action.*;
import org.apache.commons.beanutils.*;
public class LoginAction extends Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
String name = (String) PropertyUtils.getSimpleProperty(form, "name");
String password = (String) PropertyUtils.getSimpleProperty(form, "password");
if(!(name.equals("caterpillar") && password.equals("1234"))) {
ActionMessages messages = new ActionMessages();
messages.add(ActionMessages.GLOBAL_MESSAGE,
new ActionMessage("message.namepass.notmatched"));
saveMessages(request, messages);
return mapping.findForward("welcome");
}
else {
request.getSession().setAttribute("valid_user", form);
return mapping.findForward("greeting");
}
}
}
在這次的程式中,我們使用了org.apache.commons.beanutils中的PropertyUtils類別來協助我們取ActionForm中的值,好處是不用理會ActionForm真正的形態,PropertyUtils會自動幫我們判斷,getSimpleProperty()傳回的是Object,我們將之轉換為String。
ActionMessages是Struts 1.1所新增的類別,它變成了ActionErrors的父類別,同樣的,ActionMessage也是Struts 1.1新增的類別,它是ActionError的父類別,資料的格式與完整性檢查在ActionForm中我們已經驗證了,接下來我們在Action中檢查是否符合名稱與密碼,如果不符合就加入相關的訊息。
在Struts 1.1中特意將Message與Error區別,該是認定所謂的Error是使用者的輸入在完整性或格式等上有誤,而Message是指輸入的資料基本上沒有錯誤,但不能符合後續的商務處理。
為了要能夠顯示錯誤與訊息,我們必須在application_zh.properties中加入key-value對應,如下:
代碼:
# -- error --
error.name.required=沒有輸入名稱
error.password.required=沒有輸入密碼
#-- message --
message.namepass.notmatched=名稱與密碼不正確
為了要能使用中文,記得使用native2ascii工具程式進行轉換,接下來我們來看看我們的Welcome.jsp如何撰寫,要注意的是在<html:errors/>與<htm:messages/>的使用:
代碼:
<%@ taglib uri="/tags/struts-bean" prefix="bean" %>
<%@ taglib uri="/tags/struts-html" prefix="html" %>
<%@page contentType="text/html; charset=Big5"%>
<html:html locale="true">
<head>
<title><bean:message key="welcome.title"/></title>
<html:base/>
</head>
<body bgcolor="white">
<html:errors/>
<html:messages id="messages" message="true">
<bean:write name="messages"/>
</html:messages>
<h3>請登入</h3>
<html:form action="/Login">
名稱:<html:text property="name" size="20"/><br>
密碼:<html:password property="password" size="20"/><br>
<html:submit/> <html:reset/>
</html:form>
</body>
</html:html>
如果由於ActionForm傳回ActionErrors物件而返回Welcome.jsp,則<html:errors/>標籤會顯示ActionErrors中的相關錯誤訊息,我們利用<html:messages/>來檢查返回中是否也包括ActionMessages物件,如果有的話就取出並使用<bean:write/>標籤顯示之。
下面是執行時未填寫欄位所顯示的錯誤訊息的一個例子:
代碼:
<html lang="zh">
<head>
<title>哈囉!Struts!</title>
<base href="http://localhost:8080/HelloStruts/pages/Welcome.jsp">
</head>
<body bgcolor="white">
<UL>
<LI>沒有輸入名稱
</LI><LI>沒有輸入密碼
</LI></UL>
<h3>請登入</h3>
<form name="UserForm" method="post" action="/HelloStruts/Login.do">
名稱:<input type="text" name="name" size="20" value=""><br>
密碼:<input type="password" name="password" size="20" value=""><br>
<input type="submit" value="Submit"> <input type="reset" value="Reset">
</form>
</body>
</html>
注意到ActionErrors在Struts 1.2之後可能會被標示為deprecated,將來可能會改以ActionMessages取代,所以<html:errors/>在將來必須以下面的方式來取代:
代碼:
<html:messages id="msg" >
<bean:write name="msg"/>
</html:messages>
在之前的例子中,在<html:messages/>的屬性上設定message為true,這表示顯示ActionMessages的內容:
代碼:
<html:messages id="messages" message="true">
<bean:write name="messages"/>
</html:messages>