本文介绍使用CXF实现基于Soap协议的WebService(CXF的版本是3.0.0)

一. 前言

Java有三种WebService规范:Jax-WS,Jax-RS,Jaxm

1. Jax-WS(Java Api for XML-Based WebService):实现Soap协议(Simple Object Access Protocol)(用的也不多了)
2. Jax-RS(Java Api for Resource-Based WebService):实现Rest方式(Representational State Transfer)(推荐)
3. Jaxm支持文件传输,暴露更多底层细节(不推荐)

二. 引入依赖

<!-- Jax-WS前端控制模块,处理服务业务的请求 -->
<dependency>
  <groupId>org.apache.cxf</groupId>
  <artifactId>cxf-rt-frontend-jaxws</artifactId>
  <version>3.0.0</version>
</dependency>

<!-- 数据传输模块(与Rest一样) -->
<dependency>
  <groupId>org.apache.cxf</groupId>
  <artifactId>cxf-rt-transports-http</artifactId>
  <version>3.0.0</version>
</dependency>

<!-- 引入内置的Jetty,如在Tomcat中发布服务可以不引入(与Rest一样)  -->
<dependency>
  <groupId>org.apache.cxf</groupId>
  <artifactId>cxf-rt-transports-http-jetty</artifactId>
  <version>3.0.0</version>
</dependency>

三. 编写SEI(Service Endpoint Interface)

1. 接口

@WebService
public interface HelloWorld {

  //方法名和接口名可以不一致,默认一致,如果一致,可以省略operationName,甚至省略WebMethod
  @WebMethod(operationName = "sayHiString")
  public String sayHelloString(@WebParam(name = "name") String name);

  //对象参数User代码略,User的定义可能不在HelloWorld的包中,在或不在,对后期调用会产生影响
  @WebMethod(operationName = "sayHiUser")
  public User sayHelloUser(User user);

}

2. 实现类

//endpointInterface的值是接口的全名

@WebService(endpointInterface = "net.jmystudio.cxf.soap.HelloWorld", serviceName = "HelloWorld")
public class HelloWorldImpl implements HelloWorld {

  @Override
  public String sayHelloString(String name) {
    return "Hello, (String) " + name;
  }

  @Override
  public User sayHelloUser(User user) {
    return new User("Soap_" + user.getName());
  }

}

四. 发布服务

1. 发布方式一:使用默认的Jetty时,使用Java内置的Endpoint

javax.xml.ws.Endpoint.publish("http://localhost:8088/testcxf/cxf/soap/hello1", new HelloWorldImpl());

(http://localhost:8088/testcxf/cxf/soap/hello1?wsdl)

2. 发布方式二:使用默认的Jetty时,使用CXF提供的JaxWsServerFactoryBean(与Rest类似)

// 1). 服务端工厂类
JaxWsServerFactoryBean server = new JaxWsServerFactoryBean();

// 2). 设置了二个属性(setServiceClass可省)
server.setAddress("http://localhost:8088/testcxf/cxf/soap/hello2");
server.setServiceBean(new HelloWorldImpl());

// 添加输入&输出日志(可选)
server.getInInterceptors().add(new LoggingInInterceptor());
server.getOutInterceptors().add(new LoggingOutInterceptor());

// 3). 创建并发布服务,会发起一个http服务,默认使用Jetty
server.create();

(http://localhost:8088/testcxf/cxf/soap/hello2?wsdl)

3. 发布方式三:在Web应用中,使用CXFNonSpringServlet发布(实际是显式调用了发布方式一(或二)

a. 在web.xml中添加CXFNonSpringServlet的实现类(与Rest一样)

<servlet>
  <servlet-name>CXFNonSpring</servlet-name>
  <servlet-class>net.jmystudio.servlet.WebServiceNonSpringServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>CXFNonSpring</servlet-name>
  <url-pattern>/cxfns/*</url-pattern>
</servlet-mapping>

b. 实现WebServiceNonSpringServlet类(与Rest类似)

import org.apache.cxf.transport.servlet.CXFNonSpringServlet;

public class WebServiceNonSpringServlet extends CXFNonSpringServlet {

  @Override
  protected void loadBus(ServletConfig servletConfig) {
    super.loadBus(servletConfig);
    //使用Endpoint,代码类似发布方式一,也可以使用JaxWsServerFactoryBean,代码类似发布方式二,此处略
    javax.xml.ws.Endpoint.publish("/soap/hello3", new HelloWorldImpl());
  }

}

(http://localhost:8090/testcxf/cxfns/soap/hello3?wsdl)(应用包名是testcxf)

4. 发布方式四:在Web应用中,整合Spring+CXFServlet发布(实际是隐式调用了发布方式一(或二)(最常用)

a. 需要引入Spring相关的Jar包(与Rest一样)

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>4.1.6.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-web</artifactId>
  <version>4.1.6.RELEASE</version>
</dependency>

b. 在web.xml中添加Spring配置和CXFServlet(与Rest一样)

<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>classpath:spring*.xml</param-value>
</context-param>
<listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<servlet>
  <servlet-name>CXF</servlet-name>
  <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>CXF</servlet-name>
  <url-pattern>/cxf/*</url-pattern>
</servlet-mapping>

c.添加关于cxf的spring配置文件(例spring-cfx-soap.xml)(与Rest类似)

<!-- 初始化cxf servlet -->
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />

<!-- 日志拦截器bean -->
<bean id="loggingInInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor"/>
<bean id="loggingOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor"/>

<!-- 发布方式1:使用Endpoint -->
<jaxws:endpoint address="/soap/hello5" implementor="net.jmystudio.cxf.soap.HelloWorldImpl" >
  <jaxws:inInterceptors>
    <ref bean="loggingInInterceptor"/>
  </jaxws:inInterceptors>
  <jaxws:outInterceptors>
    <ref bean="loggingOutInterceptor"/>
  </jaxws:outInterceptors>
</jaxws:endpoint>

<!-- 发布方式2:使用JaxWsServerFactoryBean -->
<jaxws:server address="/soap/hello6" serviceClass="net.jmystudio.cxf.soap.HelloWorldImpl" >
  <jaxws:inInterceptors>
    <ref bean="loggingInInterceptor"/>
  </jaxws:inInterceptors>
  <jaxws:outInterceptors>
    <ref bean="loggingOutInterceptor"/>
  </jaxws:outInterceptors>
</jaxws:server>

(http://localhost:8090/testcxf/cxf/soap/hello5?wsdl) (应用包名是testcxf)
(http://localhost:8090/testcxf/cxf/soap/hello6?wsdl) 

五. 调用方式

无论使用哪种发布方式,发布成功后,在浏览器中输入 $address+"?wsdl",均可看到该WebService的接口定义的详细内容

例如 http://localhost:8088/testcxf/cxf/soap/hello1?wsdl

代码调用主要有2种方式

1. 调用方式一:使用JaxWsProxyFactoryBean获得静态Client,显式依赖WebService接口,需要引入服务提供方提供的jar包)(不推荐)(与Rest类似)

// 1). 客户端工厂类
JaxWsProxyFactoryBean proxy = new JaxWsProxyFactoryBean();

// 2). 设置了两个属性
proxy.setAddress("http://localhost:8088/testcxf/cxf/soap/hello1");
proxy.setServiceClass(HelloWorld.class);

// 添加输入&输出日志(可选)
proxy.getInInterceptors().add(new LoggingInInterceptor());
proxy.getOutInterceptors().add(new LoggingOutInterceptor());

// 3). 创建会发起一个http请求
HelloWorld  staticClient =  (HelloWorld) proxy.create();

// 4). 调用方法,获得数据
System.out.println(staticClient.sayHelloString("Jimmy"));
System.out.println(staticClient.sayHelloUser(new User("Tony")));

2. 调用方式二:使用JaxWsDynamicClientFactory获得动态Client,(无需引入服务提供方提供的jar包)

// 1). 根据接口定义url,获得Client
JaxWsDynamicClientFactory clientFactory = JaxWsDynamicClientFactory.newInstance();
Client dynamicClient = clientFactory.createClient("http://localhost:8088/testcxf/cxf/soap/hello1?wsdl");

// 2). 调用接口,获得数据 
//sayHiString是WebMethod中定义的接口名,不是方法名
Object[] result = dynamicClient.invoke("sayHiString", "Kevin"); 
System.out.println(result[0]);
result = dynamicClient.invoke("sayHiUser", new User("Cherry"));
System.out.println(result[0]);

Note: 调用方式二中,参数是对象的情况需要特别注意,User的定义是否在SEI(此例是HelloWorld)的包中?

如果发布时不指定特定的targetNamespace的话,默认的targetNamespace是SEI的所在包名(逆序),而不是参数User所在包名(2个包名可以不一样的),这时调用的时候,必须传递定义在targetNamespace的User(不是发布时代码中的User,具体可查看该接口的wsdl,会发现此User非彼User),不然会报两个User的java.lang.ClassCastException

解决办法是:

a.最简单:发布时,定义的User和SEI同在一个包中(推荐)
b.动态解析wsdl,需要获得ServiceInfo/BindingInfo/BindingOperationInfo/BindingMessageInfo/MessagePartInfo/PropertyDescriptor等一系列对象,逐步获得接口定义的详细内容后,动态生成参数对象,难度很大(不推荐)

3. 其它调用方式:使用HttpClient或HttpURLConnection等连接,与常规的URL获得数据的方式一致,详情略。(与Rest一样)

 

使用CXF实现基于Soap协议的WebService的更多相关文章

  1. C#如何使用Soap协议调用WebService?

    WebService是什么?它的作用? WebService是一个平台独立.低耦合的.自包含的.基于可编程的可使用xml描述.调用的web应用程序,用于开发分布式的交互式的应用程序. Soap是什么? ...

  2. 使用CXF实现基于Rest方式的WebService(转)

    转自:https://www.cnblogs.com/zjm701/p/6845813.html原文更清晰 本文介绍使用CXF实现基于Rest方式的WebService(CXF的版本是3.0.0) 一 ...

  3. 使用CXF实现基于Rest方式的WebService

    本文介绍使用CXF实现基于Rest方式的WebService(CXF的版本是3.0.0) 一. 前言 Java有三种WebService规范:Jax-WS,Jax-RS,Jaxm 1. Jax-WS( ...

  4. Android与服务器端数据交互(基于SOAP协议整合android+webservice)

    http://www.cnblogs.com/zhangdongzi/archive/2011/04/19/2020688.html 上一节中我们通过http协议,采用HttpClient向服务器端a ...

  5. 通过CXF,开发soap协议接口

    1. 引入cxf的jar包 pom文件里面直接增加依赖 < dependency> <groupId > junit</ groupId> <artifact ...

  6. 如何抓取基于https协议的webservice数据包

    方法一:基于Fiddler2等第三方工具(需要在Java端禁用SSL安全检查) 原文拷贝自http://blog.csdn.net/zmxj/article/details/6327775,向原作者表 ...

  7. Android之SOAP协议与WebService服务器交互,解决超时的问题

    网络搜索大部分不能实际解决问题.特意将解决方法写下.创建MyAndroidHttpTransport 类 , package com.example.omhandroid.lib; import or ...

  8. webservice第二篇【自定义webservice服务、soa、uddi概念、soap协议】

    自定义webservice服务 我们在上一章节中已经使用wsimport生成本地代理来调用webservice的服务了,其实我们自己写的web应用程序也是可以发布webservice的 我们发布了we ...

  9. python发布及调用基于SOAP的webservice

    现如今面向服务(SOA)的架构设计已经成为主流,把公用的服务打包成一个个webservice供各方调用是一种非常常用的做法,而应用最广泛的则是基于SOAP协议和wsdl的webservice.本文讲解 ...

随机推荐

  1. centos /home/ 目录下的中文名文件夹改为英文

    $ export LANG=en_US $ xdg-user-dirs-gtk-update 在弹出的窗口中询问是否将目录转化为英文路径,同意并关闭 在终端中输入命令: export LANG=zh_ ...

  2. 初始github——git的简单使用

    初学者~ 有两篇吧,一篇在github上  https://github.com/DefaultYuan/Git-Pro/wiki/Introduction 文章来源:<git的简单使用> ...

  3. HDU 多校1.7

    Function Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total ...

  4. 树状数组【CF703D】Mishka and Interesting sum

    Description 给你n( 1<=n<=1000000)个数,以及m(1<=m<=1000000)个询问,每个询问包括l和r,问你在这n个数中,区间l~r,出现偶数个数的 ...

  5. 洛谷——P1795 无穷的序列_NOI导刊2010提高(05)

    P1795 无穷的序列_NOI导刊2010提高(05) 题目描述 有一个无穷序列如下: 110100100010000100000… 请你找出这个无穷序列中指定位置上的数字 输入输出格式 输入格式: ...

  6. mysql 获取当前日期及格式化(转)

    MySQL 获取当前日期及日期格式 获取系统日期: NOW() 格式化日期: DATE_FORMAT(date, format) 注: date:时间字段,format:日期格式 select now ...

  7. Maven / Nexus 的用法和经验

    Maven / Nexus 的用法和经验

  8. 【分块打表】Gym - 100923K - Por Costel and the Firecracker

    semipal.in / semipal.out Por Costel the pig, our programmer in-training, has recently returned from ...

  9. 8.3(java学习笔记)动态编译(DynamicCompiler)与动态运行(DynamicRun)

    一.动态编译 简单的说就是在运行一个java程序的过程中,可以通过一些API来编译其他的Java文件. 下面主要说动态编译的实现: 1.获取java编译编译器 2.运行编译器(须指定编译文件) 获取编 ...

  10. 《深入理解Spark-核心思想与源码分析》(二)第二章Spark设计理念和基本架构

    若夫乘天地之正,而御六气之辩解,以游无穷者,彼且恶乎待哉? ——<庄子.逍遥游> 翻译:至于遵循宇宙万物的规律,把握“六气”的变化,遨游于无穷无尽的境域,他还仰赖什么呢! 2.1 初始Sp ...