vulcan

          低頭做事,抬頭看路

             :: 首頁 :: 聯系 :: 聚合  :: 管理
            41 Posts :: 7 Stories :: 28 Comments :: 0 Trackbacks
          由于項目需要,需要同事的DotNet實現的客戶端用我用Java寫的API,以前都沒有用過webservice,而是用進程控制的方法,先在DotNet開一個cmd.exe,然后向cmd.exe的輸入流寫如命令,進而啟動java程序。方法是很簡單,但是這樣的集成,卻穩定性不高,經常有java進程死的情況,檢查了了n編程序,但是卻一直沒有發現同事的程序有什么問題。一直想用C#重新實現底層的通信API,不過一直沒有時間;雖然這樣集成有問題,但是也運行了大半年,只是維護工作量增大了,但是不知道最近為什么,數據的下載越來越不穩定,程序一天死幾次。決定用webservice重新實現C#和java的互通,而不是格外找時間來用C#重寫API。
          使用webservice,其實過多的準備工作也不要,推薦兩個IDE,集成了WTP的Eclipse和Netbeans6.用這兩個工具,我從一個對webservice完全生疏的人,兩天之內完成了系統的集成工作。Netbeans是基于JDK6的JWS實現,主要是靠Annotation,這點很類似DotNet中webservice的實現方法,并且根據我的理解在JWS中實際的WSDL可以是不存在的,而是在runtime時生成的,用Netbeans非常方便。不過,我們現在的所有的Java環境全部是JDK5,不想貿貿然引入新的環境,因此JDK6的JWS是不能用了。看看Eclipse。Eclipse在這個方面也不錯,下載jee版的Eclipse3.3就內置了WTP,新建一個動態網站,然后就可以由兩種方法方便的生成webservice了。第一種,先有類,生成wsdl;第二種,先設計wsdl,類似于java接口的設計,這里eclipse是可以有個圖形化界面設計wsdl的,然后由此wsdl生成java類。不過我習慣第一種,先寫好java類,測試完畢之后,然后直接發布成web service,axis是非常方便部署web service的,它內置的Servlet就可以把你實現的類當作一個bean來使用。還能根據webservice來生成自動的測試頁面,不過不要太相信該測試頁面,下面我就會說到原因。

          由于系統的需要,我的這個webservice是需要維護狀態的,因為它實際上是顯示了一個通信API的web service,所以有一個會話的概念。在網上查了很久,但是都沒有我的這種例子:Axis的服務端,DotNet的客戶端,同時還要使用會話。不過看來一些資料還有Axis的Servlet的源代碼之后,慢慢清晰起來,實際上Servlet就是把HttpServletRequest和HttpServletResponse存到了MessageContext中,對于每個客戶可以用MessageContext.getCurrentContext()并且從中獲取與當前會話相關的request和response,這之后的操作就方便了,這是Servlet API的內容了;而在DotNet客戶端,由web引用生成代理類之后,只要給該代理類指定一個CookieContainer就可以維護狀態了,記住一定要指定CookieContainer,否則每次連接到web service都會是一個新的sessionId,達不到我們要求維護狀態的效果。

          為什么我說不要相信Eclipse生成的Axis的測試頁面呢?看看它的jsp源碼就知道了,它把你的類當作一個bean來用,也就是該類并不是在實際的通過遠程的web請求來使用了,也就是說它的MessageContext為null,自然也就無法維護狀態了,我就是之前沒有專門寫客戶端來測試,而是用它自動生成的測試頁面來測試session吃了虧,大概卡了一個下午的殼吧,怎么弄MessageContext都是null。

          順便說個小tip,使用在我的這個web service接口中,希望也可以對其他人有用:如果要支持一個多用戶,那么把每一個客戶關聯的對象:比如數據庫的操作類(需要事務時)或者我這里的終端通信API,它的指令執行是有Context的,所以必然注定了要關聯到每個用戶。把該對象存入到session是可行的方案,但是如果你需要一個pool自動維護這些對象的life span時,實現一個連接池肯定比session有優勢,但是怎么讓它關聯到每個用戶了。看到網上有人在dotnet中實現的方案是生成該對象的GUID,該對象初始化后(比如在連接時)返回該GUID,然后每一個操作(方法)中都帶上這個GUID參數,不過稍微想一下就知道,這種方案的弊端,時間上該GUID僅在服務端是用意義的,在服務端客戶端之間傳來傳去,給每個方法都多了一個實際上并沒有多大用處的參數。我們可以用sessionId來關聯到該這一唯一用戶。用Axis的可以在MessageContext中得到Session,這個session即是上是Axis對HttpSession的封裝,但是從這個session已經得不到sessionId了。我們需要從MessageContext中的HttpServletRequest下手:
                  MessageContext mc = MessageContext.getCurrentContext();
              HttpServleteRequest    req 
          = (HttpServletRequest) 
                              mc.getProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST);
          通過這個req可以有兩種方法得到sessionId,一種是request.getSession().getId();一種是request.getRequestedSessionId(),分別得到了本次的sessionId還有上一次連接的的sessionId,第二個方法非常有用,如果是新連接,那么getRequestedSessionId()得到的是null值,而request.getSession().getId()每次都會返回本次連接的sessionid。所以我們的思路就明晰起來:通過判斷request.getRequestedSessionId()是否為null決定是否初始化一個對象,并且把該對象用request.getSession().getId()獲取的sessionId作為key存入到pool中。以后每次來了連接都取request.getRequestedSessionId(),并且從pool中取出該sessionId對應的對象,執行該對象相應的方法。這樣就達到了web service的狀態維護了。其實很簡單,只要在DotNet客戶端制定CookiesContainer就可以了。如:
          System.Net.CookiesContainer cc = new System.Net.CookiesContainer();
          MyService service 
          = new MyService();
          service.CookiesContainer 
          = cc;


          posted on 2007-12-26 19:11 vulcan 閱讀(1244) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 金阳县| 平度市| 平乡县| 平南县| 昌乐县| 黄平县| 南丰县| 三台县| 新疆| 建始县| 秦安县| 牡丹江市| 陆河县| 兴山县| 盐边县| 荆门市| 汨罗市| 怀宁县| 固镇县| 延寿县| 巩留县| 东源县| 丽水市| 屯门区| 百色市| 沁水县| 遵化市| 绵阳市| 尚义县| 文昌市| 扎兰屯市| 普兰县| 东宁县| 罗山县| 麦盖提县| 神池县| 拜泉县| 集贤县| 宿州市| 嫩江县| 济宁市|