前面三章分别介绍了:

  1. JavaWeb开发(一)框架搭建(使用Maven搭建JavaWeb工程)
  2. JavaWeb开发(二)框架搭建(给工程添加spring支持)
  3. JavaWeb开发(三)CXF webService 服务端与客户端开发

其中第三篇是为了验证第二篇添加的spring支持是否正确,所以新写了利用CXF框架来创建webService的服务端以及客户端。在第三篇文章里,我们开发了一个webService服务端,提供两个方法以供客户端调用,一个传递字符串参数,另一个传递复杂对象。文章里介绍了三种客户端程序的开发,在第三篇里重点介绍了第一种方法,即本地测试,本地测试最大的好处是拥有所有服务端的代码,不需要额外生成服务端代码。在本章中,会重点介绍另外两种方法

  1. CXF客户端动态调用
  2. 利用wsdl2java工具来本地生成服务端代码

动态调用

动态调用的好处是使用简单,代码也很 容易,Myeclipse截图如下:

client

如图所示,新建一个CxfClient2的java类,代码如下:


package com.xiaomager.cxf.client;

import javax.xml.namespace.QName;

import org.apache.cxf.endpoint.Client;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.apache.cxf.service.model.BindingInfo;
import org.apache.cxf.service.model.BindingOperationInfo;

import com.xiaomager.cxf.server.Student;
/**
* 动态调用cxf
* @author mc
*
*/
public class CxfClient2 {

public static void main(String[] args) throws Exception{
String url = "http://localhost:7080/xiaomager/webService/cxfserver?wsdl";
String operation = "sayHello";
String namespace = "http://server.cxf.xiaomager.com/";

JaxWsDynamicClientFactory factory = JaxWsDynamicClientFactory.newInstance();
Client client = factory.createClient(url);

QName opName = new QName(namespace,operation);

Object[] res = client.invoke(opName, "tom");
System.out.println(res[0]);

com.xiaomager.cxf.server.Student stu = new Student();
stu.setName("tom");
stu.setAge(20);
stu.setNumber("111111");
stu.setScore(45.5);
opName = new QName(namespace,"addScore");
res = client.invoke(opName, stu,30.0d);
System.out.println(res[0]);

}

}

代码里需要注意的地方有一下几点:

  1. url的后缀是带?wsdl的。
  2. namespace是服务端wsdl文档里的namespace  http://server.cxf.xiaomager.com/,注意不是targetNamespace。注意这个namespace最后需要有 /
  3. 在new QName的时候,传入的是namespace和方法名,我们有两个方法 ,一个是sayHello一个是addScore。
  4. invoke方法除了第一个参数外,其余都是方法的传递参数,比如  client.invoke(opName, stu,30.0d);   就是调用addScore时,需要传入两个参数,分别是stu和30.o。
  5. 特别提醒,在使用addScore方法动态调用时,传入的Student的类全名为:com.xiaomager.cxf.server.Student,这里的包名 com.xiaomager.cxf.server,就是上面的那个namespace。如果不使用这个namespace包名下的Student,那么调用的时候就会出错:argument type mismatch。所以如果客户端没有这个包,需要新建这个包,并且名字Student必须一样。从这里可以看出,使用String等基本数据类型的好处,就是不用新建实体bean以及对应的包。

运行一下这个main函数的结果是:

client2result

上面这个动态调用的方法需要手动写明 namespace,还有一个不用手动写明namespace的实现方式,主要利用BindingInfo来主动分析,具体如下:


package com.xiaomager.cxf.client;

import javax.xml.namespace.QName;

import org.apache.cxf.endpoint.Client;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.apache.cxf.service.model.BindingInfo;
import org.apache.cxf.service.model.BindingOperationInfo;

import com.xiaomager.cxf.server.Student;
/**
* 动态调用cxf
* @author mc
*
*/
public class CxfClient2_1 {

public static void main(String[] args) throws Exception{
String url = "http://localhost:7080/xiaomager/webService/cxfserver?wsdl";
String operation1 = "sayHello";
String operation2 = "addScore";

JaxWsDynamicClientFactory factory = JaxWsDynamicClientFactory.newInstance();
Client client = factory.createClient(url);

Endpoint endpoint = client.getEndpoint();
QName opName1 = new QName(endpoint.getService().getName().getNamespaceURI(),operation1);
QName opName2 = new QName(endpoint.getService().getName().getNamespaceURI(),operation2);
BindingInfo bindingInfo = endpoint.getEndpointInfo().getBinding();

if (bindingInfo.getOperation(opName1) == null) {
for (BindingOperationInfo operationInfo : bindingInfo.getOperations()) {
if (operation1.equals(operationInfo.getName().getLocalPart())) {
opName1 = operationInfo.getName();    //重点
break;
}
}
}
if (bindingInfo.getOperation(opName2) == null) {
for (BindingOperationInfo operationInfo : bindingInfo.getOperations()) {
if (operation2.equals(operationInfo.getName().getLocalPart())) {
opName2 = operationInfo.getName();   //重点
break;
}
}
}

Object[] res = client.invoke(opName1, "tom");
System.out.println(res[0]);

com.xiaomager.cxf.server.Student stu = new Student();
stu.setName("tom");
stu.setAge(20);
stu.setNumber("111111");
stu.setScore(45.5);

res = client.invoke(opName2, stu,30.0d);
System.out.println(res[0]);

}

}

 

wsdl2java

实际上是利用cxf包里的wsdl2java命令来实现本地生成服务端代码,生成后,使用方式可以和第三篇文章介绍的那种调用方式一样,也可以打成jar包模拟调用开发即可。

因为第一种客户端调用是本地测试,直接使用现成的服务端代码。

而wsdl是本地没有服务端代码,需要生成,生成成功后,可以第一种一样,即改造生成的代码变成第一种的样子,还可以将生成的代码打成jar包,模拟生成代码中client调用的方式进行开发即可。

(1)下载CXF的zip压缩包

首先,如何获取wsdl2java这个命令呢,需要下载cxf的zip包,下载地址如下:http://cxf.apache.org/download.html,我们程序由于使用的是cxf 2.7.18(CXF3.0以上的版本已经不支持JDK6了。),所以下载这个:

2.7.18cxf

(2)使用wsdl2java

下载后解压,找到bin目录下的wsdl2java,在cmd中,到这个目录下,或者在这个目录下空白出 shift+右键,选择在此处打开命令窗口,即直接打开了cmd,输入命令:

wsdl2java -encoding utf-8 -p com.xiaomager.cxf.client.wsdl2java
-d D:\Workspaces\MyEclipse10\xiaomager\src\main\java
-all http://localhost:7080/xiaomager/webService/cxfserver?wsdl

如图:

wsdl2

命令解释:

  1. -p 表示要生成的代码的包名,如果不写的话,默认是namespace=server.cxf.xiaomager.com的反序,即com.xiaomager.cxf.server,这里我们指定为 com.xiaomager.cxf.client.wsdl2java。
  2. -d 表示生成的文件的存放路径,这里指定为代码里面的java路径。
  3. -all,这里可以写 -all,也有-client 生成客户端测试WebService代码和-server 生成服务器启动WebService代码,一般写-all就行了,即全部生成。
  4. -encoding 表示生成java代码的编码方式
  5. 最后一个参数是wsdl地址,注意要加后缀?wsdl
  6. -help 可以看所有参数的使用方法

 

生成后截图如下:

geneartecode

生成后的MyCxfServerImplService 有报错信息,

super

解决方案是 直接把第三个参数features删掉即可。然后直接运行 IMyCxfServer_MyCxfServerImplPort_Client里面的main方法,就能调用了,截图如下:

Iclient

 

然后修改 这个类里面的具体方法,就能够正常调用了

resultGe

 

真正在大型项目中使用的时候,可以把导出的java代码打成jar包,然后在调用的时候 模拟这个 IMyCxfServer_MyCxfServerImplPort_Client的样子 写代码就可以了。

总结

本文重点介绍了CXF客户端的开发,包含动态调用和wsdl2java生成服务端代码两种方式,贴有代码和截图。

 

 

tomcat参数详解与性能优化

其实,前面有些文章已经涉及到相关的内容了,比如: 快速学会Linux安装jdk和tomcat tomcat部署应用的三种方法 本文会详细介绍一下在tomcat安装完成之后一般...

阅读全文

tomcat部署应用的三种方法

在JavaWeb的开发中,tomcat是最常用的web容器,使用tomcat部署web应用,常见的有三种方式,下面以我们在前面开发过的一个WebService的服务端为例(具体服务开...

阅读全文

JavaWeb开发(三)CXF webService 服务端与客户端开发

前面两章分别介绍了: JavaWeb开发(一)框架搭建(使用Maven搭建JavaWeb工程) JavaWeb开发(二)框架搭建(给工程添加spring支持) 其中在第二章最后,我们...

阅读全文

欢迎留言