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,然后讓SendData和BackData繼承它,但是問題是這兩個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中的代碼:
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
|
@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請求這個知識點 } } |
3. Struts2的處理流程
我們再來分析一下Struts2的執行流程,這樣更加利于理解上面的原理。Struts處理流程:
1)、獲取請求后,先創建Action的代理,在創建代理的時候順便創建了Action;
2)、執行18個攔截器,攔截器執行成功后再調用Action的方法;
3)、Action的方法執行完畢后,再調用18個攔截器
所以根據這個流程,我們知道:先創建Action–>再執行攔截器(先執行ServletConfig,再執行ModelDriven,因為ServletConfig攔截器配在ModelDriven的前面)。所以在上面的代碼中,我們才可以在getModel()方法中去拿parameterMap中的數據來進行判斷。
用下面簡單的時序圖來直觀的表示一下上面的處理流程吧:
這就很直觀的看出Struts2的處理流程了,那么對于上面處理多個Model請求也很好理解了。到這里,Struts2處理多個Model請求的方法部分已經分析完了,下面針對本項目中的一個小邏輯,做一下完善。
4. 完善接收數據的方法
上面遺留了一個邏輯的實現,即處理返回的數據,這里的邏輯主要有:更新訂單狀態(已付款,已發貨等),發送郵件,發送短信等。我們先把更新訂單狀態完成,主語發送郵件和發送短信的功能,我們后面再寫。
先完善backBank()方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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!!!----" ); } } |
然后我們完成payService中的checkBackData(backData)方法(邏輯和21節中的基本一樣):
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
|
@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()); } } |
最后我們完成ForderService中的updateStatusById方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
//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(); } } |
這樣就能在顧客付款后更新訂單狀態了。
原文鏈接:http://blog.csdn.net/eson_15/article/details/51465067
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。