1、struts2類型轉換
需求:(注冊)
<body> <form action="${pageContext.request.contextPath}/converter/userAction_save.do" name="form1" method="post"> 編號:<input type="text" name="id"><br/> 姓名:<input type="text" name="userName"><br/> 出生日期:<input type="text" name="birth"><br/> <input type="submit" value="提交"><br/> </form> </body>
根據需求寫action以及一些配置就不多說了。
1、獲取表單元素的值
思考:
怎么將表單中的數據在action的對應方法中得到?
方式一:
我們在jsp+servlet的時候就知道可以使用request.getParameter獲得,所以:
public String save() throws Exception { System.out.println("UserAction ****** save"); /* web方式獲取: HttpServletRequest request=ServletActionContext.getRequest(); String username=request.getParameter("userName"); System.out.println("username ="+username ); */
方式二:
Struts2其實有機制實現了表單數據的獲取,原生的使用就有點low了。
/* *在struts2框架中,在對應動作類action中 *聲明與頁面中表單元素同名的屬性,給出對應的set和get方法 *struts2框架就會根據反射機制,獲取頁面中表單元素的值 */ private Integer id; private String userName; private Date birth;
//省略get,set方法 public String save() throws Exception { System.out.println("UserAction ****** save"); /* web方式獲取: HttpServletRequest request=ServletActionContext.getRequest(); String username=request.getParameter("userName"); System.out.println("username ="+username ); */ System.out.println("id = "+id); System.out.println("userName = "+userName); System.out.println("birth = "+birth); return "success"; }
前面我們獲取的表單元素每一個元素都是在userAction中對應一個屬性,如果我們希望有一些屬性是在userAction類中的對象屬性的某一個字段的內容,它自動注入,應該怎么處理呢?
我就不解釋了,一看看筆記看代碼。這里可以做到bean的屬性注入,和Collection集合bean的指定屬性注入。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags" %> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'userform.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <form action="${pageContext.request.contextPath}/converter/userAction_save.do" name="form1" method="post"> 編號:<input type="text" name="id"><br/> 姓名:<input type="text" name="userName"><br/> 出生日期:<input type="text" name="birth"><br/> 學歷編號:<input type="text" name="edu.id"><br/> 學歷名稱:<input type="text" name="edu.name"><br/> 員工姓名:<input type="text" name="emps[0].name"><br/> 員工薪水:<input type="text" name="emps[0].salary"><br/> 員工姓名:<input type="text" name="emps[1].name"><br/> 員工薪水:<input type="text" name="emps[1].salary"><br/> <input type="submit" value="提交"><br/> </form> </body> </html>
package cn.itcast.converter; import java.util.Collection; import java.util.Date; import com.opensymphony.xwork2.ActionSupport; public class UserAction extends ActionSupport { private static final long serialVersionUID = 1L; /* *在struts2框架中,在對應動作類action中 *聲明與頁面中表單元素同名的屬性,給出對應的set和get方法 *struts2框架就會根據反射機制,獲取頁面中表單元素的值 */ private Integer id; private String userName; private Date birth; private Edu edu; private Collection<Employee> emps; public String save() throws Exception { System.out.println("UserAction ****** save"); /* web方式獲取: HttpServletRequest request=ServletActionContext.getRequest(); String username=request.getParameter("userName"); System.out.println("username ="+username ); */ System.out.println("id = "+id); System.out.println("userName = "+userName); System.out.println("birth = "+birth); System.out.println("edu.id = "+edu.getId()); System.out.println("edu.name = "+edu.getName()); for(Employee emp:emps){ System.out.println(emp.getName()+"--"+emp.getSalary()); } return "success"; } public void setBirth(Date birth) { this.birth = birth; } public Date getBirth() { return birth; } public void setEdu(Edu edu) { this.edu = edu; } public Edu getEdu() { return edu; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } @Override public String execute() throws Exception { System.out.println("UserAction ****** execute"); return "success"; } public void setEmps(Collection<Employee> emps) { this.emps = emps; } public Collection<Employee> getEmps() { return emps; } }
2、struts2的類型自動轉換
我們前面發現struts2的這種機制可以使用反射將參數值自動注入。但是我們知道request.getParameter()得到的值都是String類型的,而我們定義的類型是各種各樣的。那么struts2是否可以自動幫我們完成所有的轉換呢?
測試得到:
對於基本數據類型和String類型來說,struts2可以完美的完成轉換類型的功能。
對於Date類型來說,必須限制date類型輸入的是yyyy-MM-dd 格式才可以成功轉換,否則會報錯。
Unexpected Exception caught setting 'birth' on 'class cn.itcast.converter.UserAction: Error setting expression 'birth' with value ['2012/01/01', ]
所以我們知道,struts2不是萬能的,只能對那幾個簡單的數據類型進行數據轉換,其他的就需要我們自動設置轉換器了。
注意:
出現類型轉換錯誤的途中可能也冒出這樣一個錯誤:
No result defined for action cn.itcast.converter.UserAction and result input
解決方案:
在action的result中配置錯誤結果處理頁面。
<package name="converter" namespace="/converter" extends="struts-default"> <action name="userAction_save" class="cn.itcast.converter.UserAction" method="save"> <!-- 錯誤提示:No result defined for action cn.itcast.converter.UserAction and result input 配置如果出錯的時候,自動化轉向到錯誤頁面 --> <result name="success">/converter/success.jsp</result> <result name="input">/converter/error.jsp</result> </action> </package>
3、自定義類型轉換器
定制類型轉換器說明:
自定義類型轉換器必須實現TypeConverter接口或對這個接口的某種具體實現做擴展
1、類型轉換器的書寫:
例子:
package cn.itcast.converter; import java.text.ParseException; import java.text.SimpleDateFormat; import com.opensymphony.xwork2.conversion.impl.DefaultTypeConverter; /* * 自定義轉換器 * 作用:把頁面中birth元素的字符串內容內容轉換成java.util.Date */ public class DateConverter extends DefaultTypeConverter { @Override public Object convertValue(Object value, Class toType) { //要轉換的值 [Ljava.lang.String;@27d314cc // System.out.println("value = "+value); //要轉換的類型: class java.util.Date //System.out.println("toType = "+toType); if(value==null){ return false; } if(toType==null){ return false; } if(toType!=java.util.Date.class){ return false; } if(value instanceof java.lang.String[]){ String[] strs=(String[]) value; if(strs[0]!=null && !strs[0].trim().isEmpty()){ try { //先確定日期的格式 SimpleDateFormat sdf=new SimpleDateFormat("yyyy/MM/dd"); return sdf.parse(strs[0]); } catch (ParseException e) { /* * 在struts2框架里,自定義的類型轉換器 * 如果我們不手動拋出異常,struts2框架只捕獲異常,但是並不拋出 * 所以框架就會認為類型轉換器轉換成功,轉向成功頁面 */ throw new RuntimeException(e); } } } return false; } }
注意幾個點:
Value是一個字符串數組而不是字符串
Return false;表示轉換失敗!
如果你僅僅是在自定義類型轉換器中try catch處理了異常,struts2框架會認為你這里沒有問題,也就是轉換成功,所以try/catch之后一定要拋出去,這樣框架才會知道使用這個自定義轉換器也轉換失敗,轉向失敗頁面
2、配置自定義的類型轉換器
在應用程序里使用一個自定義的類型轉換器之前,必須先對它進行配置。
這種配置既可以基於字段,也可以基於類
1、基於字段配置(局部):
可以為某個動作的各個屬性分別指定一個自定義的轉換器
1、 創建一個屬性文件:ActionClassName-conversion.properties,該文件需和相對應的動作類(Action)放在同一個目錄下
ActionClassName是Action的類名,后面的-conversion.properties是固定寫法
在properties文件中的內容為:
屬性名稱=類型轉換器的全類名
對於本例子而言,文件的名稱應為UserAction-conversion.properties
2、 編輯屬性文件
Birth=cn.itcast.converter.DateConverter
2、基於類配置(全局):
1、在WEB-INF/classes目錄(也就是src)下創建xwork-conversion.properties文件
在properties文件中的內容為:
待轉換的類型=類型轉換器的全類名
對於本例子而言,xwork-conversion.properties文件中的內容為:
Java.util.Date=cn.itcast.conberter.DateConverter
4、類型轉換中的異常處理
1、打印屬性錯誤異常信息
前面知道,在自定義類型轉換器中的異常需要拋出去。這樣框架才會跳轉到錯誤頁面。
我們前面的錯誤頁面:
<body>
失敗! !!<br>
</body>
僅僅告訴我們一個失敗,這樣是不夠的。我們希望還能知道是哪一個屬性轉換失敗,可以更改成為這樣:
<body> 失敗! !!<br> <s:fielderror fieldName="birth"/> </body>
在error.jsp頁面中使用<s:fielderror fieldName=””/>打印所有轉化的異常的錯誤信息
filedName:指定Action屬性的名稱
打印某個屬性轉化的異常錯誤信息
2、將顯示的異常錯誤信息變成中文
為什么顯示出來的錯誤信息是英文的呢?
錯誤信息是一個資源文件,默認的在xwork-core-2.3.jar下的com/opensymphony/xwork2的xwork-messages.properties
那么如何讓顯示出來的錯誤信息是中文的呢?
定義一個資源文件,覆蓋之前定義的錯誤信息就好了
做法:
在與當前Action同級目錄中,新建converter.properties(文件名稱自定義)資源文件
在該文件中可以增加如下內容:
Xwork-default.invalid.fieldvalue=無效的字段值”{0}”
資源文件創建好了,如何注入資源文件到struts2框架中呢?
<!-- 加載國際化資源文件,如果有多個資源文件用逗號隔開,后綴名.properties省略 其他的資源文件也是這樣加載 --> <constant name="struts.custom.i18n.resources" value="cn.itcast.converter.converter"/>
3、將異常提示信息確定到某個字段上
我們可以發現,每一個字段出現轉換異常給出的錯誤提示都是前面設置的無效的字段值,感覺不是很爽,我們希望將針對性變小來。
針對每個字段給出提示信息:
在前面的converter.properties中添加如下內容
格式: invalid.fieldvalue.xx=提示信息
內容: invalid.fieldvalue.birth=出生日期轉換異常
一些代碼與幫助文檔:

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <!-- 書寫配置文件找dtd,打開webApp,找到struts2.core下的2.3.dtd,直接復制這部分即可 --> <struts> <!-- constant:配置常量 name:指定的是struts2框架底層提供的default.properties資源文件中配置的“常量” value:指定的是配置常量的值 在struts.xml中配置的常量的值會覆蓋底層提供的default.priperties資源文件中配置的常量的值 配置struts2框架中的action的后綴名,如果有多個,使用“,”隔開 如果資源文件在struts.properties和struts.xml中都配置了,那么struts.properties中的生效 因為常量可以在多個配置文件中定義,所以我們需要了解下struts2加載常量的搜索順序: 1 struts-default.xml 2 struts-plugin.xml 3 struts.xml 4 struts.properties 5 web.xml --> <!-- action后綴名 --> <constant name="struts.action.extension" value="do,love"/> <!-- 配置國際化資源文件修改時,是否重新加載。默認是false,為不加載 --> <!-- <constant name="struts.il8n.reload" value="true"/> --> <!-- 配置struts2框架的配置文件修改時,是否重新加載。默認是false為不加載 --> <!-- <constant name="struts.configuration.xml.reload" value="true"/> --> <!-- 配置struts2框架的模式 默認為false,是生產模式 true是開發模式,需要更多的調試信息 ### when set to true, resource bundles will be reloaded on _every_ request. ### this is good during development, but should never be used in production ### struts.i18n.reload=false --> <constant name="struts.devMode" value="true" /> <!--關閉 動態方法調用 --> <constant name="struts.enable.DynamicMethodInvocation" value="false" /> <!-- 加載國際化資源文件,如果有多個資源文件用逗號隔開,后綴名.properties省略 其他的資源文件也是這樣加載 --> <constant name="struts.custom.i18n.resources" value="cn.itcast.converter.converter"/> <!-- package:包 name:包名,唯一的,必選項 namespace:命名空間,唯一的,相當於房間號。可選項,省略情況下是“/” extends:繼承 extends=“struts-default”:struts2框架底層提供的核心包struts2-core-2.3.3.jar下的struts-default.xml文件 為什么要繼承這個struts-default.xml文件 因為struts框架底層提供的struts-default.xml聲明了所有的攔截器和攔截器棧。 我們知道struts2框架運行時執行struts-default.xml中的攔截器棧完成必要功能。 如果不繼承struts-default.xml文件,就沒有辦法使用struts2提供的所有攔截器。 --> <package name="default" namespace="/" extends="struts-default"> <default-action-ref name="notFoundAction"/> <action name="notFoundAction" class="cn.itcast.util.action.NotFoundAction"> <result>/404.jsp</result> </action> </package> <!-- 引入自定義配置文件 --> <include file="cn/itcast/helloworld/struts_helloworld.xml"/> <include file="cn/itcast/prima/struts_prima.xml"/> <include file="cn/itcast/resulttype/struts_resulttype.xml"/> <include file="cn/itcast/pattern/struts_pattern.xml"/> <include file="cn/itcast/converter/struts_converter.xml"/> </struts>

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <!-- action="${pageContext.request.contextPath}/converter/userAction_save.do" --> <package name="converter" namespace="/converter" extends="struts-default"> <action name="userAction_save" class="cn.itcast.converter.UserAction" method="save"> <!-- 錯誤提示:No result defined for action cn.itcast.converter.UserAction and result input 配置如果出錯的時候,自動化轉向到錯誤頁面 --> <result name="success">/converter/success.jsp</result> <result name="input">/converter/error.jsp</result> </action> </package> </struts>

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags" %> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'userform.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <form action="${pageContext.request.contextPath}/converter/userAction_save.do" name="form1" method="post"> 編號:<input type="text" name="id"><br/> 姓名:<input type="text" name="userName"><br/> 出生日期:<input type="text" name="birth"><br/> <input type="submit" value="提交"><br/> </form> </body> </html>

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags" %> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'error.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> 失敗! !!<br> <s:fielderror fieldName="birth"/> </body> </html>

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags" %> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'success.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> 成功!!!!<br/> </body> </html>

package cn.itcast.converter; import java.util.Date; import com.opensymphony.xwork2.ActionSupport; public class UserAction extends ActionSupport { private static final long serialVersionUID = 1L; /* *在struts2框架中,在對應動作類action中 *聲明與頁面中表單元素同名的屬性,給出對應的set和get方法 *struts2框架就會根據反射機制,獲取頁面中表單元素的值 */ private Integer id; private String userName; private Date birth;//Unexpected Exception caught setting 'birth' on 'class cn.itcast.converter.UserAction: Error setting expression 'birth' with value ['2012/01/01', ] public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } @Override public String execute() throws Exception { System.out.println("UserAction ****** execute"); return "success"; } public String save() throws Exception { System.out.println("UserAction ****** save"); /* web方式獲取: HttpServletRequest request=ServletActionContext.getRequest(); String username=request.getParameter("userName"); System.out.println("username ="+username ); */ System.out.println("id = "+id); System.out.println("userName = "+userName); System.out.println("birth = "+birth); return "success"; } public void setBirth(Date birth) { this.birth = birth; } public Date getBirth() { return birth; } }

package cn.itcast.converter; import java.text.ParseException; import java.text.SimpleDateFormat; import com.opensymphony.xwork2.conversion.impl.DefaultTypeConverter; /* * 自定義轉換器 * 作用:把頁面中birth元素的字符串內容內容轉換成java.util.Date */ public class DateConverter extends DefaultTypeConverter { @Override public Object convertValue(Object value, Class toType) { //要轉換的值 [Ljava.lang.String;@27d314cc // System.out.println("value = "+value); //要轉換的類型: class java.util.Date //System.out.println("toType = "+toType); if(value==null){ return false; } if(toType==null){ return false; } if(toType!=java.util.Date.class){ return false; } if(value instanceof java.lang.String[]){ String[] strs=(String[]) value; if(strs[0]!=null && !strs[0].trim().isEmpty()){ try { //先確定日期的格式 SimpleDateFormat sdf=new SimpleDateFormat("yyyy/MM/dd"); return sdf.parse(strs[0]); } catch (ParseException e) { /* * 在struts2框架里,自定義的類型轉換器 * 如果我們不手動拋出異常,struts2框架只捕獲異常,但是並不拋出 * 所以框架就會認為類型轉換器轉換成功,轉向成功頁面 */ throw new RuntimeException(e); } } } return false; } }

# # Copyright (c) 2002-2006 by OpenSymphony # All rights reserved. # xwork.error.action.execution=Error during Action invocation xwork.exception.missing-action=There is no Action mapped for action name {0}. xwork.exception.missing-package-action=There is no Action mapped for namespace {0} and action name {1}. xwork.default.invalid.fieldvalue=Invalid field value for field "{0}".