struts2中的參數封裝
靜態參數封裝
什麼是靜態參數?
靜態參數就是硬編碼的,不可隨意改變。
例子:
我們首先創建一個Action類,裏面有兩個參數,用來封裝請求參數
public class User 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 void setAge(int age) {
this.age = age;
}
public String adduser(){
System.out.println(username+":"+age);
return null;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
我們在struts.xml中配置靜態參數
<package name="p1" extends="struts-default">
<action name="action1" class="com.cad.struts2.User" method="adduser">
<!--通過注入的方式封裝靜態參數-->
<param name="username">張三</param>
<param name="age">18</param>
</action>
</package>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
我們訪問action1動作時,會輸出 張三:18
- 1
- 2
我們配置的靜態參數怎麼就被傳遞到動作類裏呢?
我們在struts2的運行流程中提到過,我們動作類的動作方法執行之前,會有一系列的攔截器幫我們執行一些操作。
在struts-default.xml中,有很多攔截器,攔截器又分爲很多攔截器棧,我們默認是使用defaultStack的攔截器棧。
這個攔截器棧中有一個叫做staticParams的攔截器幫我們完成靜態參數的封裝,將配置的靜態方法通過action類中的set方法設置進去。
- 1
- 2
- 3
- 4
- 5
- 6
動態參數封裝
什麼是動態參數?
像我們用表單提交的數據,就是動態數據。數據是可變的。
- 1
- 2
例子:
第一步:我們先創建一個添加用戶的表單
<form action="${pageContext.request.contextPath }/action1" method="post">
用戶名:<input type="text" name="username"><br>
年 齡:<input type="text" name="age"><br>
<input type="submit" value="提交">
</form>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
第一種方式:數據參數和動作類寫在一起
要求是表單中的name必須和我們類中的set方法後面的名稱一致,例如表單中的username對應類中的setUsername,和參數並沒有太大關係,和set方法有關係。
public class User 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 void setAge(int age) {
this.age = age;
}
public String adduser(){
System.out.println(username+":"+age);
return null;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
配置struts.xml文件
<package name="p1" extends="struts-default">
<action name="action1" class="com.cad.struts2.User" method="adduser">
</action>
</package>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
我們訪問添加用戶頁面,添加數據,會輸出我們添加的數據。
這一系列操作是由攔截器棧中的名爲params的攔截器幫我們完成的
上面這種方式將參數和動作類寫在一起,看起來太過混亂,我們能不能用一個JavaBean將參數給封裝起來。 答案是能。
第二種方式,將參數數據和動作類分開寫
第一步,我們創建一個javaBean,User類,用來封裝請求參數
public class User implements Serializable{
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 void setAge(int age) {
this.age = age;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
第二步:創建一個添加用戶的動作類,裏面有一個user對象
public class AdduserAction extends ActionSupport {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String adduser(){
System.out.println(user.getUsername()+":"+user.getAge());
return null;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
第三步:我們得改變一些我們的jsp頁面的寫法,因爲表單的name要和類中的數據相對應,但類中只有一個user ,username去找動作類中的setUsername,肯定找不到。
我們這樣寫,他就會先找類中的user對象,然後去找user對象的username和age
<body>
<form action="${pageContext.request.contextPath }/action1" method="post">
用戶名:<input type="text" name="user.username"><br>
年 齡:<input type="text" name="user.age"><br>
<input type="submit" value="提交">
</form>
</body>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
原理:
這一系列操作還是攔截器params幫我們完成。我們在getUser和setUser裏打印兩句話來看看他到底是怎麼執行的
public User getUser() {
System.out.println("getuser");
return user;
}
public void setUser(User user) {
System.out.println("setuser");
this.user = user;
}
輸出
getuser :先判斷對象是否存在
setuser :如果判斷不存在,調用set方法,通過反射創建一個對象,並且設置給該類
getuser :然後再獲取該對象,調用該對象的get和set方法對參數賦值
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
模型驅動和屬性驅動
出於結構清晰的考慮,應該採用單獨的Model實例來封裝請求參數和處理結果,這就是所謂的模型驅動,
所謂模型驅動,就是使用單獨的JavaBean來貫穿整個MVC流程。
所謂屬性驅動,就是使用屬性來作爲貫穿MVC流程的信息攜帶者,當然屬性必須依附於對象,這個對象就是Action實例。
簡單說,模型驅動就是使用單獨的javaBean封裝請求參數。
屬性驅動就是把屬性寫在Action類中。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
我們發現上面的jsp中的name必須前面得加 user.username。。太過麻煩。我們使用模型驅動來解決這個問題。實際開發中使用這種方式
模型驅動的要求:
1.動作類實現ModelDriven接口
2.實現接口中的getModel方法,返回我們的數據對象
3.數據模型對象必須由我們實例化。
我們改進動作類
public class AdduserAction extends ActionSupport implements ModelDriven<User>{
//數據模型對象由我們實例化
private User user=new User();
public User getUser() {
System.out.println("getuser");
return user;
}
public void setUser(User user) {
System.out.println("setuser");
this.user = user;
}
public String adduser(){
System.out.println(user.getUsername()+":"+user.getAge());
return null;
}
//實現接口方法,返回我們的數據模型對象
public User getModel() {
// TODO Auto-generated method stub
return user;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
我們在jsp上就能像以前那樣 ,name只用我們的參數相同即可
<body>
<form action="${pageContext.request.contextPath }/action1" method="post">
用戶名:<input type="text" name="username"><br>
年 齡:<input type="text" name="age"><br>
<input type="submit" value="提交">
</form>
</body>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
原理:
其實這時候表單的name已經不僅僅是一個簡單的字符串了。
這一系列的操作是由ModelDriven和params攔截器幫我們做的 。
params攔截器負責提取請求參數,如果是屬性驅動模式,則還負責將請求參數傳給Action類的屬性
模型驅動的話就只提取請求參數。
ModelDriven攔截器會先判斷我們的動作類是否屬於ModelDriven類型
屬於的話,就調用我們實現的getModel方法,獲取我們傳入的對象
然後將我們的對象給壓入棧中
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
struts2註冊案例
第一步:我們先創建數據庫表
create database demo;
use demo;
create table user(
username varchar(100) primary key,
password varchar(100),
birthday date,
hobby varchar(255),
married boolean
);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
第二步:在domain包創建我們的user實體類
public class User {
private String username;//用戶名
private String password;//密碼
private Date birthday; //生日
private String hobby; //愛好
private boolean married; //是否結婚
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 Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
public boolean isMarried() {
return married;
}
public void setMarried(boolean married) {
this.married = married;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
第三步:完成數據層,我們在Dao層處理數據
public class UserDao {
QueryRunner qr=new QueryRunner(JdbcUtils.getDataSource());
//根據名字查找用戶
public User findUserByUsername(String username){
try {
String sql="select * from user where username=?";
return qr.query(sql, new BeanHandler<User>(User.class),username);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//添加用戶
public int addUser(User user){
String sql="insert into user values(?,?,?,?,?)";
Object []params={user.getUsername(),user.getPassword(),user.getBirthday(),user.getHobby(),user.isMarried()};
try {
return qr.update(sql,params);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
第四步:完成業務邏輯層的編寫,service層
public class UserService {
private UserDao userdao=new UserDao();
//註冊
public int regist(User user){
return userdao.addUser(user);
}
//通過用戶名查找用戶
public User findByUsername(String username){
return userdao.findUserByUsername(username);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
第五步:創建web層,我們創建web層動作類
public class UserAction extends ActionSupport implements ModelDriven{
private User user=new User();
private UserService userservice=new UserService();
//註冊方法
public String regist(){
User _user=userservice.findByUsername(user.getUsername());
//判斷用戶是否存在,存在返回exists字符串
if(_user!=null){
return "exists";
}
//獲取註冊成功更新的行數
int count=userservice.regist(user);
//如果>0,返回success
if(count>0){
return SUCCESS;
}
return null;
}
public Object getModel() {
// TODO Auto-generated method stub
return user;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
第六步:我們編寫註冊的jsp頁面
<body>
<form action="${pageContext.request.contextPath }/regist.action" method="post">
用戶名:<input type="text" name="username"><br>
密 碼:<input type="password" name="password"><br>
生 日:<input type="text" name="birthday"><br>
愛好:<input type="checkbox" name="hobby" value="籃球">籃球
<input type="checkbox" name="hobby" value="足球">足球
<input type="checkbox" name="hobby" value="寫代碼">寫代碼<br>
已婚:<input type="checkbox" name="married" value="true"><br>
<input type="submit" name="註冊"><br>
</form>
</body>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
第七步:配置 struts.xml
<package name="p1" extends="struts-default">
<action name="regist" class="com.cad.web.action.UserAction" method="regist">
<result name="success">/success.jsp</result>
<result name="exists">/msg.jsp</result>
</action>
</package>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
struts2的異常處理機制
成熟的MVC框架應該提供成熟的異常處理機制。當然可以在方法中手動捕捉異常,當捕捉到特定異常時,返回特定邏輯視圖名。
這種方式非常繁瑣,需要在方法中寫大量try catch塊,最大的缺點還是一旦需要改變異常處理方法時,需要修改代碼。
最好的方式是通過聲明式的方式管理異常處理。struts2提供了一種聲明式的異常處理方式。
struts2的異常處理
我們看Action接口中的execute方法聲明。
public String execute() throws Exception
這就意味着我們重寫該方法時,無需進行任何異常處理,而是把異常拋給struts2框架處理.
struts2框架接收到Action拋出的異常後,根據struts.xml文件配置的異常映射,轉入指定的視圖資源。
異常映射功能是由 exception的攔截器幫我們做的。
struts2的異常處理機制是通過在struts.xml中配置<exception-mapping..../>元素完成。
屬性:
exception:異常類型
result:出現該異常時,系統轉入result指定的結果
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
局部異常映射和全局異常映射
全局異常映射對所有的Action都有效,但局部異常映射只對該異常映射所在的Action有效。
如果全局異常映射和局部異常映射配置了同一個異常類型,在該Action內,局部覆蓋全局。
局部異常映射:將<exception-mapping..../>元素作爲<action.../>的子元素配置
全局異常映射:將<exception-mapping..../>元素作爲<global-exception-mappings>元素的子元素配置
- 1
- 2
- 3
- 4
異常處理案例
我們做一個簡單的登陸應用
第一步:我們編寫我們的Action類
public class LoginAction implements Action{
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;
}
public String execute()throws Exception{
//當用戶名爲monster時,拋出我們的自定義異常
if(getUsername().equals("monster")){
throw new MyException("自定義異常");
}
//當用戶名爲sql時,拋出sql異常
if(getUsername().equalsIgnoreCase("sql")){
throw new SQLException("用戶名不能爲sql");
}
if(getUsername().equals("cad")&&getPassword().equals("123456")){
return "success";
}else
{
return "error";
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
第二步:我們編寫我們的登陸jsp頁面
<body>
<form action="${pageContext.request.contextPath }/login" method="post">
用戶名:<input type="text" name="username"><br>
密 碼:<input type="password" name="password"><br>
<input type="submit" value="提交">
</form>
</body>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
第三步:我們編寫我們的配置文件struts.xml
<package name="p2" extends="struts-default">
//全局結果視圖定義
<global-results>
<result name="sql">/exception.jsp</result>
</global-results>
//全局異常定義
<global-exception-mappings>
//出現sql異常,就轉入到視圖名爲sql的視圖結果
<exception-mapping result="sql" exception="java.sql.Exception"></exception-mapping>
</global-exception-mappings>
<action name="login" class="com.cad.struts2.LoginAction" >
//局部異常定義
<exception-mapping result="my" exception="conm.cad.struts2.MyException"></exception-mapping>
<result name="my">/exception.jsp</result>
<result name="success">/welcome.jsp</result>
<result name="error">/error.jsp</result>
</action>
</package>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
struts2的未知處理器
從struts2.1開始,struts2增加了未知處理器。
當用戶請求未知Action,或指定Action裏的未知方法,或Action處理結束後返回一個未知的result。struts2允許使用未知處理器來處理這些情況。
未知處理器需要實現UnknownHandler接口,該接口包含三個方法
-handleUnknownAction:用戶請求未知Action時,該方法會被回調
-handleUnknownActionMethod:用戶請求指定Action的未知方法時,該方法會被回調
-handleUnknownResult:Action處理結束後返回一個未知Result時,該方法會被回調
一旦實現了自定義的未知處理器,就可以在struts.xml中通過<bean../>元素來配置未知處理器
例如
<bean name="myHandler" class="com.cad.struts2.MyUnknownHandler" type="com.opensymphony.xwork2.UnknownHandler"></bean>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
未知處理器案例
第一步:我們實現我們簡單的未知處理器
public class MyUnknownHandler implements UnknownHandler {
public ActionConfig handleUnknownAction(String namespace, String actionName) throws XWorkException {
System.out.println(actionName+"不存在");
return null;
}
public Result handleUnknownResult(ActionContext actionContext, String actionName, ActionConfig actionConfig,
String resultCode) throws XWorkException {
System.out.println(resultCode+"不存在");
return null;
}
public Object handleUnknownActionMethod(Object action, String methodName) throws NoSuchMethodException {
System.out.println(methodName+"不存在");
return null;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
第二步:在struts.xml中配置未知處理器
//定義我們的未知處理器
<bean name="myHandler" class="com.cad.struts2.MyUnknownHandler" type="com.opensymphony.xwork2.UnknownHandler"></bean>
<package name="p3" extends="struts-default">
<action name="myAction"></action>
</package>
//定義未知處理器棧
<unknown-handler-stack>
<unknown-handler-ref name="myHandler"></unknown-handler-ref>
</unknown-handler-stack>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
然後我們訪問myAction,會輸出success不存在。
是因爲不指定action的class屬性時,默認使用ActioSupport
一般未知處理器主要處理Action返回未知result時有用。
瞭解即可。
- 1
- 2
- 3
- 4
- 5
struts2的類型轉換
所有的MVC框架,都屬於表現層的解決方案,都需要負責收集用戶請求參數,並將請求參數傳給應用的控制器組件。
這時問題出現了,所有的請求參數都是字符串類型數據,因此MVC框架必須具備將這些字符串請求參數轉換成相應的數據類型。
struts2提供了非常強大的類型轉換機制,struts2的類型轉換是基於OGNL表達式。
struts2提供了很好的擴展性,開發者可以開發出自己的類型轉換器。完成字符串到自定義類型之間的轉換。
如果類型轉換中出現未知異常,開發者無須關心異常處理,struts2的conversionError攔截器會自動處理該異常,並且在頁面上生成提示信息。
servlet中的類型轉換
表單中提交的所有數據都是字符串類型
例如我們有一個User類,name爲String類型,age爲int類型,birthday爲Date類型,我們必須在servlet中獲取表單傳入的參數,然後將其進行類型轉換,然後封裝到User對象中。
上述需要程序員自己進行類型轉換操作,比較繁瑣。
對於一個MVC框架而言,一樣需要將請求參數封裝成對象,也必須將請求參數轉換成對象屬性的數據類型,這就是類型轉換的意義。
Struts2內建的類型轉換器
struts內建的類型轉換器能自動將我們的表單數據(字符串)轉換成對應的數據類型。
完成字符串和日期類型之間的轉換時,日期格式必須使用請求用戶本地的格式。一般是yyyy-MM-dd,如果輸入的日期格式不是本地的日期格式,例如我們輸入1996/01/31,就會出現錯誤,類型轉換失敗。
自定義類型轉換器
需求:
當我們在表單中輸入的日期格式不是本地的格式時,就會出現類型轉換錯誤,我們也經常需要將字符串轉換成其他的格式,例如字符串轉換成對象之類的操作,這時我們就需要自定義類型轉換器。
struts2的類型轉換器實際上是基於OGNL實現的。xwork集成了OGNL。
實現類型轉換器必須實現TypeConverter接口。這個接口的方法太過複雜,所以還提供了一個該接口的實現類DefaultTypeConverter。
我們重寫DefaultTypeConverter類的convertValue方法即可。
我們基於DefaultTypeConverter類實現類型轉換器時,將字符串轉換成我們需要的類型通過convertValue方法實現,將我們的類型轉換成字符串也是通過convertValue方法實現,因此我們必須判斷轉換的類型來實現不同的邏輯。
爲了簡化類型轉換器的實現,struts2提供了一個StrutsTypeConverter抽象類,這個類是DefaultTypeConverter類的子類。
我們看下這個類的源碼 :
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
繼承DefaultTypeConverter
public abstract class StrutsTypeConverter extends DefaultTypeConverter {
//重寫DefaultTypeConverter類的convertValue方法
public Object convertValue(Map context, Object o, Class toClass) {
//如果要轉換的類型是字符串類型,也就是把我們的類型轉換成字符串,調用convertToString方法
if (toClass.equals(String.class)) {
return convertToString(context, o);
}
//如果參數是字符串數組,也就是將字符串轉換成我們需要的類型,調用convertFromString方法
else if (o instanceof String[]) {
return convertFromString(context, (String[]) o, toClass);
}
//如果參數是字符串,也就是將字符串轉換成我們需要的類型,調用convertFromString方法
else if (o instanceof String) {
return convertFromString(context, new String[]{(String) o}, toClass);
} else {
return performFallbackConversion(context, o, toClass);
}
}
protected Object performFallbackConversion(Map context, Object o, Class toClass) {
return super.convertValue(context, o, toClass);
}
//將字符串轉換成我們需要的類型的方法
public abstract Object convertFromString(Map context, String[] values, Class toClass);
//將我們的類型轉換成字符串的方法
public abstract String convertToString(Map context, Object o);
}
三個參數 :
Map context:OGNL的上下文。暫時還沒學,後面會學到,暫時不用管。
value:需要轉換的參數。
toClass:轉換後的類型
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
自定義類型轉換器案例
需求:我們將我們前面的註冊案例中的生日改成 yyyy/MM/dd類型
第一步:創建自定義類型轉換器
public class MyConverter extends StrutsTypeConverter {
//日期轉換器,轉換成指定的類型
private DateFormat format=new SimpleDateFormat("yyyy/MM/dd");
//將字符串轉換成日期類型
public Object convertFromString(Map context, String[] values, Class toClass) {
//判斷參數是否爲空
if(values==null||values.length==0){
return null;
}
//我們只有一個參數,就是表單的birthday
String date=values[0];
//判斷目標類型是否是Date
if(toClass==java.util.Date.class){
try {
//進行轉換
return format.parse(date);
} catch (ParseException e) {
e.printStackTrace();
}
}
return null;
}
//將日期類型轉換成字符串
public String convertToString(Map context, Object o) {
//判斷當前參數是否是日期類型
if(o instanceof java.util.Date){
return format.format(o);
}
return null;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
第二步:註冊類型轉換器
局部類型轉換器
按照屬性來註冊
如果屬性都在action中,那麼應該創建一個文件 Action名字-conversion.properties ,例如LoginAction-conversion.properties
如果屬性放到了javaBean中,那麼創建一個文件 javaBean名稱-conversion.properties 例如 User-conversion.properties
文件由鍵值對組成。
鍵爲需要轉換的屬性名字,值爲自己實現的類型轉換器全類名。
我們創建 User-conversion.properties
內容 birthday=com.cad.web.convert.MyConverter
這時我們註冊時使用 1996/01/24這種格式進行註冊就不會出現類型轉換錯誤。
用戶提交請求時,請求中的birthday參數會先被該類型轉換器處理。
全局類型轉換器
所有的Action都能用。我們需要在src目錄下創建一個 xwork-conversion.properties 的文件
因爲是全局的,就不存在只對birthday這個屬性進行轉換。
這裏的鍵是要轉換的類型,值還是類型轉換器類。
我們創建 xwork-conversion.properties
內容 java.util.Date=com.cad.web.convert.MyConverter
這樣當我們輸入日期的表單時,就可以使用我們自定義的日期格式。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
類型轉換中的錯誤處理
struts2提供了一個名爲conversionError的攔截器,這個攔截器被註冊在默認攔截器棧中。
當類型轉換器執行類型轉換出現錯誤時,該攔截器負責將對應錯誤封裝成表單域錯誤(fieldError),並將錯誤信息放入ActionContext中。
當攔截器對轉換異常進行處理後,系統會跳轉到名爲input的邏輯視圖。
我們在struts.xml中配置 <result name="input">/regist.jsp</result>
當類型轉換失敗後,再跳轉到註冊頁面
跳轉到input視圖以後,我們發現沒有任何錯誤提示信息。我們前面講過conversionError攔截器會將轉換錯誤封裝成fieldError,並放在ActionContext中。
爲了在頁面中輸出錯誤信息,我們需要使用struts的標籤。我們先使用一些,後面會詳細介紹。
我們在頁面添加<s:fielderror></s:fielderror>標籤
當我們類型轉換失敗後,就會輸出錯誤信息。
我們發現輸出的錯誤信息是英文的,我們希望能變爲中文的提示信息。
我們只需要在創建一個properties文件 文件名爲 javabean名稱.properties
鍵爲invalid.fieldvalue.屬性名稱 例如 :invalid.fieldvalue.birthday
值爲要輸出的內容 例如 invalid.fieldvalue.birthday=生日格式不正確
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
struts2的輸入校驗
輸入校驗是web應用必須處理的問題,要防止用戶的誤輸入和惡意非法輸入。struts2給我們提供了非常強大的輸入校驗體系。
輸入校驗分爲客戶端校驗和服務器端校驗。一般開發中兩者都用,但是服務端校驗必須使用。
客戶端校驗是通過javascript在表單頁面進行初步過濾。客戶端校驗並不安全,攻擊者有很多方法可以繞過客戶端校驗,所以服務端校驗是必不可少的。
但是客戶端校驗必不可少,因爲大多數瀏覽者都是正常用戶,可以阻止一些誤操作,降低了服務器的負載。
服務端校驗:
我們以前在servlet中增加校驗。是通過獲取參數,然後判斷參數是否爲空和長度等等來進行校驗。
在servlet中使用硬編碼進行輸入校驗乏味而又繁瑣,struts2提供了基於校驗框架的輸入校驗,只需要指定簡單的配置文件即可。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
聲明式驗證:通過xml配置文件進行驗證
-校驗規則文件與Action類放在同一目錄下
-校驗配置文件名稱爲 ActionClassName-validation.xml 例如 :UserAction-validation.xml
增加校驗文件後,系統會自動加載該文件。當用戶提交請求時,struts2會根據該文件對用戶數據進行校驗
- 1
- 2
- 3
- 4
- 5
基於表單字段的配置風格
<?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">
//指定校驗器,struts2有很多內建校驗器,requiredstring是校驗數據是否爲空並去除兩端空格
<field-validator type="requiredstring">
//校驗失敗後的提示信息
<message>用戶名不能爲空</message>
</field-validator>
</field>
</validators>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
校驗失敗後,struts2會返回名爲input的邏輯視圖名,因此我們還需要添加一個<result>
這個配置文件是全局驗證。也就是這個Action中的所有動作都會被驗證,我們Action有的方法並不需要驗證,加入驗證甚至會出錯。
我們有兩種方式可以讓不需要驗證的方法跳過驗證:
第一種:在不需要驗證的方法前面添加註解@SkipValidation
第二種:針對動作類中的某個方法進行驗證,創建的XML文件名爲 ActionClassName-ActionName-validation.xml ,這裏的ActionName不是方法名,而是配置的action名字 ,例如 :UserAction-regist-validation.xml
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
非字段配置風格(基於驗證器的配置風格)
<validators>
//驗證器類型
<validator type="requiredstring">
//要校驗的參數名字
<param name="fieldName">password</param>
//校驗失敗後返回的信息
<message>密碼不能爲空</message>
</validator>
</validators>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
短路校驗器
校驗配置文件的<field-validator>和<validator>元素可以指定一個可選的short-circuit屬性,指定該校驗器是否是短路校驗器,默認是false。
短路校驗器的作用是如果一個字段內有多個校驗器,如果一個校驗器校驗失敗,其他校驗器根本不會繼續校驗。
校驗器的執行順序
-所有基於驗證器的配置風格的校驗器優先於字段風格的校驗器
-所有的基於驗證器風格的校驗器,排在前面的先執行
-所有的基於字段風格的校驗器,排在前面的先執行。
校驗器的短路原則
-所有的非字段校驗器最先執行,如果某個非字段校驗器校驗失敗,則該字段上的所有字段校驗器都不會執行
-非字段校驗器校驗失敗,不會阻止其他非字段校驗器的執行
-如果某個字段校驗器校驗失敗,則該字段下的後面的字段校驗器都不會執行
-字段校驗器永遠都不會阻止非字段校驗器的執行
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
struts2的內建校驗器
required:必填驗證器,要求指定的字段必須有值。使用非字段風格的配置時,可以配置fieldName屬性來設置要校驗的表單項名稱。
requiredstring:必填字符串驗證器。
int、long、short:整數校驗器。要求字段的整數值必須在指定範圍內。參數:min指定該屬性最小值,不指定不檢查最小值。max指定該屬性最大值,不指定不檢查最大值。
date:日期校驗器。要求字段的日期值必須在指定範圍內。參數:min最小日期 ,max最大日期
expression:表達式校驗器,它只能被非字段風格配置。參數:expression指定一個邏輯表達式。
fieldexpression:字段表達式校驗器。要求字段滿足一個邏輯表達式。
email:郵件校驗器。要求被檢查字段非空,並且必須是合法的郵箱地址,底層是正則表達式。
url:網址校驗器。要求被檢查字段非空並且是個發的url地址,底層是正則表達式。
stringlength:字符串長度校驗器。要求字段長度必須在指定的範圍內。參數:manLength 最大長度 minLength最小長度
regex:正則表達式校驗器。
等等。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
自定義校驗。
struts2內建的校驗器可以完成大部分輸入校驗。但是有時候無法滿足一些特殊的要求,struts2允許通過手動方式完成自定義校驗。
繼承ActionSupport,重寫validate方法
public void validate() {
if(user.getUsername()==null||user.getUsername().isEmpty()){
addFieldError("username", "用戶名不能爲空!!!");
}
}
重寫validate方法會檢驗action類裏的所有方法,我們不需要校驗某些方法,有兩種方法。
第一種:在不需要校驗的方法前加上註解@SkipValidation
第二種:重寫validateXxx方法,Xxx即爲要驗證的方法名
public void validateRegist() {
if(user.getUsername()==null||user.getUsername().isEmpty()){
addFieldError("username", "用戶名不能爲空!!!");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
struts2的輸入校驗流程
1.對字符串類型的請求參數進行類型轉換,並且設置給JavaBean的屬性
2.類型轉換中可能出現異常,如果出現異常,將異常信息保存並封裝
3.調用struts2的輸入校驗規則進行輸入校驗(根據各種vatidate.xml文件裏定義的校驗規則)
4.通過反射調用validateXxx方法進行校驗
5.調用validate方法校驗
6.上面的校驗出現錯誤,轉到input對應的視圖資源。沒錯誤,調用action中的處理方法。
文章轉載:http://blog.csdn.net/c99463904/article/details/72231558