详谈cxf和axis两种框架下的webservice客户端开发

目录

  • 第一种:基于cxf的客户端开发
    • 1.引入依赖 pom.xml
    • 2.cxf和axis都没有spring配置
  • 第二种:基于axis框架的客户端开发
    • 一个客户端和服务端底层传输数据的了解
      客户端相比服务端,基本没啥配置。引入jar包就好。我这里为了看效果,是新建了maven工程来做客户端。调用另一个webservice服务端maven工程.
      环境:jdk1.7+maven3.3.9+tomcat7
      框架:spring+cxf/spring+axis(这里不是axis2,是axis)

      第一种:基于cxf的客户端开发
      1.引入依赖 pom.xml
      这里把两种框架的依赖一次到位。就不分开引入了。
      4.0.0com.zhanglfcxfClientTestwar0.0.1-SNAPSHOTcxfClientTest Maven Webapphttp://maven.apache.orgjunitjunit3.8.1testorg.springframeworkspring-core4.1.7.RELEASEorg.springframeworkspring-beans4.1.7.RELEASEorg.springframeworkspring-tx4.1.7.RELEASEorg.springframeworkspring-context4.1.7.RELEASEorg.springframeworkspring-context-support4.1.7.RELEASEorg.springframeworkspring-web4.1.7.RELEASEorg.springframeworkspring-webmvc4.1.7.RELEASEorg.springframeworkspring-aop4.1.7.RELEASEorg.springframeworkspring-aspects4.1.7.RELEASEorg.springframeworkspring-jdbc4.1.7.RELEASEorg.apache.cxfcxf-core3.1.5org.apache.cxfcxf-rt-frontend-jaxws3.1.5org.apache.cxfcxf-rt-transports-http3.1.5org.apache.axisaxis1.4org.apache.axisaxis-jaxrpc1.4axisaxis-wsdl4j1.5.1commons-discoverycommons-discovery0.2javax.mailmail1.4.7cxfClient


      2.cxf和axis都没有spring配置
      直接进入业务代码CxfClientTest.java
      package com.zhanglf; import org.apache.cxf.endpoint.Client; import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory; public class CxfClientTest {public static void main(String[] args) throws Exception {JaxWsDynamicClientFactory factory = JaxWsDynamicClientFactory.newInstance(); //通过wsdl服务描述文件创建客户端工厂。Client client = factory.createClient("http://localhost:8080/springCXFWebserviceDemo01/service/HelloWorldService?wsdl"); //尝试使用不带?wsdl的地址//Client client = factory.createClient("http://localhost:8080/springCXFWebserviceDemo01/service/HelloWorldService"); //invoke(//String operationName:要调用的方法名//Object... params):方法的入参。可以是多个。Object[] objs = client.invoke("sayHello", "阿福"); //invoke方法是默认返回Object[]数组。取出数组的第一位值得值就是返回值。System.out.println(objs[0].toString()); }}

      直接Run As Java Application.可以看到在控制台打出访问服务端的代码。
      详谈cxf和axis两种框架下的webservice客户端开发
      文章图片

      拓展:这里的客户端只是传了一个简单的人名,正常传入的是个String类型的xml报文。然后服务端接收报文,进行报文解析,并对信息进行crud操作。并将执行结果以报文形式发送到客户端。客户端在进行报文解析。判断执行情况以便进行下一步操作。下面我们用axis框架进行稍微接近业务的代码开发。
      axis客户端代码和cxf都在一个maven工程里。我把工程结构贴出来供参考
      详谈cxf和axis两种框架下的webservice客户端开发
      文章图片


      第二种:基于axis框架的客户端开发 AxisClientTest.java的code,所有涉及的点我都在代码里说了。解释的文字比较多,代码并不多。
      package com.zhanglf; import java.net.URL; import javax.xml.namespace.QName; import javax.xml.rpc.ParameterMode; import org.apache.axis.client.Call; import org.apache.axis.client.Service; import org.apache.axis.encoding.XMLType; /** * 说明:address="http://localhost:8080/HelloWorld/services/user?wsdl" * http://localhost:8080/HelloWorld:工程访问路径, * /services:此路径在web.xml里面配置cxf拦截器前置访问路径 * /user:此路径在服务端的applicationContext.xml里配置的,要暴露给外部调用的接口,address:请求路径 * * @author Administrator * */public class AxisClientTest {public static void main(String[] args) throws Exception {// namespaceURI// 为:一般可以认为是中的targetNamespace的值,最好还是标签下的// xmlns:tns的值为准。// 也是webservice接口的类上注解的targetNamespace,效果如同spring中的requestMapping,用来区分请求定位到具体的那个接口。// 这里的命名空间对应的是接口上面的targetNamespace,而不是实现类上面的。故通过wsdl中的标签下的 xmlns:tns的值为准String nameSpaceURI = "com.serviceTargetName"; // 指出service所在URL,这个有没有?wsdl均能正确访问。。。,这里区别于cxf,cxf是不能少这个?wsdlString publishUrl = "http://localhost:8080/springCXFWebserviceDemo01/service/HelloWorldService?wsdl"; // 创建一个服务(service)调用(call)Service service = new Service(); // 通过service创建call对象Call call = (Call) service.createCall(); // 设置webservice接口地址call.setTargetEndpointAddress(new URL(publishUrl)); // 你需要远程调用的方法new QName(定位类的targetnamespace,定位方法的方法名)/*** call.setOperationName(new QName("serviceTargetName", "sayHello")); * 方法中的QName方法的入参说明: new QName( String* namespaceURI-定位接口的命名空间:接口注解targetnamespace的值或者wsdl文件* call.addParameter("parameterName", XMLType.XSD_STRING, ParameterMode.IN); // call.addParameter(new QName(soapaction,"xxxx"), XMLType.XSD_STRING,// ParameterMode.IN); // 设置返回类型,一般用string接收call.setReturnType(XMLType.XSD_STRING); // 给方法传递参数,并且调用方法String name = "zhanglifeng"; String temp = getXml(name); // 这里的obj{}是放入几个入参,完全由service提供的接口方法的入参决定,且顺序和你存放的顺序一致!一般入参为String类型的xml报文,回参也是xml报文。Object[] obj = new Object[] { temp }; String result = (String) call.invoke(obj); System.out.println(result); }private static String getXml(String name) {StringBuffer sb = new StringBuffer(""); sb.append(""); sb.append("" + name + ""); sb.append(""); return sb.toString(); }}

      运行方法:Run As Java Application.客户端的请求的入参报文如下:
      " + 入参:人名 +

      下面我把调用服务端的方法也贴出来,这样更好理解。昨天已经贴出了服务端的目录结构,我就把其中的HelloWorldImpl.java中的sayHello方法改一下。code如下:
      package com.zlf.impl; import javax.jws.WebService; import org.springframework.stereotype.Component; import org.w3c.dom.Document; import org.w3c.dom.Node; import com.util.XMLUtils; import com.zlf.HelloWorld; /** * 由于实现类和接口不在同一个包中。所以要加上targetNamespace属性。 * 另外,这里的endpointInterface是实现类对应接口的全路径 * @author Administrator */@WebService(targetNamespace="com.serviceTargetName",endpointInterface="com.zlf.HelloWorld")@Component("HelloWord")//spring注入用public class HelloWorldImpl implements HelloWorld {@Overridepublic String sayHello(String str) {String username="aaa"; Document document = XMLUtils.parse(str); //首先接口开发肯定是双发都知道此方法要接受的报文格式的。我们获取报文中人名对应的节点即可。Node node = document.getElementsByTagName("userName").item(0); if(node !=null){username=node.getTextContent(); }return "你好,"+username+"你已成功访问了webservice服务端!" ; }}

      XMLUtils.java工具类我也贴出来,这个也比较常用。
      package com.util; import java.io.IOException; import java.io.StringReader; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.xml.sax.InputSource; import org.xml.sax.SAXException; /** * 解析器 * @author Administrator * */public class XMLUtils {private final static DocumentBuilder createDocumentBuilder(){DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance(); DocumentBuilder builder=null; try {factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); builder=factory.newDocumentBuilder(); } catch (ParserConfigurationException e) {// TODO Auto-generated catch blocke.printStackTrace(); }return builder; }public final static Document parse(InputSource in){try {return createDocumentBuilder().parse(in); } catch (SAXException e) {// TODO Auto-generated catch blocke.printStackTrace(); } catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace(); }return null; }public final static Document parse(String xml){return parse(new InputSource(new StringReader(xml))); }}

      这样就完成了客户端对服务端的调用。毕竟是初步入门。对以后的开发还是有所裨益。

      一个客户端和服务端底层传输数据的了解 客户端传入参数,执行String result = (String) call.invoke(new Object[] { “zhanglifeng”})后,实际发送给服务端的是一个soap底层协议自动生成的入参报文。
      zhanglifeng

      服务端接收这个报文后自动解析,并把入参赋值给方法sayHello(String str)的入参str.经过处理数据返回给客户端,也是soap底层自动生成的回参报文
      你好,zhanglifeng你已成功访问了webservice服务端!

      客户端自动把从返回报文中取出返回值,并付值给String result。这样底层已经处理过了报文。还有一种情况就是如果客户端传过来的参数本身就是xml时,底层封装参数的问题。
      如果客户端的invoke()方法入参
      String xml="zhanglifeng"

      底层自动为xml加上
      zhanglifeng ]]>

      知道这个原理,在使用SoupUI进行调用webservice接口时就可以使用这种格式进行调用。soupui调用的入参如下图
      详谈cxf和axis两种框架下的webservice客户端开发
      文章图片

      【详谈cxf和axis两种框架下的webservice客户端开发】以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

        推荐阅读