需求:(註冊)css
<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以及一些配置就很少說了。html
思考:java
怎麼將表單中的數據在action的對應方法中獲得?web
方式一:express
咱們在jsp+servlet的時候就知道可使用request.getParameter得到,因此:apache
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了。app
/* *在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的指定屬性注入。jsp
<%@ 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; } }
咱們前面發現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>
定製類型轉換器說明:
自定義類型轉換器必須實現TypeConverter接口或對這個接口的某種具體實現作擴展
例子:
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以後必定要拋出去,這樣框架纔會知道使用這個自定義轉換器也轉換失敗,轉向失敗頁面
在應用程序裏使用一個自定義的類型轉換器以前,必須先對它進行配置。
這種配置既能夠基於字段,也能夠基於類
能夠爲某個動做的各個屬性分別指定一個自定義的轉換器
一、 建立一個屬性文件:ActionClassName-conversion.properties,該文件需和相對應的動做類(Action)放在同一個目錄下
ActionClassName是Action的類名,後面的-conversion.properties是固定寫法
在properties文件中的內容爲:
屬性名稱=類型轉換器的全類名
對於本例子而言,文件的名稱應爲UserAction-conversion.properties
二、 編輯屬性文件
Birth=cn.itcast.converter.DateConverter
一、在WEB-INF/classes目錄(也就是src)下建立xwork-conversion.properties文件
在properties文件中的內容爲:
待轉換的類型=類型轉換器的全類名
對於本例子而言,xwork-conversion.properties文件中的內容爲:
Java.util.Date=cn.itcast.conberter.DateConverter
前面知道,在自定義類型轉換器中的異常須要拋出去。這樣框架纔會跳轉到錯誤頁面。
咱們前面的錯誤頁面:
<body>
失敗! !!<br>
</body>
僅僅告訴咱們一個失敗,這樣是不夠的。咱們但願還能知道是哪個屬性轉換失敗,能夠更改爲爲這樣:
<body> 失敗! !!<br> <s:fielderror fieldName="birth"/> </body>
在error.jsp頁面中使用<s:fielderror fieldName=」」/>打印全部轉化的異常的錯誤信息
filedName:指定Action屬性的名稱
打印某個屬性轉化的異常錯誤信息
爲何顯示出來的錯誤信息是英文的呢?
錯誤信息是一個資源文件,默認的在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"/>
咱們能夠發現,每個字段出現轉換異常給出的錯誤提示都是前面設置的無效的字段值,感受不是很爽,咱們但願將針對性變小來。
針對每一個字段給出提示信息:
在前面的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}".