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中的代碼:
@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
中的數據來進行判斷。
用下面簡單的時序圖來直觀的表示一下上面的處理流程吧:
這就很直觀的看出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