Struts2第二天學習
解決struts.xml文件的冗余
將所有的配置文件放在一份struts.xml將會導致, 文件繁雜且容易出錯, 將有如下的解決方案:
分文件編寫Struts2的配置文件:對于具有類似功能的action就可以放入不同對應的xml文件中, 最后使用struts標簽中的<include file="user.xml"></include>處理例如:1. struts.xml<struts><constant name="struts.devMode" value="true"></constant><include file="A.xml"></include><include file="B.xml"></include></struts>2. A.xml<struts><package name="A" extends="struts-default"><action name="addA"><result>/success.jsp</result></action></package> </struts>3. B.xml<struts><package name="B" extends="struts-default"><action name="addB"><result>/success.jsp</result></action></package> </struts>
封裝請求數據到對象中
靜態參數封裝: 使用struts.xml配置param參數, 調用動作類的setXXX方法做數據注入,默認編碼utf-8, 不會出現亂碼問題
例: struts.xml配置<struts><package name="user" extends="struts-default"><action name="addUser" class="com.action.UserAction" method="saveUser"><param name="username">A</param><param name="age">18</param></action></package> </struts>在動作類中的配置:public class UserAction extends ActionSupport{private String username;private int age;public String getUsername(){return username;}public void setUsername(String username){this.username = username;}public int getAge(){return age;}public int setAge(){this.age = age;}public String saveUser(){ //action方法return null; } }
當訪問index.jsp中addUser操作的時候, struts.xml觸發saveUser的action, 將username, age中參數通過UserAction中的set方法做注入操作
整個注入的過程中, 首先會自動為UserAction生成一個user對象, 將username, age通過set方式進行賦值
Struts2是通過staticParams的攔截器做注入操作, 這里注意必須保證, 注入的param標簽中的name必須與Action類中的屬性同名
在param中的age參數18是作為字符串出現的, 當使用set操作的時候, 字符串自動轉換為數字
動態參數封裝: 就是對用戶提交的表單數據封裝到實體模型中
當用戶使用表單提交數據的時候, 在Servlet中, 直接使用request.getParameter("參數名")處理
而在Struts2中, 系統默認將表單數據一一通過set操作封裝到Action類的屬性中
在struts.xml不需要做參數配置, 例如:<action name="addUser" class="com.action.UserAction" method="saveUser"></action>無需指定param
注: 此處的操作是由params攔截器完成的, 通過攔截器將表單數據填入對應的Action類中同名同類型使用此種方式出現的問題是: Action不應該處理對JavaBean數據的處理, Action的主要功能是對用戶操作的反饋針對上述的問題, 提出如下的操作
1. 動作類與實體模型分開
在動作類中不采用上面的方式(將username, age等屬性放入動作類), 而是將數據單獨封裝為User類處理
例:public class UserAction extends ActionSupport{private User user;public String getUser(){return user;}public void setUser(User use){this.user = user;}public String saveUser(){ //action方法return null; } }
在index中, 作如下處理
用戶名: <input name="text" name="user.username"/>
此處說明: user.username就類似于Servlet中的將數據存入request, session中傳遞
注: 在index.jsp中要注意: user.username中, user必須與Action中屬性名相同, username必須與User中的屬性名相同在表單數據封裝到實體類中分為以下2個步驟:1. 通過Action類中的get方法查看當前User實例是否存在, 不存在則new一個, 然后使用Action中的set方法為bean引用賦值2. 調用action中get方法獲得bean對象, 通過注入的方式為實例對象賦值, 整個過程中在struts.xml無需做配置, 過濾器會自動將表單中數據封裝到action中對象上
此時的賦值一樣是param攔截器進行處理
需要注意的, 當在上述的1操作中, 如果bean的實例對象存在, 那么就不會執行set操作, 直接執行get操作, 最后對該實例對象賦值
2. 在動作類與實體模型分開的基礎上, 進行模型驅動
如果只是單純地將動作類與實體模型分開, 容易出現的問題就是在寫jsp的過程中必須保證, 模型變量之間的聯系, 如果某個地方的變量名錯誤, 很容易導致錯誤 當采用模型驅動的方式, 在一定程度上可以減輕jsp的開發 如標題所說, 模型驅動就是使用已存在的bean實例驅使jsp中表單數據進行封裝, 而不是讓jsp去指定向哪個實例中的哪個屬性進行封裝數據 模型驅動的2個步驟: 1. 讓Action實現ModelDriven接口, 實現getModel方法(返回值泛型) 2. 使用模型驅動, 數據模型必須自己實例化
例:Action類: public class UserAction extends ActionSupport implements ModelDriven<User>{private User user = new User();public User getModel(){//重寫ModelDriven中的getModelreturn user;}public String registerUser(){return null; }}index.jsp:用戶名:<input type="text" name="username"/><br/>年齡:<input type="text" name="age"/><br/><input type="submit" value="注冊"/>struts.xml:<action name="registerUser" class="com.action.UserAction" method="registerUser"></action>
注: 模型驅動使用的是ModelDriven攔截器
數據類型轉換
需要注意的是, 通過客戶端填寫的數據都是String或String[]
- 獲取表單中字符串數據 -> 使用set方法填充模型數據 -> POJO- POJO -> 使用get方法獲取數據 -> jsp顯示(字符串類型)
注: 在set填充數據的時候Struts2會根據數據類型做自動轉換處理
注: 系統的類型轉換在某些方面可能不滿足實際需求, 需要我們自己定義類型轉換器.
下面介紹一下自定類型轉換器
在Struts2中具有一個TypeConvert的接口, 當實現該接口就可完成自定義類型的轉換, 存在的問題是該接口中的convertValue方法顯得過于繁瑣, 因此一般采用繼承TypeConvert的子類解決問題
編寫類繼承TypeConvert的子類StrutsTypeConverter, 實現抽象方法: public abstract Object convertFromString(Map context, String[] values, Class toClass); 以及 public abstract String convertToString(Map context, Object o);
convertFromString是將用戶輸入的String數據轉化為指定類型
convertToString是將指定該類型轉化為String類型
context: 存放動作訪問的所有數據
values: 存放用戶輸入的值
toClass: 要轉換的目標類
以轉換日期為例:
public class MyTypeConverter extends StrutsTypeConverter{private DateFormat df = new SimpleDateFormat("mm/dd/yyyy"); //例如將1/1/2019變為字符串, 按照當地時間格式存入數據庫//重寫convertFormStringpublic Object convertFromString(Map context, String[] values, Class toClass){if (values == null || values.length == 0){return null;}String str = values[0];if(toClass == java.util.Date.class){try{return df.parse(str);} catch(Exception e){e.printStackTrace() return null;}}}return null;
}
//重寫convertToString
public abstract String convertToString(Map context, Object o){if(o instanceof Date){return df.format((Date)o);} return null;
}
- 局部注冊: 在javaBean包下建立一個 javaBeanName-conversion.properties的文件javaBeanName代表類名, 文件名必須按照上面的格式在.properties文件中將需要轉換的屬性注冊轉換器例: birthday=com.convert..MyTypeConverter- 全局類型轉換器: 需要使用轉換的數據類型注冊轉換器在src路徑下, 建立一個xwork-conversion.properties屬性的文件, 這里的文件名也是固定的例: java.util.Date=com.convert..MyTypeConverter此處由于針對全局元素, 所以直接將Data類型作為轉換器注冊對象
經過上述的步驟就能將指定類型轉換為本身需要的類型
轉換失敗后的處理
轉換失敗后不能將異常拋給用戶, 所以, 一般采用如下操作:
在結果視圖標簽中, 添加<result name="input">/index.jsp</result>
當出現異常的時候, Struts2會自動切換到input視圖
處理input回顯數據
常規的Servlet回顯數據使用的是將數據存入request中, 通過EL表達式在表單中回顯數據 而Struts2采用的是配置標簽, 使用Struts2自帶標簽, 在使用input回顯操作的時候將會對數據做自動填充, 填充至表單中, Struts2中自帶的標簽就是對原本的html標簽的一種修飾以及功能加強 如下操作:
<%@ taglib uri="/struts-tags" perfix="s"%> <%--使用Struts2自帶標簽--%>
<s:form><s:textfield name="username" label="用戶名"></s:textfield><s:textfield name="password" label="密碼"></s:password>
</s:form>
剩余標簽以及內部屬性,自行查閱
當使用Struts2提供的標簽庫的時候, 數據的回顯, 不再需要"request封裝"
表單信息提示
當用戶提交表單數據的時候, 需要對表單數據做驗證操作, 如果信息錯誤則給用戶一個錯誤提示, 在Servlet中, 采用的是request封裝數據, 結合js做驗證 在Struts2中采用的也是標簽配置, 例如:
<s:fielderror></s:fielderror> <%--字段錯誤提示, 此處的s借用上面的--%>
<s:actionerror/> <%--動作錯誤--%>
當字段出現錯誤的時候, 做數據回顯, 會作自動的提示操作, 告訴用戶對應的輸入出現什么樣的錯誤
注: 當出現數據類型轉化錯誤, 將會觸發conversionError的攔截器(前提必須是Action繼承ActionSupport), 該攔截器將會進入input視圖如果沒有對字段信息做處理, 將會以默認的方式顯示, 顯示一堆英文對用戶不友好, 所以下面將針對編寫自定義信息提示做敘述
自定義表單數據信息提示以及驗證規則
一般采用客戶端與服務端共同對信息進行驗證 下面介紹Struts2的服務端驗證, 下面的所有的操作都是基于Action類繼承ActionSupport來處理的
form表單中的數據總是針對JavaBean某個字段而言, 所以有以下處理:
在JavaBean路徑下, 新建一個與Bean類名相同的properties的文件, 然后針對需要自定義的字段進行信息配置
例如:在User.properties中invalid.fieldvalue.birthday=出生日期有誤, 使用yyyy-MM-dd格式注: 在properties文件中, 中文會自動用Unicode編碼代替文件的key必須是invalid.fieldvalue.屬性名文件value代表顯示的中文提示信息
處理Action類中動作方法的驗證 使用重寫validate方法解決驗證
在ActionSupport中提供了一個validate方法, 那是系統默認的驗證操作, 自定義驗證規則就需要重寫父類方法
例:public void validate(){if (StringUtils.isEmpty(user.getUsername)){addFieldError("username", "用戶名必須輸入");} }
//在Struts2中提供一個Map用于封裝操作錯誤信息, 通過addFieldError方法添加錯誤信息
//"username"代表錯誤信息的字段名, "用戶名必須輸入"代表錯誤提示信息
注: 使用上面的validate操作具有一個弊端, 就是會對所有的動作操作做驗證規則, 如上面的操作, 如果user的username一直為空, 當用戶執行其他動作操作, 就會報錯 例如:
在Action類中具有一個findAll操作
public String findAll(){return SUCCESS;
}
當用戶沒有注冊( 此時的username為null )而去執行findAll操作, 出現的問題就是: 即使findAll操作成功. 但是依舊拋異常
出現這種情況的原因就是: validate對所有的動作都進行驗證
解決上述問題, 采用有如下的方案:
給不需要驗證的動作添加一個@SkipValidation注解 如上面的操作, 為findAll添加一個@SkipValidation注解, 使得跳過findAll, 不去驗證它
validation方法遵循書寫規范 將上面的validate改為validateRegist, 使得用戶注冊的時候只驗證regist動作, 而不去驗證findAll動作
聲明式驗證, 不使用函數式驗證方式, 而是編寫xml配置文件, 制定驗證規則 在動作類所在的目錄下, 新建一個 動作類類名-validation.xml的文件 例如:
文件名: UserAction-validation.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC"-//Apache Struts//XWork Validator 1.0.3//EN""http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"><validators><field name="username"><field-validator type="requiredString"><message>請輸入用戶名</message></field-validator></field> </validators>對username屬性做requiredString驗證(表示username不能為空)
注: 它是針對動作類中所有的動作方法做驗證 在動作類所在的目錄下, 新建一個 動作類類名-動作名-validation.xml的文件就可以實現對特定的動作進行驗證 例如:
文件名: UserAction-regist-validation.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC"-//Apache Struts//XWork Validator 1.0.3//EN""http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"><validators><field name="username"><field-validator type="requiredString"><message>請輸入用戶名</message></field-validator></field></validators>Struts.xml中代碼<package name="user" extends="struts-default"><action name="findAll" class="com.action.UserAction"><result>/success.jsp</result></action><action name="regist" class="com.action.UserAction" method="regist"><result type="redirect">/success.jsp</result><result type="exists">/message.jsp</result><result type="input">/success.jsp</result> <%--視圖回顯--%></action></package>此時的操作就只是單純針對于regist
只是單純地配置validation.xml并不能滿足對輸入數據的檢查要求, 它只能做到根據field標簽中type類型來檢查數據, 所以需要使用驗證器參數注入增強驗證功能 常用驗證器自行百度 驗證器參數注入有兩種方式, 如下: 基于字段: 先獲取需要驗證的字段名, 然后對其內容進行驗證 例如:
<validators><field name="username"><field-validator type="requiredString"><param name="trim">false</param><message>請輸入用戶名</message></field-validator></field></validators>上面針對type為requireString的驗證器做trim注入, 將該驗證器的trim屬性設置為false表示驗證器不除去空格
基于驗證器: 先判斷當前需要驗證的類型屬于哪一類, 然后再判斷需要驗證哪個字段
例如:
<validators type="requiredString"><validator><param name="fieldname">username</param><message>請輸入用戶名</message></validator></validators>對username做注入, 表示對username做判斷requiredString操作
注: 一個驗證器只能處理一個驗證請求, 需要對同一屬性做多種條件判斷, 需要多個< field-validator>, 例如對password判斷, 需要判斷password長度, 以及password是否為已輸入.
<validators><field name="password"><field-validator type="requiredString"><message>請輸入密碼</message></field-validator><field-validator type="stringlength"><param name="minlength">3</param><param name="maxlength">8</param><message>密碼長度${minlength}~${maxlength}</message></field-validator></field></validators>
還需要注意的是, 密碼中含有特殊字符, 可以將密碼作為文本處理, 防止特殊字符出錯
上面有錯, 還請指出, 如果認為我寫的還不錯, 還請點個贊, 多多支持一下, O(∩_∩)O~~
總結
以上是生活随笔 為你收集整理的Struts2_2_解决配置文件冗余_动作类对象数据封装_数据类型转换_表单数据信息提示 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。