【SSH網上商城項目實戰24】Struts2中如何處理多個Model請求

1. 問題的提出

  Struts2中如果實現了ModelDriven<model>接口就可以將傳來的參數注入到model中了,就可以在Action中使用該model,但是如果現在有兩個model都需要在同一個Action中使用該咋整呢?比如上一節我們完成了在線支付功能,但是支付完成了還沒結束,我們需要接收從第三方那邊反饋回來的信息,比如成功支付後,我們需要給付款方發送郵件和短信等。所以我們還需要在payAction中獲取從第三方傳過來的參數,由於從第三方傳過來的參數與我們傳過去的參數是不同的,所以接收那些參數我們也得寫一個Model(BackData),那麼問題來了,我們的PayAction已經寫成這樣子了:public class PayAction extends BaseAction<SendData>,即已經在BaseAction中實現了ModelDriven<SendData>接口了,那麼如何在一個action中再接收一個Model,並且還得對它們進行不同的處理呢?
  有種解決辦法(其實也不能稱爲解決辦法……因爲根本就沒解決……)就是寫一個Model,然後讓SendDataBackData繼承它,但是問題是這兩個Model根本就沒關係,爲啥要繼承同一個Model,所以這種解決辦法實際上是在逃避上面的問題。
  在SpringMVC(SpringMVC還沒真正開始學,如果有說錯,請指正!)很好的解決了這個問題,因爲SpringMVC中每個方法對應一個Model,而不是每個Action對應一個Model,這就方便了,我在同一個Action中寫兩個方法即可,不同的方法處理不同的Model。

2. 問題的解決

  針對這個問題,Struts2也提供了一種解決辦法:
  Struts2在ActionContext中存儲了很多個Map,比如之前提到的request, session, application等,其中還有個parameterMap,該Map中存儲了request所有的請求參數,只要我們的Action實現了parameterAware接口,就能拿到這個parameterMap,這就跟ModelDriven的道理是一樣的,如果我們實現了ModelDriven<Model>接口,那麼我們在Action中就能獲得該Model,即定義一個Model並實現set方法即可。
  好了,那現在問題好辦了,支付的參數和返回的參數是不同的,也就是說兩次進入PayAcition中的參數是不同的,即兩次的parameterMap中裝的數據不一樣,那隻要我們在Action中選取一個參數(該參數只要能區分兩次是不同的request請求即可)作爲判斷,就知道當前該用哪個Model來接收參數(SendData還是BackData)。下面我們改寫一下PayAction中的代碼:

@Controller("payAction")
@Scope("prototype")
public class PayAction extends BaseAction<Object> implements ParameterAware {
//注意上面繼承的BaseAction中不能寫SendData了,要寫Object,等下我們再判斷具體使用哪個 

    //定義一個Map接收request的請求參數
    private Map<String, String[]> parameters;
    @Override
    public void setParameters(Map<String, String[]> parameters) {
        this.parameters = parameters;

    }   
    /*在struts-default.xml文中,ServletConfig攔截器在ModelDriven之前先執行,所以我們在注入model的時候,
    request參數已經有了,這樣我們就可以在getModel()方法中通過參數來判斷是哪個請求了*/
    @Override
    public Object getModel() {
    //付款的時候有支付通道編碼的參數(pd_FrpId),返回的時候沒有
    //這樣我們就可以通過該參數判斷是支付還是返回了
        if(parameters.get("pd_FrpId") != null) {
            model = new SendData();
        } else {
            model = new BackData();
        }
        return model;
    }

    //向易寶發送數據的方法
    public String goBank() {
        //對應發送的model:SendData
        SendData sendData = (SendData)model;
        //處理髮送數據的邏輯,前一節已經實現過了……
    }

    //接收返回的數據的方法
    public void backBank() {
        //對應接收的model:BackData
        BackData backData = (BackData)model;
        //處理返回數據的邏輯……後面再來實現,
        //先講Struts2處理多個Model請求這個知識點
    }
}
  • 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
  • 41
  • 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
  • 41

3. Struts2的處理流程

  我們再來分析一下Struts2的執行流程,這樣更加利於理解上面的原理。Struts處理流程:

  • 獲取請求後,先創建Action的代理,在創建代理的時候順便創建了Action;
  • 執行18個攔截器,攔截器執行成功後再調用Action的方法;
  • Action的方法執行完畢後,再調用18個攔截器

所以根據這個流程,我們知道:先創建Action–>再執行攔截器(先執行ServletConfig,再執行ModelDriven,因爲ServletConfig攔截器配在ModelDriven的前面)。所以在上面的代碼中,我們纔可以在getModel()方法中去拿parameterMap中的數據來進行判斷。  
  用下面簡單的時序圖來直觀的表示一下上面的處理流程吧:

Created with Raphaël 2.1.0struts2啓動struts2啓動Action代理和Action對象Action代理和Action對象18個攔截器18個攔截器創建按順序執行執行其他攔截器……執行ServletConfig攔截器,將request參數放到parameterMap中執行ModelDriven攔截器,初始化model(我們就在這裏拿上面參數進行判斷的)執行其他攔截器……再去執行Action中相應的方法再按順序執行一次攔截器

  這就很直觀的看出Struts2的處理流程了,那麼對於上面處理多個Model請求也很好理解了。到這裏,Struts2處理多個Model請求的方法部分已經分析完了,下面針對本項目中的一個小邏輯,做一下完善。

4. 完善接收數據的方法

  上面遺留了一個邏輯的實現,即處理返回的數據,這裏的邏輯主要有:更新訂單狀態(已付款,已發貨等),發送郵件,發送短信等。我們先把更新訂單狀態完成,主語發送郵件和發送短信的功能,我們後面再寫。
先完善backBank()方法:

public void backBank() {
    BackData backData = (BackData)model;
    System.out.println(model);
    boolean isOK = payService.checkBackData(backData);
    if(isOK) {
        //1. 更新訂單狀態,參數是自己根據數據庫中的情況傳進去的,用來測試
        forderService.updateStatusById(Integer.valueOf(201605006), 2);
        //2. 根據user郵箱地址,發送郵件
        //3. 發送手機短信
        System.out.println("----success!!----");
    } else {
        System.out.println("----false!!!----");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

然後我們完成payService中的checkBackData(backData)方法(邏輯和21節中的基本一樣):

@Service("payService")
public class PayServiceImpl implements PayService {
        //省略不相關代碼
        /******************************上面是發送請求的方法**************************************/
        // 完成返回數據的追加
        private String joinBackDataParam(BackData backData) {
            // 追加字符串,爲加密驗證做準備
            StringBuffer infoBuffer = new StringBuffer();
            infoBuffer.append(backData.getP1_MerId());
            infoBuffer.append(backData.getR0_Cmd());
            infoBuffer.append(backData.getR1_Code());
            infoBuffer.append(backData.getR2_TrxId());
            infoBuffer.append(backData.getR3_Amt());
            infoBuffer.append(backData.getR4_Cur());
            infoBuffer.append(backData.getR5_Pid());
            infoBuffer.append(backData.getR6_Order());
            infoBuffer.append(backData.getR7_Uid());
            infoBuffer.append(backData.getR8_MP());
            infoBuffer.append(backData.getR9_BType());
            return infoBuffer.toString();
        }

        // 對返回來的數據進行加密,並且和傳過來的密文進行比較,如果OK則說明數據沒有被篡改
        public boolean checkBackData(BackData backData){
            String joinParam=this.joinBackDataParam(backData);
            // 加密後得到自己的密文
            String md5 = DigestUtil.hmacSign(joinParam.toString(),key);
            // 密文和傳過來密文比較
            return md5.equals(backData.getHmac());
        }   
}
  • 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
  • 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

最後我們完成ForderService中的updateStatusById方法:

//ForderService接口
public interface ForderService extends BaseService<Forder> {
    //省略其他無關代碼……
    //根據訂單編號,更新訂單狀態
    public void updateStatusById(int id, int sid);
}

//ForderServiceImpl實現類
@Service("forderService")
public class ForderServiceImpl extends BaseServiceImpl<Forder> implements ForderService {

    //省略其他無關代碼

    @Override
    public void updateStatusById(int id, int sid) {
        String hql = "update Forder f set f.status.id=:sid where f.id=:id";
        getSession().createQuery(hql)
            .setInteger("sid", sid)
            .setInteger("id", id)
            .executeUpdate();
    }   
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

  這樣就能在顧客付款後更新訂單狀態了。

  相關閱讀:http://blog.csdn.net/column/details/str2hiberspring.html
  整個項目的源碼下載地址:http://blog.csdn.net/eson_15/article/details/51479994


—–樂於分享,共同進步!
—–更多文章請看:http://blog.csdn.net/eson_15

(function () { ('pre.prettyprint code').each(function () { var lines = (this).text().split(\n).length;var numbering = $('
    ').addClass('pre-numbering').hide(); (this).addClass(hasnumbering).parent().append( numbering); for (i = 1; i
    發表評論
    所有評論
    還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
    相關文章