Struts2學習之2(請求引數的封裝,型別轉換,輸入驗證,自定義攔截器)
封裝請求引數
動態引數注入(請求引數,使用者輸入的)
方式一(動作類作為模型)
- 頁面
<form action="${pageContext.request.contextPath}/q1/login.do" method="post">
<!-- name屬性對應著動作類中的屬性-->
UserName:<input name="userName" type="text"/><br/>
Password:<input name="password" type="password"/><br />
<input type="submit" value="登入"/>
</form>
- 動作類
package com.jyh.action;
import com.opensymphony.xwork2.ActionSupport;
@SuppressWarnings("serial")
public class UserAction extends ActionSupport {
//編寫與表單裡面名字相同的私有屬性並提供相應的getset方法
private String userName;
private String password;
public void setUserName(String userName) {
this.userName = userName;
}
public void setPassword(String password) {
this.password = password;
}
public String getUserName() {
return userName;
}
public String getPassword() {
return password;
}
public String login(){
System.out.println(userName + ":" + password);
if("jyh".equals(userName) && "123".equals(password))
return SUCCESS;
return ERROR;
}
}
方式二(動作類和模型分開)
- 頁面
<form action="${pageContext.request.contextPath}/q2/login.do" method="post">
<!-- name屬性中person代表著動作類中模型物件的例項 -->
UserName:<input name="person.userName" type="text"/><br/>
Password:<input name="person.password" type="password"/><br/>
<input type="submit" value="登入"/>
</form>
- 動作類
package com.jyh.action;
import com.jyh.domain.Person;
import com.opensymphony.xwork2.ActionSupport;
@SuppressWarnings("serial")
public class PersonAction extends ActionSupport {
private Person person = new Person();
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
public String login(){
System.out.println(person);
if("jyh".equals(person.getUserName()) && "123".equals(person.getPassword()))
return SUCCESS;
return ERROR;
}
}
方式三(動作類和模型分開,使用ModelDriven模型驅動)
- 頁面
<form action="${pageContext.request.contextPath}/q3/login.do" method="post">
UserName:<input name="userName" type="text"/><br/>
Password:<input name="password" type="password"/><br/>
<input type="submit" value="登入"/>
</form>
- 動作類
package com.jyh.action;
import com.jyh.domain.Person;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
@SuppressWarnings("serial")
public class PersonAction2 extends ActionSupport implements ModelDriven<Person>{
private Person person = new Person();
public String login(){
System.out.println(person);
if("jyh".equals(person.getUserName()) && "123".equals(person.getPassword()))
return SUCCESS;
return ERROR;
}
@Override
public Person getModel() {
return person;
}
}
模型就是JavaBean模型類,該功能是由modelDriven攔截器完成的,與struts2的值棧有關。
靜態引數注入
就是在struts.xml配置檔案中的action下面配置引數<param name="name">名字</param>
,
然後就給動作類對應的屬性賦值了。
引數注入是由兩個攔截器來完成。
靜態引數注入:staticParams
動態引數注入:params
自定義型別轉換
編寫型別轉換實現類
package com.jyh.convertors;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import org.apache.struts2.util.StrutsTypeConverter;
//1、實現MM/dd/yyyy<------>java.util.Date互相轉換
@SuppressWarnings("all")
public class MyDateConverter extends StrutsTypeConverter {
private DateFormat df = new SimpleDateFormat("MM/dd/yyyy");
//String--->其他型別:Date
/**
* String[] values:使用者輸入的值.
* Class toClass:目標型別
*/
public Object convertFromString(Map context, String[] values, Class toClass) {
if(toClass!=Date.class){
throw new RuntimeException("您轉換的不是日期,請選擇別的轉換器");
}
if(values==null||values.length==0)
throw new IllegalArgumentException("沒有資料");
String sDate = values[0];//使用者輸入的是""
if(!sDate.trim().equals("")){
try {
return df.parse(sDate);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
return null;
}
//其他型別:Date---->String
/**
* Object o:物件
*/
public String convertToString(Map context, Object o) {
if(!(o instanceof Date)){
throw new RuntimeException("您的資料不是日期,請選擇別的轉換器");
}
Date date = (Date)o;
return df.format(date);
}
}
宣告定義配置
區域性型別轉換器,為某個類的某個屬性欄位進行驗證
- 動作和模型分開
配置檔案放在模型類所在包,檔名為:模型類名-conversion.properties
- 動作和模型不分開
配置檔案放在動作類所在包,檔名為:動作類名-conversion.properties
全域性轉換器,為某個型別進行驗證
配置檔案放在構建路徑頂端,檔名為:xwork-conversion.properties,裡面一般是需要驗證的型別對應自定義的轉換器,比如java.util.Date=com.jyh.convertors.MyDateConverter。
轉換失敗之後的提示
- 轉換失敗,會自動轉到一個name=input的邏輯檢視,一般指向輸入的那個頁面,目的回顯(建議使用struts2的表單標籤)
- 錯誤訊息提示中文版本
前提:動作類繼承ActionSupport才能使用。
檔名為:類名.properties
總結就是轉換器配置檔名為:需要驗證的屬性所在類的類名-conversion.properties
中文提示資訊的配置檔名為:被驗證的屬性所在類的類名.properties
輸入驗證
程式設計式驗證
缺點:驗證規則寫到了程式碼中,硬編碼。
優點:驗證時可以控制的更加精細。(用的少)
針對所有方法進行驗證
1.動作類需要實現ActionSupport,覆蓋掉public void validate(){}方法,
2.方法內部:編寫你的驗證規則,不正確的情況呼叫addFieldError新增錯誤資訊
public void validate() {
if("".equals(student.getUsername())){
addFieldError("username", "請輸入使用者名稱");
}
}
使用username這種方式新增錯誤資訊s:fieldError標籤中和普通標籤中都有錯誤提示訊息,使用了,將只會在s:fieldError中顯示錯誤訊息
3.驗證失敗:
檢視:會自動轉向一個name=input的邏輯檢視
錯誤訊息提示:建議使用struts2標籤庫。如果沒有顯示請使用s:fieldError標籤
針對指定的方法進行驗證
方式一
在指定方法前面新增一個註解:@SkipValidation,有該註解的方法就不會進行驗證
方式二
在需要驗證的方法,編寫一個方法,命名為validate+需要驗證的方法名,需要驗證的方法名首字母需要大寫,如:如果一個動作方法名叫做regist,只針對該方法進行驗證,就編寫public void validateRegist(){};
宣告式驗證
優點:把驗證規則寫到了配置檔案中。(用得多)
缺點:不是很精細。
錯誤檢視和訊息提示和程式設計式一致。
針對所有方法進行驗證
在動作類所在的包中建立:動作類名-validation.xml配置檔案。
頭部宣告可以在struts包/xwork-core-xxx.jar/xwork-validator-xxx.dtd中找到,該dtd檔案就是驗證配置檔案的約束。
針對指定的方法進行驗證
檔名改為:動作類名-動作名(struts.xml中action的name屬性)-validation.xml
說明:驗證功能是由validation攔截器來負責處理的。回顯錯誤資訊是由workflow攔截器來負責處理的。
struts2中提供的內建宣告式驗證器的使用
Struts2提供的宣告式驗證器在xwork-core-**.jar包的
com.opensymphony.xwork2.validator.validators.default.xml配置檔案中。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
"-//Apache Struts//XWork Validator Definition 1.0//EN"
"http://struts.apache.org/dtds/xwork-validator-definition-1.0.dtd">
<!-- START SNIPPET: validators-default -->
<validators>
<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"/>
</validators>
<!-- END SNIPPET: validators-default -->
驗證配置檔案寫法:
<?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是欄位名。和表單一致 -->
<field name="username">
<!-- 必須由3~8位字母組成-->
<field-validator type="regex"><!-- type為驗證型別,也就是驗證器的名字 -->
<param name="regexExpression"><![CDATA[[a-zA-Z]{3,8}]]></param><!-- param是指定驗證器的屬性引數 -->
<message>你的名字必須由3~8位字母組成</message><!-- message是返回的錯誤資訊 -->
</field-validator>
</field>
<!-- 驗證密碼必須3~8位數字組成:換一種 -->
<!--
<validator type="regex">
<param name="fieldName">password</param>
<param name="regexExpression"><![CDATA[\d{3,8}]]></param>
<message>你的密碼必須由3~8位數字組成</message>
</validator>
-->
<field name="password">
<field-validator type="requiredstring">
<message>請輸入密碼</message>
</field-validator>
<field-validator type="strongpassword">
<message>你的密碼必須由大小寫字母和數字組成</message>
</field-validator>
</field>
<!-- 必須選擇性別 -->
<field name="gender">
<field-validator type="required">
<message>請選擇性別</message>
</field-validator>
</field>
<field name="email">
<field-validator type="email">
<message>請輸入正確的郵箱</message>
</field-validator>
</field>
</validators>
自定義宣告式驗證
驗證密碼的強度:至少一個大寫、小寫、數字組成。
1.驗證的實現:編寫一個類,繼承FieldValidatorSupport。
package com.jyh.validators;
import com.opensymphony.xwork2.validator.ValidationException;
import com.opensymphony.xwork2.validator.validators.FieldValidatorSupport;
public class StrongPasswordValidator extends FieldValidatorSupport {
private boolean trim = true;
public boolean isTrim() {
return trim;
}
public void setTrim(boolean trim) {
this.trim = trim;
}
// Object object:當前執行的動作類
public void validate(Object object) throws ValidationException {
String fieldName = getFieldName();// 當前要驗證的欄位名
Object value = this.getFieldValue(fieldName, object);// 獲取使用者輸入的值
if (!(value instanceof String)) {
addFieldError(fieldName, object);
} else {
String s = (String) value;
if (trim) {
s = s.trim();
}
if (!isPasswordStrong(s)) {
addFieldError(fieldName, object);
}
}
}
private static final String GROUP1 = "abcdefghijklmnopqrstuvwxyz";
private static final String GROUP2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String GROUP3 = "0123456789";
protected boolean isPasswordStrong(String password) {
boolean ok1 = false;
boolean ok2 = false;
boolean ok3 = false;
int length = password.length();
for (int i = 0; i < length; i++) {
if (ok1 && ok2 && ok3)
break;
String character = password.substring(i, i + 1);
if (GROUP1.contains(character)) {
ok1 = true;
continue;
}
if (GROUP2.contains(character)) {
ok2 = true;
continue;
}
if (GROUP3.contains(character)) {
ok3 = true;
continue;
}
}
return ok1 && ok2 && ok3;
}
}
2.驗證的宣告:在構建路徑頂端,建立一個固定名稱為validators.xml的配置檔案,配置檔案參考
xwork-core-xxx.jar包的com.opensymphony.xwork2.validator.validators.default.xml。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
"-//Apache Struts//XWork Validator Definition 1.0//EN"
"http://struts.apache.org/dtds/xwork-validator-definition-1.0.dtd">
<validators>
<!-- name為驗證器的名字,class為驗證器的實現類 -->
<validator name="strongpassword" class="com.jyh.validators.StrongPasswordValidator"/>
</validators>
3.驗證器的使用
<field name="password">
<field-validator type="requiredstring">
<message>請輸入密碼</message>
</field-validator>
<!-- type為驗證器的name屬性 -->
<field-validator type="strongpassword">
<message>你的密碼必須由大小寫字母和數字組成</message>
</field-validator>
</field>
自定義攔截器
編寫一個類,繼承AbstractInterceptor抽象類或者MethodFilterInterceptor抽象類
package com.jyh.interceptors;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
@SuppressWarnings("serial")
//繼承MethodFilterInterceptor可以有選擇的進行攔截與不攔截
public class Demo1Interceptor extends MethodFilterInterceptor/*AbstractInterceptor*/{
public String doIntercept(ActionInvocation invocation) throws Exception {
System.out.println("攔截前");
String valueString = invocation.invoke();//放行
System.out.println("攔截後");
return valueString;
}
}
宣告定義與使用自定義攔截器
<!-- 定義一個包,用來進行攔截器的定義初始化 -->
<package name="myDefaultPackage" extends="struts-default">
<!-- 宣告定義攔截器 -->
<interceptors>
<!-- 攔截器名和其實現類 -->
<interceptor name="demo1Interceptor" class="com.jyh.interceptors.Demo1Interceptor"></interceptor>
<!-- 定義一個攔截器棧 -->
<interceptor-stack name="mydefault">
<!-- 包含預設的defaultStack棧 -->
<interceptor-ref name="defaultStack"></interceptor-ref>
<!-- 包含自己定義的攔截器 -->
<interceptor-ref name="demo1Interceptor"></interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 覆蓋預設的攔截器棧 -->
<default-interceptor-ref name="mydefault"></default-interceptor-ref>
</package>
<!-- 繼承剛剛定義的包 -->
<package name="demo" extends="myDefaultPackage" namespace="/demo">
<action name="demo1" class="com.jyh.action.Demo1Action" method="add">
<!-- 使用攔截器,將會 覆蓋所有預設攔截器 -->
<interceptor-ref name="demo1Interceptor">
<!-- 新增引數excludeMethods代表不攔截,後面為不攔截的方法名(當前訪問的方法名)
includeMethods代表攔截 -->
<param name="excludeMethods">add</param>
</interceptor-ref>
<result name="success">/demo1.jsp</result>
</action>
<action name="demo2" class="com.jyh.action.Demo1Action" method="del">
<!-- 使用攔截器棧,將會 覆蓋所有預設攔截器,但是因為繼承了預設的攔截器棧,所以儲存了預設的攔截器 -->
<interceptor-ref name="mydefault"></interceptor-ref>
<result name="success">/demo1.jsp</result>
</action>
</package>