使用webservice,其實過多的準(zhǔn)備工作也不要,推薦兩個IDE,集成了WTP的Eclipse和Netbeans6.用這兩個工具,我從一個對webservice完全生疏的人,兩天之內(nèi)完成了系統(tǒng)的集成工作。Netbeans是基于JDK6的JWS實現(xiàn),主要是靠Annotation,這點很類似DotNet中webservice的實現(xiàn)方法,并且根據(jù)我的理解在JWS中實際的WSDL可以是不存在的,而是在runtime時生成的,用Netbeans非常方便。不過,我們現(xiàn)在的所有的Java環(huán)境全部是JDK5,不想貿(mào)貿(mào)然引入新的環(huán)境,因此JDK6的JWS是不能用了。看看Eclipse。Eclipse在這個方面也不錯,下載jee版的Eclipse3.3就內(nèi)置了WTP,新建一個動態(tài)網(wǎng)站,然后就可以由兩種方法方便的生成webservice了。第一種,先有類,生成wsdl;第二種,先設(shè)計wsdl,類似于java接口的設(shè)計,這里eclipse是可以有個圖形化界面設(shè)計wsdl的,然后由此wsdl生成java類。不過我習(xí)慣第一種,先寫好java類,測試完畢之后,然后直接發(fā)布成web service,axis是非常方便部署web service的,它內(nèi)置的Servlet就可以把你實現(xiàn)的類當(dāng)作一個bean來使用。還能根據(jù)webservice來生成自動的測試頁面,不過不要太相信該測試頁面,下面我就會說到原因。
由于系統(tǒng)的需要,我的這個webservice是需要維護(hù)狀態(tài)的,因為它實際上是顯示了一個通信API的web service,所以有一個會話的概念。在網(wǎng)上查了很久,但是都沒有我的這種例子:Axis的服務(wù)端,DotNet的客戶端,同時還要使用會話。不過看來一些資料還有Axis的Servlet的源代碼之后,慢慢清晰起來,實際上Servlet就是把HttpServletRequest和HttpServletResponse存到了MessageContext中,對于每個客戶可以用MessageContext.getCurrentContext()并且從中獲取與當(dāng)前會話相關(guān)的request和response,這之后的操作就方便了,這是Servlet API的內(nèi)容了;而在DotNet客戶端,由web引用生成代理類之后,只要給該代理類指定一個CookieContainer就可以維護(hù)狀態(tài)了,記住一定要指定CookieContainer,否則每次連接到web service都會是一個新的sessionId,達(dá)不到我們要求維護(hù)狀態(tài)的效果。
為什么我說不要相信Eclipse生成的Axis的測試頁面呢?看看它的jsp源碼就知道了,它把你的類當(dāng)作一個bean來用,也就是該類并不是在實際的通過遠(yuǎn)程的web請求來使用了,也就是說它的MessageContext為null,自然也就無法維護(hù)狀態(tài)了,我就是之前沒有專門寫客戶端來測試,而是用它自動生成的測試頁面來測試session吃了虧,大概卡了一個下午的殼吧,怎么弄MessageContext都是null。
順便說個小tip,使用在我的這個web service接口中,希望也可以對其他人有用:如果要支持一個多用戶,那么把每一個客戶關(guān)聯(lián)的對象:比如數(shù)據(jù)庫的操作類(需要事務(wù)時)或者我這里的終端通信API,它的指令執(zhí)行是有Context的,所以必然注定了要關(guān)聯(lián)到每個用戶。把該對象存入到session是可行的方案,但是如果你需要一個pool自動維護(hù)這些對象的life span時,實現(xiàn)一個連接池肯定比session有優(yōu)勢,但是怎么讓它關(guān)聯(lián)到每個用戶了。看到網(wǎng)上有人在dotnet中實現(xiàn)的方案是生成該對象的GUID,該對象初始化后(比如在連接時)返回該GUID,然后每一個操作(方法)中都帶上這個GUID參數(shù),不過稍微想一下就知道,這種方案的弊端,時間上該GUID僅在服務(wù)端是用意義的,在服務(wù)端客戶端之間傳來傳去,給每個方法都多了一個實際上并沒有多大用處的參數(shù)。我們可以用sessionId來關(guān)聯(lián)到該這一唯一用戶。用Axis的可以在MessageContext中得到Session,這個session即是上是Axis對HttpSession的封裝,但是從這個session已經(jīng)得不到sessionId了。我們需要從MessageContext中的HttpServletRequest下手:
HttpServleteRequest req = (HttpServletRequest)
mc.getProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST);
MyService service = new MyService();
service.CookiesContainer = cc;