Struts2+Spring2+Hibernate3 web應用示例(四)
六、 創建Action類:BookAction
有Struts 1.x經驗的朋友都知道Action是Struts的核心內容,當然Struts 2.0也不例外。不過,Struts 1.x與Struts 2.0的Action模型很大的區別。
|
Struts 1.x
|
Stuts 2.0
|
接口
|
必須繼承org.apache.struts.action.Action或者其子類
|
無須繼承任何類型或實現任何接口
|
表單數據
|
表單數據封裝在FormBean中
|
表單數據包含在Action中,通過Getter和Setter獲取
|
1、建立BookAction類
package com.sterning.books.web.actions;

import java.util.Collection;

import com.sterning.books.model.Books;
import com.sterning.books.services.iface.IBooksService;
import com.sterning.commons.AbstractAction;
import com.sterning.commons.Pager;
import com.sterning.commons.PagerService;


public class BooksAction extends AbstractAction
{
private IBooksService booksService;
private PagerService pagerService;
private Books book;
private Pager pager;
protected Collection availableItems;
protected String currentPage;
protected String pagerMethod;
protected String totalRows;
protected String bookId;
protected String queryName;
protected String queryValue;
protected String searchName;
protected String searchValue;
protected String queryMap;

public String list() throws Exception
{

if(queryMap ==null||queryMap.equals(""))
{

}else
{
String[] str=queryMap.split("~");
this.setQueryName(str[0]);
this.setQueryValue(str[1]);
}
System.out.println("asd"+this.getQueryValue());
int totalRow=booksService.getRows(this.getQueryName(),this.getQueryValue());
pager=pagerService.getPager(this.getCurrentPage(), this.getPagerMethod(), totalRow);
this.setCurrentPage(String.valueOf(pager.getCurrentPage()));
this.setTotalRows(String.valueOf(totalRow));
availableItems=booksService.getBooks(this.getQueryName(),this.getQueryValue(),pager.getPageSize(), pager.getStartRow());
this.setQueryName(this.getQueryName());
this.setQueryValue(this.getQueryValue());
this.setSearchName(this.getQueryName());
this.setSearchValue(this.getQueryValue());
return SUCCESS;
}

public String load() throws Exception
{
if(bookId!=null)
book = booksService.getBook(bookId);
else
bookId=booksService.getMaxID();
return SUCCESS;
}

public String save() throws Exception
{

if(this.getBook().getBookPrice().equals(""))
{
this.getBook().setBookPrice("0.0");
}
String id=this.getBook().getBookId();
Books book=booksService.getBook(id);
if(book == null)
booksService.addBook(this.getBook());
else
booksService.updateBook(this.getBook());
this.setQueryName(this.getQueryName());
this.setQueryValue(this.getQueryValue());

if(this.getQueryName()==null||this.getQueryValue()==null||this.getQueryName().equals("")||this.getQueryValue().equals(""))
{

}else
{
queryMap=this.getQueryName()+"~"+this.getQueryValue();
}
return SUCCESS;
}

public String delete() throws Exception
{
booksService.deleteBook(this.getBookId());

if(this.getQueryName()==null||this.getQueryValue()==null||this.getQueryName().equals("")||this.getQueryValue().equals(""))
{

}else
{
queryMap=this.getQueryName()+"~"+this.getQueryValue();
}
return SUCCESS;
}

public Books getBook()
{
return book;
}


public void setBook(Books book)
{
this.book = book;
}


public IBooksService getBooksService()
{
return booksService;
}


public void setBooksService(IBooksService booksService)
{
this.booksService = booksService;
}


public Collection getAvailableItems()
{
return availableItems;
}


public String getCurrentPage()
{
return currentPage;
}


public void setCurrentPage(String currentPage)
{
this.currentPage = currentPage;
}


public String getPagerMethod()
{
return pagerMethod;
}


public void setPagerMethod(String pagerMethod)
{
this.pagerMethod = pagerMethod;
}


public Pager getPager()
{
return pager;
}


public void setPager(Pager pager)
{
this.pager = pager;
}


public String getTotalRows()
{
return totalRows;
}


public void setTotalRows(String totalRows)
{
this.totalRows = totalRows;
}

public String getBookId()
{
return bookId;
}


public void setBookId(String bookId)
{
this.bookId = bookId;
}


public String getQueryName()
{
return queryName;
}


public void setQueryName(String queryName)
{
this.queryName = queryName;
}


public String getQueryValue()
{
return queryValue;
}


public void setQueryValue(String queryValue)
{
this.queryValue = queryValue;
}

public String getSearchName()
{
return searchName;
}


public void setSearchName(String searchName)
{
this.searchName = searchName;
}


public String getSearchValue()
{
return searchValue;
}


public void setSearchValue(String searchValue)
{
this.searchValue = searchValue;
}

public String getQueryMap()
{
return queryMap;
}


public void setQueryMap(String queryMap)
{
this.queryMap = queryMap;
}

public PagerService getPagerService()
{
return pagerService;
}



public void setPagerService(PagerService pagerService)
{
this.pagerService = pagerService;
}
}

com.sterning.books.web.actions.BookAction.java
(1)、默認情況下,當請求bookAction.action發生時(這個會在后面的Spring配置文件中見到的),Struts運行時(Runtime)根據struts.xml里的Action映射集(Mapping),實例化com.sterning.books.web.actions.BookAction類,并調用其execute方法。當然,我們可以通過以下兩種方法改變這種默認調用。這個功能(Feature)有點類似Struts 1.x中的LookupDispathAction。
在classes/sturts.xml中新建Action,并指明其調用的方法;
訪問Action時,在Action名后加上“!xxx”(xxx為方法名)。
(2)、細心的朋友應該可能會發現com.sterning.books.web.actions.BookAction.java中Action方法(execute)返回都是SUCCESS。這個屬性變量我并沒有定義,所以大家應該會猜到它在ActionSupport或其父類中定義。沒錯,SUCCESS在接口com.opensymphony.xwork2.Action中定義,另外同時定義的還有ERROR, INPUT, LOGIN, NONE。
此外,我在配置Action時都沒有為result定義名字(name),所以它們默認都為success。值得一提的是Struts 2.0中的result不僅僅是Struts 1.x中forward的別名,它可以實現除forward外的很激動人心的功能,如將Action輸出到FreeMaker模板、Velocity模板、JasperReports和使用XSL轉換等。這些都過result里的type(類型)屬性(Attribute)定義的。另外,您還可以自定義result類型。
(3)、使用Struts 2.0,表單數據的輸入將變得非常方便,和普通的POJO一樣在Action編寫Getter和Setter,然后在JSP的UI標志的name與其對應,在提交表單到Action時,我們就可以取得其值。
(4)、Struts 2.0更厲害的是支持更高級的POJO訪問,如this.getBook().getBookPrice()。private Books book所引用的是一個關于書的對象類,它可以做為一個屬性而出現在BookActoin.java類中。這樣對我們開發多層系統尤其有用。它可以使系統結構更清晰。
(5)、有朋友可能會這樣問:“如果我要取得Servlet API中的一些對象,如request、response或session等,應該怎么做?這里的execute不像Struts 1.x的那樣在參數中引入。”開發Web應用程序當然免不了跟這些對象打交道。在Strutx 2.0中可以有兩種方式獲得這些對象:非IoC(控制反轉Inversion of Control)方式和IoC方式。
非IoC方式
要獲得上述對象,關鍵是Struts 2.0中com.opensymphony.xwork2.ActionContext類。我們可以通過它的靜態方法getContext()獲取當前Action的上下文對象。另外,org.apache.struts2.ServletActionContext作為輔助類(Helper Class),可以幫助您快捷地獲得這幾個對象。
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
HttpSession session = request.getSession();
如果你只是想訪問session的屬性(Attribute),你也可以通過ActionContext.getContext().getSession()獲取或添加session范圍(Scoped)的對象。
IoC方式
要使用IoC方式,我們首先要告訴IoC容器(Container)想取得某個對象的意愿,通過實現相應的接口做到這點。如實現SessionAware, ServletRequestAware, ServletResponseAware接口,從而得到上面的對象。
1、對BookAction類的Save方法進行驗證
正如《Writing Secure Code》文中所寫的名言All input is evil:“所有的輸入都是罪惡的”,所以我們應該對所有的外部輸入進行校驗。而表單是應用程序最簡單的入口,對其傳進來的數據,我們必須進行校驗。Struts2的校驗框架十分簡單方便,只在如下兩步:
在Xxx-validation.xml文件中的<message>元素中加入key屬性;
在相應的jsp文件中的<s:form>標志中加入validate="true"屬性,就可以在用Javascript在客戶端校驗數據。
其驗證文件為:BooksAction-save-validation.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0//EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.dtd">
<validators>
<!-- Field-Validator Syntax -->
<field name="book.bookName">
<field-validator type="requiredstring">
<message key="book.bookName.required"/>
</field-validator>
</field>
<field name="book.bookAuthor">
<field-validator type="requiredstring">
<message key="book.bookAuthor.required"/>
</field-validator>
</field>
<field name="book.bookPublish">
<field-validator type="requiredstring">
<message key="book.bookPublish.required"/>
</field-validator>
</field>
</validators>

com.sterning.books.web.actions.BooksAction-save-validation.xml
1、對BookAction類的Save方法進行驗證的資源文件
注意配置文件的名字應該是:配置文件(類名-validation.xml)的格式。BooksAction類的驗證資源文件為:BooksAction.properties
book=Books
book.bookName.required=\u8bf7\u8f93\u5165\u4e66\u540d
book.bookAuthor.required=\u8bf7\u8f93\u5165\u4f5c\u8005
book.bookPublish.required=\u8bf7\u8f93\u5165\u51fa\u7248\u793e
format.date={0,date,yyyy-MM-dd}

com.sterning.books.web.actions.BooksAction.properties
資源文件的查找順序是有一定規則的。之所以說Struts 2.0的國際化更靈活是因為它可以根據不同需要配置和獲取資源(properties)文件。在Struts 2.0中有下面幾種方法:
(1)、使用全局的資源文件。這適用于遍布于整個應用程序的國際化字符串,它們在不同的包(package)中被引用,如一些比較共用的出錯提示;
(2)、使用包范圍內的資源文件。做法是在包的根目錄下新建名的package.properties和package_xx_XX.properties文件。這就適用于在包中不同類訪問的資源;
(3)、使用Action范圍的資源文件。做法為Action的包下新建文件名(除文件擴展名外)與Action類名同樣的資源文件。它只能在該Action中訪問。如此一來,我們就可以在不同的Action里使用相同的properties名表示不同的值。例如,在ActonOne中title為“動作一”,而同樣用title在ActionTwo表示“動作二”,節省一些命名工夫;
(4)、使用<s:i18n>標志訪問特定路徑的properties文件。在使用這一方法時,請注意<s:i18n>標志的范圍。在<s:i18n name="xxxxx">到</s:i18n>之間,所有的國際化字符串都會在名為xxxxx資源文件查找,如果找不到,Struts 2.0就會輸出默認值(國際化字符串的名字)。
例如:某個ChildAction中調用了getText("user.title"),Struts 2.0的將會執行以下的操作:
查找ChildAction_xx_XX.properties文件或ChildAction.properties;
查找ChildAction實現的接口,查找與接口同名的資源文件MyInterface.properties;
查找ChildAction的父類ParentAction的properties文件,文件名為ParentAction.properties;
判斷當前ChildAction是否實現接口ModelDriven。如果是,調用getModel()獲得對象,查找與其同名的資源文件;
查找當前包下的package.properties文件;
查找當前包的父包,直到最頂層包;
在值棧(Value Stack)中,查找名為user的屬性,轉到user類型同名的資源文件,查找鍵為title的資源;
查找在struts.properties配置的默認的資源文件,參考例1;
輸出user.title。
未完待續 。。。。。。