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

 更新时间:2021年08月26日 10:15:59   作者:万米高空  
这篇文章主要介绍了详谈cxf和axis两种框架下的webservice客户端开发,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

客户端相比服务端,基本没啥配置。引入jar包就好。我这里为了看效果,是新建了maven工程来做客户端。调用另一个webservice服务端maven工程.

环境:jdk1.7+maven3.3.9+tomcat7

框架:spring+cxf/spring+axis(这里不是axis2,是axis)

第一种:基于cxf的客户端开发

1.引入依赖 pom.xml

这里把两种框架的依赖一次到位。就不分开引入了。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.zhanglf</groupId>
    <artifactId>cxfClientTest</artifactId>
    <packaging>war</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>cxfClientTest Maven Webapp</name>
    <url>http://maven.apache.org</url>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
        <!-- 添加 Spring dependency -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.1.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>4.1.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>4.1.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.1.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>4.1.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>4.1.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.1.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>4.1.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>4.1.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>4.1.7.RELEASE</version>
        </dependency>
        <!-- 添加CXF dependency -->
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-core</artifactId>
            <version>3.1.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>3.1.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>3.1.5</version>
        </dependency>
        <!-- 添加CXF dependency -->
        <!-- 另一种axis方法调用webservice依赖 -->
        <dependency>
            <groupId>org.apache.axis</groupId>
            <artifactId>axis</artifactId>
            <version>1.4</version>
        </dependency>
        <dependency>
            <groupId>org.apache.axis</groupId>
            <artifactId>axis-jaxrpc</artifactId>
            <version>1.4</version>
        </dependency>
        <dependency>
            <groupId>axis</groupId>
            <artifactId>axis-wsdl4j</artifactId>
            <version>1.5.1</version>
        </dependency>
        <dependency>
            <groupId>commons-discovery</groupId>
            <artifactId>commons-discovery</artifactId>
            <version>0.2</version>
        </dependency>
        <dependency>
            <groupId>javax.mail</groupId>
            <artifactId>mail</artifactId>
            <version>1.4.7</version>
        </dependency>
    <!-- 另一种axis方法调用webservice -->
    </dependencies>
    <build>
        <finalName>cxfClient</finalName>
    </build>
</project>

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.可以看到在控制台打出访问服务端的代码。

这里写图片描述

拓展:这里的客户端只是传了一个简单的人名,正常传入的是个String类型的xml报文。然后服务端接收报文,进行报文解析,并对信息进行crud操作。并将执行结果以报文形式发送到客户端。客户端在进行报文解析。判断执行情况以便进行下一步操作。下面我们用axis框架进行稍微接近业务的代码开发。

axis客户端代码和cxf都在一个maven工程里。我把工程结构贴出来供参考

这里写图片描述

第二种:基于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
        // 为:一般可以认为是<wsdl:definitions>中的targetNamespace的值,最好还是<wsdl:definitions>标签下的
        // xmlns:tns的值为准。
        // 也是webservice接口的类上注解的targetNamespace,效果如同spring中的requestMapping,用来区分请求定位到具体的那个接口。
        // 这里的命名空间对应的是接口上面的targetNamespace,而不是实现类上面的。故通过wsdl中的<wsdl:definitions
        // 里面的targetNamespace是不准的,应该以<wsdl:import 中的
        // namespace为准或者<wsdl:definitions>标签下的 xmlns:tns的值为准
        String nameSpaceURI = "com.serviceTargetName";
        // 指出service所在URL,这个有没有?wsdl均能正确访问。。。,这里区别于cxf,cxf是不能少这个?wsdl
        String 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文件
         * <wsdl:definitions中的xmlns
         * :tns="com.serviceTargetName"来锁定targetnamespace的值, 这里不能用wsdl文件<wsdl:
         * definitions中的targetNamespace来确定值的原因在于这里的值来源与接口实现类上的targetNamespace注解的值
         * 。如果你接口的实现类中的targetNamespace和接口的不一样,岂不是搞错了。 String
         * localPart-接口下定位方法的方法名
         * :就是这里的抽象方法sayHello方法名,或者wsdl文件<wsdl:binding标签下<wsdl:operation
         * name="sayHello"中name的值。 )
         */
        call.setOperationName(new QName(nameSpaceURI, "sayHello"));
        // 方法参数,如果没有参数请无视。这里如果接口没有用@WebParam(name = "name"),则会报错:Unmarshalling
        // Error: 意外的元素 (uri:"", local:"name")。所需元素为<{}arg0>
        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(
                "<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        sb.append("<userBean>");
        sb.append("<userName>" + name + "</userName>");
        sb.append("</userBean>");
        return sb.toString();
    }
}

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

<?xml version="1.0" encoding="UTF-8"?>
    <userBean>
        <userName>" + 入参:人名 + </userName>
    </userBean>

下面我把调用服务端的方法也贴出来,这样更好理解。昨天已经贴出了服务端的目录结构,我就把其中的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 {
    @Override
     public 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 block
            e.printStackTrace();
        }
        return builder;
    }
    public final static Document parse(InputSource in){
        try {
            return createDocumentBuilder().parse(in);
        } catch (SAXException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.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底层协议自动生成的入参报文。

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:com="com.serviceTargetName">
   <soapenv:Header/>
   <soapenv:Body>
      <com:sayHello>
         <!--Optional:-->
         <parameterName>zhanglifeng</parameterName>
      </com:sayHello>
   </soapenv:Body>
</soapenv:Envelope>

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

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <ns2:sayHelloResponse xmlns:ns2="com.serviceTargetName">
         <return>你好,zhanglifeng  你已成功访问了webservice服务端!</return>
      </ns2:sayHelloResponse>
   </soap:Body>
</soap:Envelope>

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

如果客户端的invoke()方法入参

String xml="
<?xml version=\"1.0\" encoding=\"UTF-8\"?><userBean><userName>zhanglifeng</userName></userBean>"

底层自动为xml加上<![CDATA[ xml ]]>:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:com="com.serviceTargetName">
   <soapenv:Header/>
   <soapenv:Body>
      <com:sayHello>
         <!--Optional:-->
         <parameterName><![CDATA[<?xml version="1.0" encoding="UTF-8"?><userBean><userName>zhanglifeng</userName></userBean> ]]></parameterName>
      </com:sayHello>
   </soapenv:Body>
</soapenv:Envelope>

知道这个原理,在使用SoupUI进行调用webservice接口时就可以使用这种<![CDATA[ 入参xml ]]>格式进行调用。soupui调用的入参如下图

这里写图片描述

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 使用Maven打包时包含资源文件和源码到jar的方法

    使用Maven打包时包含资源文件和源码到jar的方法

    这篇文章主要介绍了使用Maven打包时包含资源文件和源码到jar的方法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-08-08
  • Java服务器端跨域问题解决方案

    Java服务器端跨域问题解决方案

    这篇文章主要介绍了java服务器端跨域问题解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-01-01
  • Maven仓库加载顺序的实例解析

    Maven仓库加载顺序的实例解析

    Maven仓库一般分为本地仓库和远程仓库。那么在实际开发中,在配置了多个仓库的情况下,他们之间的加载访问顺序是怎么样的呢,本文就详细的来介绍一下
    2021-12-12
  • SpringCloud Alibaba环境集成之nacos详解

    SpringCloud Alibaba环境集成之nacos详解

    Spring Cloud Alibaba提供了越来越完善的各类微服务治理组件,比如分布式服务配置与注册中心nacos,服务限流、熔断组件sentinel等,本篇先来介绍SpringCloud Alibaba环境集成之nacos详解,需要的朋友可以参考下
    2023-03-03
  • java类加载器和类反射使用示例

    java类加载器和类反射使用示例

    这篇文章主要介绍了java类加载器和类反射使用示例,需要的朋友可以参考下
    2014-03-03
  • 详解自动注册Gateway网关路由配置

    详解自动注册Gateway网关路由配置

    这篇文章主要为大家介绍了自动注册Gateway网关路由配置的方法详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • Java中List排序的3种常见方法总结

    Java中List排序的3种常见方法总结

    在Java编程中List对象的排序是一个常见的需求,List接口提供了多种排序方法,这篇文章主要给大家介绍了关于Java中List排序的3种常见方法,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-08-08
  • 分布式锁实例教程之防止重复提交

    分布式锁实例教程之防止重复提交

    订单重复问题已经是老生常谈的问题了,下面这篇文章主要给大家介绍了关于分布式锁实例教程之防止重复提交的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2021-11-11
  • Spring mvc是如何实现与数据库的前后端的连接操作的?

    Spring mvc是如何实现与数据库的前后端的连接操作的?

    今天给大家带来的是关于Spring mvc的相关知识,文章围绕着Spring mvc是如何实现与数据库的前后端的连接操作的展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下
    2021-06-06
  • java实现哈弗曼编码与反编码实例分享(哈弗曼算法)

    java实现哈弗曼编码与反编码实例分享(哈弗曼算法)

    本文介绍java实现哈弗曼编码与反编码实例,大家参考使用吧
    2014-01-01

最新评论