在
《WebService大講堂之Axis2(5):會話(Session)管理》
一文中介紹了如何使用Axis2來管理同一個服務的會話,但對于一個復雜的系統,不可能只有一個WebService服務,例如,至少會有一個管理用戶的WebService(用戶登錄和注冊)以及處理業務的WebService。象這種情況,就必須在多個WebService服務之間共享會話狀態,也稱為跨服務會話(Session)管理。實現跨服務會話管理與實現同一個服務的會話管理的步驟類似,但仍然有一些差別,實現跨服務會話管理的步驟如下:
實現跨服務的Session管理需要如下三步:
1.?使用MessageContext和ServiceGroupContext獲得與設置key-value對。
2.?為要進行Session管理的WebService類所對應的<service>元素添加一個scope屬性,并將該屬性值設為application。
3.?在客戶端使用setManageSession(true)打開Session管理功能。
從上面的步驟可以看出,實現跨服務會話管理與實現同一個服務的會話管理在前兩步上存在著差異,而第3步是完全一樣的。下面是一個跨服務的會話管理的實例。在這個例子中有兩個WebService類:LoginService和SearchService,代碼如下:
LoginService.java
package
?service;
import
?org.apache.axis2.context.MessageContext;
import
?org.apache.axis2.context.ServiceGroupContext;
public
?
class
?LoginService
{
????
public
?
boolean
?login(String?username,?String?password)
????{????????
????????
if
(
"
bill
"
.equals(username)?
&&
?
"
1234
"
.equals(password))
????????{
????????????
//
??第1步:設置key-value對
????????????MessageContext?mc?
=
?MessageContext.getCurrentMessageContext();
????????????ServiceGroupContext?sgc?
=
?mc.getServiceGroupContext();
????????????sgc.setProperty(
"
login
"
,?
"
成功登錄
"
);????
????????????
return
?
true
;
????????}
????????
else
????????{
????????????
return
?
false
;
????????}
????}????
????
public
?String?getLoginMsg()
????{
???????
//
??第1步:獲得key-value對中的value
????????MessageContext?mc?
=
?MessageContext.getCurrentMessageContext();
????????ServiceGroupContext?sgc?
=
??mc.getServiceGroupContext();
????????
return
?(String)sgc.getProperty(
"
login
"
);????
????}
}
SearchService.java
package
?service;
import
?org.apache.axis2.context.MessageContext;
import
?org.apache.axis2.context.ServiceGroupContext;
public
?
class
?SearchService
{
????
public
?String?findByName(String?name)
????{
????????
//
??第1步:獲得key-value對中的value
????????MessageContext?mc?
=
?MessageContext.getCurrentMessageContext();
????????ServiceGroupContext?sgc?
=
??mc.getServiceGroupContext();????????????????
????????
if
?(sgc.getProperty(
"
login
"
)?
!=
?
null
)
????????????
return
?
"
找到的數據<
"
?
+
?name?
+
?
"
>
"
;
????????
else
????????????
return
?
"
用戶未登錄
"
;
????}
}
services.xml文件中的配置代碼如下:
<
serviceGroup
>
????
<!--
??第2步:添加scope屬性,并設置屬性值為application?
-->
????
<
service?
name
="loginService"
?scope
="application"
>
????????
<
description
>
????????????登錄服務
????????
</
description
>
????????
<
parameter?
name
="ServiceClass"
>
????????????service.LoginService
????????
</
parameter
>
????????
<
messageReceivers
>
????????????
<
messageReceiver?
mep
="http://www.w3.org/2004/08/wsdl/in-out"
????????????????class
="org.apache.axis2.rpc.receivers.RPCMessageReceiver"
?
/>
????????
</
messageReceivers
>
????
</
service
>
????
<!--
??第2步:添加scope屬性,并設置屬性值為application?
-->
????
<
service?
name
="searchService"
?scope
="application"
>
????????
<
description
>
????????????搜索服務
????????
</
description
>
????????
<
parameter?
name
="ServiceClass"
>
????????????service.SearchService
????????
</
parameter
>
????????
<
messageReceivers
>
????????????
<
messageReceiver?
mep
="http://www.w3.org/2004/08/wsdl/in-out"
????????????????class
="org.apache.axis2.rpc.receivers.RPCMessageReceiver"
?
/>
????????
</
messageReceivers
>
????
</
service
>
</
serviceGroup
>
第3步與《WebService大講堂之Axis2(5):會話(Session)管理》一文中介紹的方法類似。
下面是使用兩個stub類的對象實例訪問上面實現的兩個WebService的客戶端代碼:
LoginServiceStub?stub?
=
?
new
?LoginServiceStub();
LoginServiceStub.Login?login?
=
?
new
?LoginServiceStub.Login();
login.setUsername(
"
bill
"
);
login.setPassword(
"
1234
"
);
if
(stub.login(login).local_return)
{
????System.out.println(stub.getLoginMsg().local_return);
????SearchServiceStub?searchStub?
=
?
new
?SearchServiceStub();
????SearchServiceStub.FindByName?fbn?
=
?
new
?SearchServiceStub.FindByName();
????fbn.setName(
"
abc
"
);
????System.out.println(searchStub.findByName(fbn).local_return);?
}
在執行上面的代碼后,將輸出如下的信息:
成功登錄
找到的數據
<
abc
>
讀者可以將scope屬性值改成transportsession,看看會輸出什么!
??? 實際上,Axis2的會話管理也是通過Cookie實現的,與Web應用中的Session管理類似。如果讀者使用C#訪問支持會話(在同一個服務中的會話管理)的WebService,需要指定一個CookieContainer對象,代碼如下:
service.loginService?ls?
=
?
new
?service.loginService();
System.Net.CookieContainer?cc?
=
?
new
?System.Net.CookieContainer();
ls.CookieContainer?
=
?cc;
bool
?r,?rs;
ls.login(
"
bill
"
,?
"
1234
"
,?
out
?@r,?
out
?rs);
if
?(r)
{
????MessageBox.Show(ls.getLoginMsg().@return);
}
如果是訪問跨服務的支持會話的WebService
,則不需要指定CookieContainer
對象,代碼如下:
service.loginService?ls?=?new?service.loginService();
bool?r,?rs;
ls.login("bill",?"1234",?out?@r,?out?rs);
if?(r)
{
????service1.searchService?ss?=?new?service1.searchService();
????MessageBox.Show(ss.findByName("abc"));
}
如果讀者使用delphi(本文使用的是delphi2009,其他的delphi版本請讀者自行測試)調用支持會話的WebService時有一些差別。經筆者測試,使用delphi調用WebService,將scope屬性值設為transportsession和application都可以實現跨服務的會話管理,這一點和Java與C#不同,Java和C#必須將scope屬性值設為application才支持跨服務會話管理。在delphi中不需要象C#指定一個CookieContainer或其他類似的對象,而只需要象訪問普通的WebService一樣訪問支持會話的WebService即可。