Java程式員從笨鳥到菜鳥之(四十三)細談struts2(六)擷取servletAPI和封裝表單資料

來源:互聯網
上載者:User

本文來自:曹勝歡部落格專欄。轉載請註明出處:http://blog.csdn.net/csh624366188 

 

一:擷取servletAPI的三種方法

       在傳統的Web開發中,經常會用到Servlet API中的HttpServletRequest、HttpSession和ServletContext。Struts 2架構讓我們可以直接存取和設定action及模型對象的資料,這降低了對HttpServletRequest對象的使用需求,同時降低了對servletAPI的依賴性,從而降低了與servletAPI的耦合度。但在某些應用中,我們可
能會需要在action中去訪問HttpServletRequest等對象,所以有時候我們不得不拉近struts2和servletAPI的關係,但struts2也有盡量減少耦合度的方法,下面我們就一起具體看一下在struts2中獲得ServletAPI的三種方法:

 

1.ServletAPI解藕方式(一)擷取Map對象:

    為了避免與Servlet API耦合在一起,方便Action類做單元測試,Struts 2對HttpServletRequest、HttpSession和ServletContext進行了封裝,構造了三個Map對象來替代這三種對象,在Action中,直接使用HttpServletRequest、HttpSession和ServletContext對應的Map對象來儲存和讀取
資料。可以通過com.opensymphony.xwork2.ActionContext類來得到這三個對象。ActionContext是Action執行的上下文,儲存了很多個物件如parameters、request、session、application和locale等。通過ActionContext類擷取Map對象的方法為:

ActionContextcontext=ActionContext.getContext(); --得到Action執行的上下文Maprequest=(Map)context.get("request");--得到HttpServletRequest的Map對象Mapsession=context.getSession();--得到HttpSession的Map對象Mapapplication=context.getApplication();--得到ServletContext的Map對象

          ActionContext中儲存的資料能夠從請求對象中得到,其中的奧妙就在於Struts 2中的org.apache.struts2.dispatcher.StrutsRequestWrapper類,這個類是
HttpServletRequest的封裝類,它重寫了getAttribute()方法(在頁面中擷取request對象的屬性就要調用這個方法), 在這個方法中,它首先在請求對象中尋找屬性,如果沒有找到(如果你在ActionContext中儲存資料,當然就找不到了),則到 ActionContext中去尋找。這就是為什麼在ActionContext中儲存的資料能夠從請求對象中得到的原因。

2.IOC(控制反轉)擷取servletAPI

     Action類還有另一種獲得ServletAPI的解耦方式,這就是我們可以讓他實現某些特定的介面,讓Struts2架構在運行時向Action執行個體注入request、session和application對象。這種方式也就是IOC(控制反轉)方式,與之對應的三個介面和它們的方法如下所示:

public class SampleAction implementsAction,RequestAware, SessionAware, ApplicationAware{private Map request;private Map session;private Map application;@Overridepublic void setRequest(Map request){this.request = request;}@Overridepublic void setSession(Map session){this.session = session;}@Overridepublic void setApplication(Map application){this.application = application;}}

ServletRequestAware介面和ServletContextAware介面不屬於同一個包,前者在org.apache.struts2.interceptor包中,後者在org.apache.struts2.util包中,這很讓人迷惑。

 

3.與Servlet API耦合的訪問方式

    直接存取Servlet API將使你的Action與Servlet環境耦合在一起,我們知道對於HttpServletRequest、 HttpServletResponse和ServletContext這些對象,它們都是由Servlet容器來構造的,與這些對象綁定在一起,測試時就需要有Servlet容器,不便於Action的單元測試。但有時候,我們又確實需要直接存取這些對象,那麼當然是以完成任務需求為主。要直接擷取HttpServletRequest和ServletContext對象,可以使用org.apache.struts2.
ServletActionContext類,該類是ActionContext的子類,在這個類中定義下面兩個靜態方法:

1.得到HttpServletRequest對象:

public static HttpServletRequestgetRequest()

2.得到ServletContext對象:

public static ServletContextgetServletContext()

此外,ServletActionContext類還給出了擷取HttpServletResponse對象的方法,如下:

public static HttpServletResponsegetResponse()

ServletActionContext類並沒有給出直接得到HttpSession對象的方法,HttpSession對象可以通過HttpServletRequest對象來得到。

除了上述的方法調用得到HttpServletRequest和ServletContext對象外,還可以調用ActionContext對象的 get()方法,傳遞ServletActionContext.HTTP_REQUEST和 ServletActionContext.SERVLET_CONTEXT索引值來得到HttpServletRequest和
ServletContext對象同樣的,也可以向ActionContext的get()方法傳遞ServletActionContext.HTTP_ RESPONSE索引值來得到HttpServletResponse對象

 

       總結:通過上面三種方式的講解我們可以看出,三種獲得servletAPI的方式基本都差不多,通常我們建議大家採用第一種方式來擷取HttpServletRequest和ServletContext對象,這樣簡單而又清晰,並且降低了和servletAPI的耦合度,這樣也方便進行單元測試

二:struts2封裝請求參數三種方式

     在struts2開發應用中,我們可能經常要求獲得視圖層傳過來的很多資料,一般都是一個實體類的n多屬性,很多時候實體類的屬性特別多,這時候如果還是按以前的方式在action裡面一個個的定義出這些屬性的私人變數,然後在提供set、get方法的話,這樣就會使整個action太臃腫,嚴重妨礙了代碼的可閱讀性,並且也違背了代碼的可複用性,這時我們就需要對這些請求參數進行封裝,提高代碼的可複用性,下面我們就一起來具體看一下三種封裝請求參數的方法:

1.利用實體類封裝參數

        這種方式是封裝參數最簡單的方法,一般也比較常用,因為在我們的struts應用程式中,我們一般會根據資料庫的資訊寫出對應的實體類,所以這正好使我們可以利用的,下面我們看一下具體操作:

1.建立實體類user(包括使用者名稱和密碼屬性),這裡比較簡單,我們就不貼出代碼了。

2.建立action,這裡我們主要是來看一下action接收資料的屬性這個地方,我們就不是在一一定義這些屬性的私人變數了,我們直接定義一個對應實體類的私人對象就可以了,代碼如下:

package com.bzu.action;publicclass LoginAction extends ActionSupport {    private User user;    public User getUser() {        returnuser;    }    publicvoid setUser(User user) {        this.user = user;    }    public String execute(){    if(user.getUsername().equals("admin")&&user.getPassword().equals("123456"))            return"success";        return"fail";    }}

3.定義表單,這裡我們需要注意一下,這裡表單裡面的控制項的name屬性定義有一定的要求,定義name時我們應該定義為:對象.屬性的形式,範例程式碼:

<s:form action="LoginAction">  <s:actionerror/> <s:textfield name="user.username"></s:textfield><s:password name="user.password"></s:password>  <s:submit value="提交" ></s:submit>   </s:form>

4.配置struts.xml,這裡配置和平常一樣,這裡就不再重複了

至此,我們簡單的實體類封裝請求參數就完成了,我相信大家一定也會感覺很簡單吧

 

2.模型驅動封裝請求參數
      模型驅動是指使用JavaBean來封裝來回請求的參數.這種方式的好處就是減少了action的壓力。既用於封裝來回請求的參數,也保護了控制邏輯,使它的結構清晰.這就是模型驅動的優勢.

下面我們具體來看一下模型驅動的具體實現:

模型驅動的實現主要是體現在action上

1.首先建立一個實體,比較簡單,這裡就不再寫了。

2.建立action類,繼承自ActionSupport,實現ModelDriven介面,這個介面定義了一個getModel()方法,用於返回定義的Model,然後調用set方法,進行賦值。程式碼範例:

publicclass LoginAction3 extends ActionSupport implementsModelDriven<User> { private User user=new User();//這裡記住要執行個體化 private LoginService loginService=new LoginServiceImpl();//這裡是調用登入的業務處理邏輯@Override public User getModel() { //TODOAuto-generated method stub return user;} public String execute(){System.out.println(user.getUsername());System.out.println(user.getPassword()); if(loginService.isLogin(user.getUsername(),user.getPassword())){ return SUCCESS;} return INPUT;}}



在com.opensymphony.xwork2.ModelDriven介面原始碼中有一段很重要的說明,現抄錄如下
ModelDriven Actions provide a model object to bepushed onto the ValueStack in additionto the Action itself,allowing a FormBeantype approach like Struts
翻譯:模型驅動的Action。將模型對象以及Action對象都放到ValueStack裡面,允許像Struts一樣的FormBean方式
也即:一個Action要想成為模型驅動的話,就必須實現ModelDriven接
口,而我們之前所一直繼承的ActionSupport類並沒有實現ModelDriven介面

ModelDrivenAction類的執行流程是:首先調用getModel()方法得到User對象,接著根據JavaBean的原則將用戶端傳過來的屬性,一個一個的set到User對象的屬性中,將屬性全部set完之後,再執行execute()方法。對於模型驅動,只要瞭解這些就足夠了

擴充:模型驅動的底層實現機制
這裡用到了defaultStack攔截器棧中的modelDriven攔截器
它對應com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor類,其API描述如下
public class ModelDrivenInterceptor extends AbstractInterceptor
Watches for ModelDriven actions and adds the action`s model on to the valuestack.
翻譯:觀察模型驅動的Action,並將這個Action的模型【這裡指User對象】放到值棧中
Note:The ModelDrivenInterceptor must come before the bothStaticParametersInterceptor and ParametersInterceptor if you want theparameters to be applied to the model.
翻譯:若希望將表單提交過來的參數應用到模型裡面,那麼ModelDrivenInterceptor攔截器就必須位於StaticParametersInterceptor和ParametersInterceptor攔截器前面。

實際上struts-default.xml已完成這個工作了。可以在defaultStack攔截器棧中查看三者位置,所以對於採用模型驅動的方式的話,在struts.xml中只需要指定模型驅動的類就可以了,其它的都不需要我們手工修改

3,屬性驅動接收參數

這種方式應該不算是參數封裝的方式,但我們很多情況下都用屬性驅動的方式接收參數,因為這種方式方便,簡潔,易控制。屬性驅動在Action中提供與表單欄位一一對應的屬性,然後一一set賦值,採用屬性驅動的方式時,是由每個屬性來承載表單的欄位值,運轉在MVC流程裡面。由於這種方式比較簡單,這裡就不在贅述了。


到底是用屬性驅動和是模型驅動呢?

1)統一整個系統中的Action使用的驅動模型,即要麼都是用屬性驅動,要麼都是用模型驅動。

2)如果你的DB中的持久層的對象與表單中的屬性都是一一對應的話,那麼就使用模型驅動吧,畢竟看起來代碼要整潔得多。

3)如果表單的屬性不是一一對應的話,那麼就應該使用屬性驅動,否則,你的系統就必須提供兩個Bean,一個對應表單提交的資料,另一個用與持久層。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.