文檔版本 | 開發工具 | 測試平臺 | 工程名字 | 日期 | 作者 | 備註 |
---|---|---|---|---|---|---|
V1.0 | 2016.06.14 | lutianfei | none |
struts2中獲取請求參數
- 在struts2中action是什麼?(struts2是一個mvc框架)
- View : jsp
- Model : action
- Control : action & StrutsPrepareAndExecuteFilter
1.屬性驅動
1.直接將action做一個model(類似bean結構),就可以得到請求參數.
- 問題1:action封裝請求參數,會不會存在線程安全問題?
- 不會:因爲每一次請求,都是一個新的action。
- 缺點:需要單獨定義javaBean,將action中屬性copy到javaBean中。
- 優點:簡單。
- 這種方式,底層是通過反射來實現的。
- 問題1:action封裝請求參數,會不會存在線程安全問題?
配合第一天作業案例,修改Login1Action.java
private String username;
private String password;
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;
}
@Override
public String execute() throws Exception {
HttpServletRequest request = ServletActionContext.getRequest();
// 2.判斷用戶名與密碼是否正確
if ("tom".equals(username) && "123".equals(password)) {
request.getSession().setAttribute("username", username);
return SUCCESS;
} else {
request.setAttribute("login.message", "用戶名或密碼錯誤");
return "failer";
}
}
}
2.在action中聲明一個model。
- 在頁面上使用ognl來描述
- 注意修改:
<input type="text" name="user.username">
- 優點:簡單,解決了第一種封裝的問題
- 缺點:在頁面上使用了ognl表達式,頁面不通用了。
- 問題:這種方式,數據是怎樣封裝的?
- 通過struts2中的interceptor進行了數據封裝.
<interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
- 通過struts2中的interceptor進行了數據封裝.
Login2Action.java
//獲取請求參數 屬性驅動 第二種,直接在action聲明一個model
public class Login2Action extends ActionSupport {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String execute() throws Exception {
HttpServletRequest request = ServletActionContext.getRequest();
// 2.判斷用戶名與密碼是否正確
if ("tom".equals(user.getUsername()) && "123".equals(user.getPassword())) {
request.getSession().setAttribute("username", user.getUsername());
return SUCCESS;
} else {
request.setAttribute("login.message", "用戶名或密碼錯誤");
return "failer";
}
}
}
- login2.jsp
<body>
${requestScope["login.message"] }<br>
<form action="${pageContext.request.contextPath}/login2" method="post">
username:<input type="text" name="user.username"><br>
password:<input type="password" name="user.password"><br>
<input type="submit" value="登錄">
</form>
</body>
2.模型驅動(在開發中應用比較多)
- 開發步驟:
- 1.讓action類實現 ModelDriven
- 2.重寫getModel方法
- 3.在action中實例化一個model對象,讓getModel方法返回這個對象。
public class Login3Action extends ActionSupport implements ModelDriven<User> { //第一步:implements ModelDriven<User>
private User user = new User(); //第三步
public User getModel() { //第二步
return user;
}
}
//jsp
<body>
${requestScope["login.message"] }<br>
<form action="${pageContext.request.contextPath}/login3" method="post">
username:<input type="text" name="username"><br>
password:<input type="password" name="password"><br>
<input type="submit" value="登錄">
</form>
</body>
- 優點:解決了屬性驅動存在的問題
缺點:一次只能封裝一個model對象.
struts2 有很多圍繞模型驅動的特性
<interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>
爲模型驅動提供了更多特性
擴展
- 1.將數據封裝到List集合
頁面:
username1:<input type="text" name="users[0].username"><br>
password1:<input type="password" name="users[0].password"><br>
username2:<input type="text" name="users[1].username"><br>
password2:<input type="password" name="users[1].password"><br>
action類:
public class ListAction extends ActionSupport {
private List<User> users;
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
@Override
public String execute() throws Exception {
System.out.println(users);
return null;
}
}
//struts.xml配置
<action name="list" class="cn.itcast.action.ListAction">
</action>
- 2.將數據封裝到Map集合
頁面:
username1:<input type="text" name="map['aaa'].username"><br>
password1:<input type="password" name="map['aaa'].password"><br>
username2:<input type="text" name="map['bbb'].username"><br>
password2:<input type="password" name="map['bbb'].password"><br>
- action類:
public class MapAction extends ActionSupport {
private Map<String, User> map;
public Map<String, User> getMap() {
return map;
}
public void setMap(Map<String, User> map) {
this.map = map;
}
@Override
public String execute() throws Exception {
System.out.println(map);
return null;
}
}
struts2中提供的類型轉換
- 在web中我們使用beanutils直接將表單數據封裝到javaBean中。—類型轉換
struts2中action得到請求參數,也可以直接封裝到javaBean.
struts2 內部提供大量類型轉換器,用來完成數據類型轉換問題
- boolean 和 Boolean
- char 和 Character
- int 和 Integer
- long 和 Long
- float 和 Float
- double 和 Double
- Date 可以接收 yyyy-MM-dd格式字符串
- 數組 可以將多個同名參數,轉換到數組中
- 集合 支持將數據保存到 List 或者 Map 集合
但並不是所有的類型都支持
- 例如:日期類型,我們傳遞 yyyy-MM-dd yyyy年MM月dd日格式都可以,但是如果是yyyy/MM/dd就會出現問題.
關於struts2中的類型轉換器根接口是:
com.opensymphony.xwork2.conversion.TypeConverter
。
自定義類型轉換器
- 操作步驟:
- 1.創建一個類實現TypeConverter接口
- 2.重寫接口中方法,實現類型轉換操作
- 3.註冊類型轉換器
1.創建一個自定義類型轉換器
1.實現TypeConverter需要重寫如下方法:
public Object convertValue(Map<String, Object> context, Object target, Member member, String propertyName, Object value, Class toType);
如果實現接口,這個方法參數太多(6個),不推薦。
2.繼承 DefaultTypeConverter類
- 優點:重寫的方法參數沒有那麼多
public Object convertValue(Map<String, Object> context, Object value, Class toType) {return convertValue(value, toType);}
3.推薦使用 繼承
DefaultTypeConverter類
的一個子類StrutsTypeConverter
.- 原因:在這個類中將從頁面傳遞的數據怎樣封裝,以及action中的數據怎樣在頁面上顯示做了分離。
- convertFromString : 將頁面數據轉換至JavaBean
- convertToString : 將JavaBean轉換至頁面輸出
public abstract Object convertFromString(Map context, String[] values, Class toClass);
public abstract String convertToString(Map context, Object o);
2.註冊一個自定義類型轉換器
1.局部–針對於action(action中包含了一個Bean結構)
- 配置文件所在位置以及名稱: 在Action類所在包 創建
Action類名-conversion.properties
- 配置文件書寫格式 :
屬性名稱=類型轉換器的全類名
- 配置文件所在位置以及名稱: 在Action類所在包 創建
eg:
birthday= test.utils.MyTypeConverter
- MyTypeConverter.java
public class MyTypeConverter extends StrutsTypeConverter{
@Override
public Object convertFromString(Map context, String[] values, Class toClass) {
// System.out.println(context); //ognl.OgnlContext@faae2497
// System.out.println(values[0]); //1990/11/10
// System.out.println(toClass); //class java.util.Date
String value = values[0];
SimpleDateFormat sdf =new SimpleDateFormat("yyyy/MM/dd");
Date date = null;
try {
date = sdf.parse(value);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return date;
}
- RegistAction.java
public class RegistAction extends ActionSupport implements ModelDriven<User>{
private User user = new User();
@Override
public User getModel() {
//
return user;
}
@Override
public String execute() {
System.out.println(user);
return null;
}
}
- sturts.xml & regist.jsp
<struts>
<package name="default" namespace="/" extends ="struts-default">
<action name="regist" class = "test.action.RegistAction">
<result name="input">/success.jsp</result>
</action>
</package>
</struts>
<body>
<form action="${pageContext.request.contextPath}/regist" method="post">
username:<input type="text" name="username"><br>
password:<input type="password" name="password"><br>
hobby:<input type="checkbox" name="hobby" value="eat">吃<input
type="checkbox" name="hobby" value="drink">喝<input
type="checkbox" name="hobby" value="play">玩<br> age:<input
type="text" name="age"><br> birthday:<input type="text"
name="birthday"><br> <input type="submit" value="註冊">
</form>
</body>
2.局部–針對於model(action中實例化了一個Bean)
- 配置文件所在位置以及名稱: 在model類所在包 創建
model類名-conversion.properties
- 配置文件書寫格式 :
屬性名稱=類型轉換器的全類名
- 配置文件所在位置以及名稱: 在model類所在包 創建
eg:在上例的基礎上做如下修改
- 修改properties文件名及位置如下:
- 修改properties文件名及位置如下:
RegistAction.jsp
public class RegistAction extends ActionSupport {
private String username;
private String password;
private int age;
private Date birthday;
private String[] hobby;
public String[] getHobby() {
return hobby;
}
public void setHobby(String[] hobby) {
this.hobby = hobby;
}
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 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;
}
@Override
public String execute() throws Exception {
System.out.println(this.toString());
return null;
}
@Override
public String toString() {
return "RegistAction [username=" + username + ", password=" + password
+ ", age=" + age + ", birthday=" + birthday + ", hobby="
+ Arrays.toString(hobby) + "]";
}
}
3.全局
- 配置文件所在位置以及名稱:在src下創建一個
xwork-conversion.properties
- 配置文件書寫格式:
要轉換的類型全名=類型轉換器的全類名
- 配置文件所在位置以及名稱:在src下創建一個
eg:
- 在第一個例子的基礎上改成指定名字,並將其放在
src
目錄下就好。 - properties文件改爲:
java.util.Date=test.utils.MyTypeConverter
- 在第一個例子的基礎上改成指定名字,並將其放在
注意:
對於struts2中類型轉換器(非自定義),如果表單數據提交時,將數據向model封裝,出現了問題,會報錯:
No result defined for action cn.itcast.action.RegistAction and result input
意思是,在RegistAction的配置中沒有配置input結果視圖;當加入
result name=input
標籤時,會跳轉到對應的頁面(例如success.jsp)
<action name="regist" class="cn.itcast.action.RegistAction">
<result name="input">/success.jsp</result>
</action>
- 爲什麼會向input視圖跳轉?
- 因爲struts2中的攔截器(interceptor).
- 在struts2中的
<interceptor name="conversionError" class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/>
用於記錄類型轉換問題。 - 在struts2中
<interceptor name="workflow" class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/>
用於得到問題,向input視圖跳轉。
- 關於錯誤信息展示:
- 通過分析攔截器作用,得知當類型轉換出錯時,自動跳轉input視圖 ,在input視圖頁面中
<s:fieldError/>
顯示錯誤信息
- 通過分析攔截器作用,得知當類型轉換出錯時,自動跳轉input視圖 ,在input視圖頁面中
如果想通過國際化改爲中文顯示需要在Action所在包中,創建
ActionName.properties
,在局部資源文件中配置提示信息 :invalid.fieldvalue.屬性名= 錯誤信息
eg:
//注意加 taglib
<%@ taglib prefix="s" uri="/struts-tags" %>
<body>
<s:fielderror/>
</body>
//RegisAction.properties
invalid.fieldvalue.birthday=\u65E5\u671F\u683C\u5F0F\u8981\u6C42 yyyy/MM/dd
- 如果是自定義類型轉換器,出現類型轉換問題,要跳轉到input視圖,在類型轉換器中,必須拋出異常纔可以。
- eg : MyTypeConverter:第20行
public class MyTypeConverter extends StrutsTypeConverter {
// 接收頁面傳遞的數據封裝到javaBean.
@Override
public Object convertFromString(Map context, String[] values, Class toClass) {
// System.out.println(context); //ognl.OgnlContext@faae2497
// System.out.println(values[0]); //[Ljava.lang.String;@100c4d
// System.out.println(toClass); //class java.util.Date
String value = values[0];
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
Date date = null;
try {
date = sdf.parse(value);
} catch (ParseException e) {
// e.printStackTrace();
throw new RuntimeException();
}
return date;
}
關於struts2提供的數據校驗
在開發中,請求參數是需要校驗的。
- 客戶端校驗—->js
- 服務器校驗—->java代碼。
struts2中提供的校驗—–服務器端校驗。
- 分成兩種:
- 1.手動校驗(編碼校驗)
- 2.配置校驗(annotation,xml) 我們講的是xml。
1.手動校驗(瞭解)
- 要求:action類必須繼承自ActionSupport。因爲需要重寫一個方法
validate
- 通過測試發現在action中重寫的validate方法執行了。並且是在請求處理方法(execute)之前執行的。
struts2提供的校驗,也是通過攔截器實現的。
問題:在validate方法中怎樣存儲校驗錯誤信息?
- 在validate方法中 this.addFieldError(Sting name,String value);
@Override
public void validate() {
if (user.getUsername() == null
|| user.getUsername().trim().length() == 0) {
// 說明用戶名爲空
this.addFieldError("username.message", "用戶名不能爲空");
}
if (user.getPassword() == null
|| user.getPassword().trim().length() == 0) {
this.addFieldError("password.message", "密碼不能爲空");
}
if (!(user.getAge() >= 10 && user.getAge() <= 40)) {
this.addFieldError("age.message", "年齡必須在10-40之間");
}
// System.out.println("validate......");
}
- 問題:在頁面上怎樣獲取錯誤信息?(在input視圖上)
<s:fielderror>
展示所有錯誤信息<s:fielderror fieldName="">
展示特定名稱的錯誤信息.
<s:fielderror/>
<form action="${pageContext.request.contextPath}/regist" method="post">
username:<input type="text" name="username"><s:fielderror fieldName="username.message"/><br>
password:<input type="password" name="password"><s:fielderror fieldName="password.message"/><br>
- 問題:在同一個Action中有多個請求處理方法(login,regist)那麼有些方法是需要校驗的,有些是不需要的,怎樣處理?
- 解決方案:創建一個名稱叫
validate+請求處理方法名
- 例如:請求處理方法叫
regist()
校驗的 方法名validateRegist()
- 如上情況下還有
validate
方法時,會先運行validateRegist()
方法,後運行validate()
方法。
- 解決方案:創建一個名稱叫
2.配置校驗(xml,常用)
- struts2的校驗框架。
已經完成了校驗操作(做了很多校驗方法)。而我們在使用時,只需要將它們調用就可以(通過配置文件)
要求:action類必須繼承自ActionSupport類。
校驗配置文件的配置方法
- 位置:xml文件要與action類在同一個包下
- 名稱:
action類名-validation.xml
- 約束:
xwork-core-2.3.7.jar
中xwork-validator-1.0.3.dtd
下
<!DOCTYPE validators PUBLIC
"-//Apache Struts//XWork Validator 1.0.3//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
- 書寫:
- 1.根元素
<validators>
- 2.子元素
<field name="屬性名稱"></field>
- 3.
<field>子元素
- 指定校驗器
<field-validator type="校驗器">
- 問題:校驗器有哪些?
- 校驗器位置:
xwork-core-2.3.7.jar
中 /com/opensymphony/xwork2/validator/validators/default.xml下
- 指定校驗器
- 1.根元素
<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"/>
- 4.
<field-validator>子元素
<message>錯誤信息</message>
5.
<field-validator>
子元素<param name="">值</param>
: 用於指定校驗器中的參數。
eg :
<validators>
<!-- 對username屬性進行校驗 -->
<field name="username">
<!-- 指定username不能爲空 -->
<field-validator type="requiredstring">
<!-- 錯誤信息 -->
<message>用戶名不能爲空--------</message>
</field-validator>
</validators>
配置校驗中的常用校驗器
required
(必填校驗器,要求被校驗的屬性值不能爲null)requiredstring
(必填字符串校驗器,要求被校驗的屬性值不能爲null,並且長度大於0,默認情況下會對字符串去前後空格),如果不想去空格,只需如下設置。
stringlength
(字符串長度校驗器,要求被校驗的屬性值必須在指定的範圍內,否則校驗失敗- minLength參數指定最小長度
- maxLength參數指定最大長度
- trim參數指定校驗field之前是否去除字符串前後的空格
regex
正則表達式校驗器,檢查被校驗的屬性值是否匹配一個正則表達式,expression參數指定正則表達式,caseSensitive參數指定進行正則表達式匹配時,是否區分大小寫,默認值爲true)
int(整數校驗器,要求field的整數值必須在指定範圍內
- min指定最小值
- max指定最大值
double
(雙精度浮點數校驗器,要求field的雙精度浮點數必須在指定範圍內,min指定最小值,max指定最大值)fieldexpression
(字段OGNL表達式校驗器,要求field滿足一個ognl表達式,expression參數指定ognl表達式,該邏輯表達式基於ValueStack進行求值,返回true時校驗通過,否則不通過)
email
(郵件地址校驗器,要求如果被校驗的屬性值非空,則必須是合法的郵件地址)
url(網址校驗器,要求如果被校驗的屬性值非空,則必須是合法的url地址)
date
:日期校驗器,要求field的日期值必須在指定範圍內- min指定最小值
- max指定最大值
問題:通過配置校驗,怎樣處理在同一個action中存在多個請求處理方法校驗問題?
- 只需要將校驗xml文件名稱修改就可以。
- 原名稱:
action類名-valication.xml
現在要對action類中某一個方法校驗。 - 修改名稱:
action類名-action名稱-validation.xml
- 原名稱:
- 只需要將校驗xml文件名稱修改就可以。