WebService—CXF—实现接口发布和客户端调用

时间:2024-01-01 12:14:15

(一)接口发布的几种方式

定义接口:

@WebService(targetNamespace="http://www.itfad.net/queryUser")
public interface IQueryUser
{
String query(@WebParam(name = "user") UserInfo user);

实现类:

@WebService(endpointInterface="net.itfad.services.IQueryUser")
public class QueryUserImpl implements IQueryUser
{
public String query(UserInfo user)
{
if (user == null)
throw new IllegalArgumentException("参数user不能为null");
return "your name is " + user.getUserName();
}

一、使用jax-ws方式(Java EE原生代码方式)

package server;
import hb.QueryUserImpl;
import hb.SessionSendMsg;
import javax.xml.ws.Endpoint;
public class DeployHelloWorldService { public static void main(String[] args) {
//发布第1个接口
QueryUserImpl service = new QueryUserImpl();
String address = "http://localhost:9000/helloWorld";
Endpoint.publish(address, service);
//发布第2个接口
SessionSendMsg sessionSendMsg = new SessionSendMsg();
String address1 = "http://localhost:9000/session";
Endpoint.publish(address1, sessionSendMsg);
}
}

二、使用CXF方式

String url="http://localhost:8080/queryUser";
JaxWsServerFactoryBean factoryBean=new JaxWsServerFactoryBean();
factoryBean.setAddress(url);
factoryBean.setServiceClass(IQueryUser.class);
factoryBean.setServiceBean(new QueryUserImpl());
factoryBean.create()

三、CXF Simple FrontEnd方式

该方式无需在类中指定相关协议,也就是说不需要在类中指定相关webservice注解,一个普通类就行。

ServerFactoryBean svrFactory = new ServerFactoryBean();
//设置服务接口类
svrFactory.setServiceClass(IQueryUser.class);
svrFactory.setAddress("http://localhost:8080/queryUser");
//设置服务实现接口类
svrFactory.setServiceBean(QueryUserImpl);
svrFactory.create();

(二)客户端调用的几种方式

一、WSDL2Java WSDL2Java generated Client

根据wsdl文件生成客户端代码,本地化调用。cxf框架有基于maven的生成客户端代码的插件,使用如下:

<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>${cxf.version}</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<wsdlOptions>
<wsdlOption>
<wsdl>src/main/resources/OrderProcess.wsdl</wsdl>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>

二、JaxWsProxyFactoryBean

客户端直接调用服务器端提供的服务接口,不需要生成客户端代码,类似RMI的机制。CXF通过运行时代理生成远程服务的代理对象,在客户端完成对webservice的访问。所以客户端也必须依赖服务器端的接口,限制是很大的,要求服务器端的webservice必须是java实现。似乎失去了webservice跨平台数据调用的意义。

    package demo.order.client;
import demo.order.Order;
import demo.order.OrderProcess;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
public class ClientProxyClient { public static void main(String args[]) throws Exception {
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(OrderProcess.class);
factory.setAddress("http://localhost:8080/OrderProcess");
OrderProcess service = (OrderProcess)factory.create(); Order order = new Order();
order.setCustomerID("C001");
order.setItemID("I001");
order.setPrice(100.00);
order.setQty(20);
String result = service.processOrder(order);
System.out.println("The order ID is " + result);
}
}

三、Dynamic Client 动态代理

CXF提供动态类的两个工厂类。如果你的服务是在JAX-WS的规范来定义,你应该使用jaxwsdynamicclientfactory。如果你不想要或不需要JAX-WS语义,使用dynamicclientfactory。

下文使用jaxws语义。只要指定服务器端wsdl文件的位置,然后指定要调用的方法和方法的参数即可,不关心服务端的实现方式,动态生成客户端代码。让我们假设您有一个WSDL,它定义了一个"echo"操作(方法),它接受一个字符串的输入并输出一个字符串。你可以使用jaxwsdynamicclientfactory它这样:

JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
Client client = dcf.createClient("echo.wsdl");
Object[] res = client.invoke("echo", "test echo");
System.out.println("Echo response: " + res[0]);

由于有许多的WSDL将有更复杂的类型。在这种情况下,jaxwsdynamicclientfactory更关心的是生成这些类型的java类。例如,我们可能有一个跟踪组织中人员的人员服务。在样品下面我们创建一个Person对象,动态地发送到服务器的addperson操作(方法):

JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
Client client = dcf.createClient("people.wsdl", classLoader);
Object person = Thread.currentThread().getContextClassLoader().loadClass("com.acme.Person").newInstance();
Method m = person.getClass().getMethod("setName", String.class);
m.invoke(person, "Joe Schmoe");
client.invoke("addPerson", person);

You may be asking yourself the following question: "Where did the class name 'com.acme.Person' come from?"

One way to get the class names is to run wsdl2java and examine the results. The dynamic client factory uses the same code generator as that tool.

四、JaxWsServerFactoryBean

用JaxWsServerFactoryBean发布,需要独立的jetty包。SUN针对Java的Web Service实现先后提出两套API,一个是JaxRPC,另一个JaxWs。 JaxWsServiceFactoryBean继承了ReflectionServiceFactoryBean, 并提供JaxWsAPI的支持。在该类中这里主要是支持JSR181,重载了很多父类的方法,有关createServiceFromWSDL的部分则可重用父类ReflectionServiceFactoryBean.

在CXF中有几个很相似名词 JaxWsServiceFactoryBean, JaxWsServerFactoryBean,很相似。Service创建客户端的代理,生成factory对象,用于调用服务端的方法。Server创建服务端的对象 用于发布服务。Server 是对服务器端来说,Service是针对服务信息来说的。也就是一个Server必然要包含一个Servie信息。如果使用CXF内部API来创建服务的话,只需要通过设置JaxWsServerFactoryBean 就可以发布服务了。在JaxWsServerFactorBean的构造函数中会创建一个缺省JaxWsServiceFactoryBean. 当然在构建自己的Server的同时也可以设置自己的ServiceFactoryBean,(API目的在于CXF对Spring的支持?)你可以在Spring中定义装配符合自己要求的服务,自然需要有读取和设置的这或者那样Bean的方法了。

五、Ajax(js+xml的方式调用)

Ajax请求的URL即webservice服务地址,请求方式必须是POST。需要手动设置请求头,构造请求体。必须要对SOAP文件非常的了解。一般使用ajax调用,应该是在已经获知了以下信息以后才去调用:

a:获知请求(request)的soap文本。

b:获知响应(response)的soap文本。

请求文件和响应文本格式,一般会随web服务的发布一同发布。我们可以通过WSExplorer获取上面两段文本。具体调用方法如下:

1:前端页面请求:

<body>
<input type="text" id="msg" />
<input type="button" onclick="sendAjaxWS();" value="通过ajax调用webservice服务"/>
</body>

2:js里面封装请求信息:

      <script>
var xhr;
function sendAjaxWS(){
xhr = new ActiveXObject("Microsoft.XMLHTTP");
//指定ws的请求地址
var wsUrl = "http://192.168.1.108:5678/hello";
//手动构造请求体
      var requestBody = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" '
+ 'xmlns:q0="http://service.itcast.cn/" xmlns:xsd="http://www.w3.org/2001/XMLSchema "'
+ ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
+ '<soapenv:Body><q0:sayHello><arg0>'
+ document.getElementById("msg").value+'</arg0> <arg1>10</arg1> </q0:sayHello></soapenv:Body></soapenv:Envelope>';
       //打开连接
xhr.open("POST",wsUrl,true);
//重新设置请求头
xhr.setRequestHeader("content-type","text/xml;charset=utf8");
//设置回调函数
xhr.onreadystatechange = _back;
//发送请求
xhr.send(requestBody);
} //定义回调函数
function _back(){
if(xhr.readyState == 4){
if(xhr.status == 200){
var ret = xhr.responseXML;
//解析xml
var eles = ret.getElementsByTagName("return")[0];
alert(eles.text);
}
}
}
</script>