欢迎来到:http://observer.blog.51cto.com
webservcie是可以跨语言跨平台开发的一种技术,各种计算机语言都可以搭建服务器,同时各种计算机语言也可以开发客户端。只要有服务器,不管是用java还是C++抑或是php搭建的,其他语言都可以根据其开放的wsdl开发好客户端,然后调用其方法就像调用本地本项目的方法一样。本文使用java开发客户端,例子依赖于上一篇文章:CXF搭建webService服务器;如果有不明白的可以先看此文章再看本文。
第一:下载CXF包
本文的客户端使用CXF自带工具开发,如果懒得上网找可以到这里下载:apache-cxf-2.6.1.tar
,解压开发包。
第二:配置环境变量
这一步其实可以忽略,但是如果不配置环境变量,在调用命令是就必须到cxf的bin目录下才能调用,缺乏灵活性,所以本文章对其进行配置。
liunx下配置:
调出控制台输入命令:
~$ gedit ~/.bashrc
添加:
export CXF_HOME=/home/roadahead/apache-cxf-2.6.1
export CLASSPATH=$CLASSPATH:${CXF_HOME}/lib
export PATH=$PATH:${CXF_HOME}/bin
自己将“/home/roadahead/apache-cxf-2.6.1”对应到自己的CXF目录。
保存退出,调用以下命令让其立即生效:
~$ source ~/.bashrc
windows下配置:
右键“我的电脑”——>“属性”——>“高级”——>“环境变量”
新建环境变量:
变量名:CXF_HOME
变量值:C:\apache-cxf-2.6.1
变量值是你自己的CXF目录。
CLASSPATH中添加:;%CXF_HOME%\lib
PATH中添加:;%CXF_HOME%\bin
自己将“C:\apache-cxf-2.6.1”对应到自己的CXF目录。
确定完成。
第三:调用命令wsdl2java
将服务器部署好(这里如果不会服务器的部署,自己面壁去),调出控制台,调用如下命令:
~$ wsdl2java -d /home/roadahead/workspace/webServiceClient/src http://127.0.0.1:8080/webServiceCXF/services/Service?wsdl
这里-d后面跟的是生成的客户端代码所放的位置,这里放在我的项目webServiceClient下的src目录下。最后面跟的是你的webservice的wsdl的uri地址,在上一篇文章中,点击{http://service.cxf.observer.com/}GradeService后出现的地址。在此提醒,在实际的项目开发当中,必须将127.0.0.1:8080换成你的网站域名的地址来生成客户端,因为调用客户端是通过远程来进行的,而127.0.0.1:8080显然只适合在本机使用。在这里因为只是用于本机测试,所以就使用127.0.0.1:8080。
如果没有出现错误,那么你在你的目录底下就会看到有新的目录生成,你会看到这个新生的目录里面有着各种.java文件,没错,这些就是你使用wsdl2java命令生成的webservice客户端。
第四:简单的使用客户端
生成客户端之后,将它放到了eclipse里面会看到有错误如下图:
错误去除了之后就好办了,将服务器部署好,运行,然后调用客户端链接webservice,调用方法如下:
public static void main(String[] args) { GradeService_Service gradeService_Service = new GradeService_Service(); GradeService gs = gradeService_Service.getGradeServicePort(); String gstr = gs.getGradeName(12120); System.out.println(gstr); }
当输出is succeed时已经证明调用成功了。
到此,webservice客户端已经开发完成,到了这里已经可以基本满足工作的需要。
第五:封装客户端
开发webservice客户端(以下简称客户端)是非常简单的事情,如果没有封装的话,我也当然不想说啥了。
为什么要封装呢?
一、要是将自己的客户端封装好,打包成jar包以后,哪个java程序想要使用就直接将jar包拿过去就直接用了,这是不是一件很爽的事情?
二、客户端涉及到各种意外情况的反馈,要是服务器没有运行,客户端就运行了怎么反馈信息呢?要是客户端运行的过程中,服务器关闭了又怎么反馈信息呢?而且各种调用客户端的程序的反馈方式都不一样,怎样才能封装得适合各种程序调用呢?比如说web的反馈方式为jsp,swing反馈方式为JOptionPane.showMessageDialog,android的反馈方式可以为Toast.makeText。
三、没有封装的客户端,在调用时是不会强制性的的要你捕获异常的,要是你直接调用,当哪天服务器关闭了,如果是web就会在浏览器中出现异常错误信息,这显然是非常不友好的表现,而且让程序员容易出现不知名错误的。
本文使用“类似于单例”+“类似于工厂模式”+“异常处理”来实现封装。之所以说是类似,是因为这里不是单例,只是在封装类中存在着一个静态链接类,之所以不用真正的单例,是因为要将原客户端代码与封装类分离开来,这样可以在wsdl改变时,再次调用wsdl2java命令生成代码,不用改变其他东西。工厂模式也是一样的道理。如果客户端程序员非要调用原客户端代码,这时也可以让其灵活利用。
首先创建一个异常处理类,我的类如下:
package com.observer.service.manager; public class ConnectException extends Exception { private String title; private String details; public ConnectException(String title, String details) { super(); this.title = title; this.details = details; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getDetails() { return details; } public void setDetails(String details) { this.details = details; } @Override public String toString() { return "com.observer.service.ConnectException [title=" + title + ", details=" + details + "]"; } }
然后serviceManager类,比如我的封装类:GradeServiceManager如下:
import javax.xml.ws.WebServiceException; import com.observer.service.GradeService; import com.observer.service.GradeService_Service; public class GradeServiceManager { private static GradeService_Service gradeService_Service = null; private static GradeService createGradeService() throws ConnectException{ try{ synchronized (Thread.currentThread()) { if(gradeService_Service==null){ gradeService_Service = new GradeService_Service(); } } }catch (WebServiceException e) { e.printStackTrace(); throw new ConnectException("连接异常1", "服务器正在维护中,请稍后再试,或者联系服务器维护人员进行处理"); } return gradeService_Service.getGradeServicePort(); } public static String getGradeName(long toid) throws ConnectException{ String gradeName = null; try { GradeService gs = createGradeService(); gradeName = gs.getGradeName(toid); } catch (ConnectException e) { e.printStackTrace(); throw e; } catch (Exception e) { e.printStackTrace(); throw new ConnectException("连接异常2", "服务器正在维护中,请稍后再试,或者联系服务器维护人员进行处理"); } return gradeName; } }
在这里,我的webservice只有getGradeName一个方法,所以就简单的将createGradeService放在一起了,实际应用中如果方法多了,完全可以将createGradeService方法与webservcie中的方法封装开来以供灵活运用。
第六:导出jar包与导进jar包
导出jar包很简单,右键项目——>Export——>JAR file选择好保存的路径与名称,我这里选择为webServiceClient.jar,然后Finish完成。
导进jar包:普通的项目跟平时导进ssh框架一样,这里要讲的是maven中导进jar包。
maven中导进jar包,个人觉得好使点的有两种方式,一种是将jar包放到maven的库中,然后按普通方式配置pom.xml,另外一种是将jar包放到项目下面的目录下然后在pom.xml中配置。因为这里的jar包不大,而且如果进行分布式开发的话,每个人都必须在自己的maven库中配置并放上这个jar包,所以这里用后一种方式。
一:将webServiceClient.jar复制到项目下的src/main/webapp/WEB-INF/lib目录下,如果没有lib目录,自己创建一个。
二:在pom.xml中的
webServiceClient webServiceClient 1.0 system ${project.basedir}/src/main/webapp/WEB-INF/lib/webServiceClient.jar
这里的
第七:应用客户端
到了这里,已经可以说是完成了配置了,接下来我们来点成就感,在servlet、swing、android中应用客户端
servlet中我们可以直接这样用:
String gradename = null; try { gradename = GradeServiceManager.getGradeName(2323); } catch (ConnectException e) { e.printStackTrace(); request.setAttribute("massage", e.getDetails()); request.getRequestDispatcher("/errer.jsp").forward(request, response); return; }
在swing中我们可以这样用:
String gradename = null; try { gradename = GradeServiceManager.getGradeName(2323); } catch (ConnectException e) { e.printStackTrace(); JOptionPane.showMessageDialog(this, e.getDetails(), e.getTitle(), JOptionPane.ERROR_MESSAGE); return; }
在android中我们可以这样用:
String gradename = null; try { gradename = GradeServiceManager.getGradeName(2323); } catch (ConnectException e) { e.printStackTrace(); Toast.makeText(XXXXX.this, e.getDetails(), Toast.LENGTH_LONG).show(); return; }
当然不管是swing还是android或者web都还有很多用法,自己慢慢鼓捣吧!
在这里共享一下我的客户端项目(webServiceClient)跟maven的web项目(serviceServletClient)代码:http://down.51cto.com/data/857036
接下来还有js的webservice客户端的设计开发与应用