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 阅读(1233) 评论(0)  编辑  收藏

只有注册用户登录后才能发表评论。


网站导航: