WebService框架WebService-CXF (二) --参考传智播客视频

1      :WebService框架WebService-CXF

 

1.1    简介:

1.1.1  什么是CXF

l  Apache CXF = Celtix + Xfire :结合Celtix + Xfire的优点;

l  支持多种协议:

•    SOAP1.1,1,2

•    XML/HTTP

•    CORBA(Common Object Request Broker Architecture公共对象请求代理体系结构,早期语言使用的WS。C,c++,C#)

•    并可以与Spring进行快速无缝的整合

•    灵活的部署:可以运行在Tomcat,Jboss,Jetty(内置),IBMWS,BeaWL上面。

 

 

 

 

 

 

 

 

                                                                  

 

 

 

1.1.2 CXF的结构:

 

 

1.1.2.1 Bus CXF框架的支撑

Bus是CXF框架的支撑.CXF Bus由spring配置文件构成(cxf.xml),在servlet初始化时

通过SpringBusFactory加载,它为所有终端定义了公共的上下文.它织入了所有运行

时的结构组件并提供了一个公共的应用上下文.SpringBusFactory扫描并加载类路径

下的META-INF/cxf目录并从以下文件构建上下文.

META-INF/cxf/cxf.xml

META-INF/cxf/cxf-extension.xml

META-INF/cxf/cxf-property-editors.xml

XML文件是安装CXF类库的一部分.CXF内部使用Spring配置.cxf.xml文件中bus定义如

下:

<bean id="cxf"class="org.apache.cxf.bus.CXFBusImpl" />

核心bus组件是CXFBusImpl,该类更多扮演拦截器供应商的角色对于终端出入的请求.

这些拦截器一旦应用,即可用于上下文中所有的终端.cxf.xml文件也定义了其他的组

件,比如BindingFactoryManager, ConduitFactoryManager等等.这些组件可用于bus

的扩展.可以使用getExtension()方法这些组件.注册这些组件以用于获取或更新服

务终端级别参数如服务绑定,传输协议,中转等等.

--------------

1.1.2.2Frontend-前端:

Frontend

CXF提供了前端建模的概念,可以使用不同的前端API创建ws.这些API使用简单工厂

bean和JAX-WS实现创建ws.可以创建动态ws客户端.CXF支持的前端主要是JAX-WS.

---------

1.1.2.3Message and intercetpors: 消息和拦截器

CXF框架中重要的组件之一是拦截器组件.拦截器拦截客户端和服务器间的消息.在

CXF,这通过拦截器链的概念实现.拦截器链是CXF运行时的核心功能.链中的每个拦截

器是可配的,用户可以控制他的执行.

框架的核心的是拦截器接口,它定义了两个方法handleMessage和handleFault,都携

带Message类型作为参数.

拦截器通常分组成各阶段.每个阶段执行特定的消息处理,每个阶段又被添加到拦截

器链中,因此,链有时有序的拦截器阶段的列表.典型的ws终端有三个连接器链:

Inbound messages chain(入消息链)

Outbound messages chain(出消息链)

Error messages chain(错误消息链)

内置拦截器如日志,安全,也可以自定义拦截器.

-----

1.1.2.4Service Model-主要用于生成wsdl文件的各个元素。

建模service,创建各种WSDL元素如操作,绑定,终端,schema等等.

如下显示了服务模型中的各个组件:

-------

1.1.2.5 Data binding

数据绑定是ws开发的关键.它意味着java对象和xml元素之间的映射.数据绑定组件执

行这一工作.CXF最新版本使用JAXB2.1.JAXB使用注解定义java对象和XML之间的映射.如下:

@XmlRootElement(name="processOrder",

                          namespace="http://localhost/orderprocess")

@XmlAccessorType(XmlAccessType.FIELD)

@XmlType(name="processOrder",namespace="http://localhost/orderprocess")

public class OrderProcess {

         @XmlElement(name="arg0",namespace="")

         privateorder.Order arg0;

         //Gettterand Setter

         …

}

-----------

协议绑定:protocol bindings

CXF支持以下形式的绑定:

SOAP1.1

SOAP1.2

CORBA

Pure XML

--

数据传输——transport

CXF支持以下数据传输方式:

HTTP

CORBA

JMS

LOCAL

 

下载完成后将其解压到某个目录下

 

1.2    Ant +CXF+java环境搭建

l  Ant

l  Tomcat

l  并设置以下环境变量:

•    JAVA_HOME 

•    CXF_HOME

•    ANT_HOME

•    CATALINA_HOME  (tomcat_hone)

•    Path =%JAVA_HOME%\bin;%CXF_HOME%\bin;%CATALINA_HOME%\bin;%ANT_HOME%\bin

•    CLASSPATH=.;%CXF_HOME%\lib\cxf-manifest.jar;.\build\classes

 

1.2.1 1、为什么要用到ant这个工具呢?

Ant做为一种工具已经广泛被使用,并且历史悠久。使用ant的内置命令,可以编译java源文件(javac),运行java文件(java),给class文件打包(jar、war、ear),也可以创建(mkdir)、删除(del)、拷贝(copy),甚至可以使用ant执行sql文件。由于ant是用xml语言写成的文件,并取默认名为build.xml文件。所以,今后大家应该在见到名为build.xml文件时知道这是一个ant的文件。

2、默认在Eclipse和MyEclipse的对ant有内建的支持。大家可以在MyEclipse中任意项目中建立一个文件叫build.xml文件,你会发现它有不同的图标(上面有个小蚂蚁)。

 

 

1.2.2 用ANT来构造第一个CXF示例:

l  在cxf_home\samples\java_first_pojo目录下启动服务器:

•    在命令行模式下进入上述目录:

•    执行 以下命令 ant server   (server不是固定的_这里使用server)

l  在同一目录下打开新命令行窗口运行:

•    ant client

l  上面的代码,其实就是通过ant工具对源代码进行编译和运行。

l  如果能编译通过,将会显示buildsuccess.

•     

1.2.3 用ANT来构造第一个CXF示例:

查看它的源代码并修改运行:

 

1.2.3.1用ANT将它发布到Tomcat服务器上:

l  1、执行ant clean清除以前生成的代码

l  2、执行ant war打包此应用。

l  3、执行ant deploy –Dtomcat=true将项目发布到tomcat的服务器上。

l  4、启动tomcat服务器

l  5、打开IE的地址栏输入:

http://localhost:9999/helloworld/services/hello_world?wsdl

或:http://localhost:9999/helloworld/services

l  6、在命令行执行:

•    ant client-servlet –Dbase.url=http://localhost:9999

•    或在MyEclipse的WebServiceExplorer中访问这个WebService

l  7、停止tomcat服务器。

l  8、卸载应用:ant undeploy –Dtomcat=true

l  9、清空项目:ant clean

 

 

 

1.3    Eclipse中开发CXF的JavaSE应用:

l  导入CXF中的 所有jar文件。可以通过WACH_JARS来观察各jar文件的用途。

l  建立好之后的项目如

      右图所示:

 

 

 

CXF发布服务的类:

l  用两个不同的类发布应用:

l  ServerFactoryBean   --FacotryBean

l  JaxWsServerFactoryBean(建议使用此类)

 

1.3.1  使用ServerFactoryBean发布服务:(不建议使用)

l  使用ServerFactoryBean发布服务。

l  使用CXF发布一个服务,与JDK6发布一个服务完全不同

•    * 即使是不使用@WebService注解,一样可以发布成功

•    * 即使此类没有对外公布的方法一样可以发布成功

 

 

package cn.itcast.cxf1;

import java.util.Date;

import org.apache.cxf.frontend.ServerFactoryBean;

/**

 * 使用ServerFactoryBean发布服务

 * 使用CXF发布一个服务,与JDK6发布一个服务完全不同

 * 即使是不使用@WebService注解,一样可以发布成功

 * 即使此类没有对外公布的方法一样可以发布成功

 */

public class CxfOneServer {

         public String sayHi(){

                   return "Hello:"+new Date();

         }

         public static void main(String[] args) {

                   ServerFactoryBean bean = //声明实例

                            new ServerFactoryBean();

                   //绑定到发布地址的端口

                   bean.setAddress("http://127.0.0.1:9999/one");

                   //设置服务接口,如果没有接口,则为本类

                   bean.setServiceClass(CxfOneServer.class);

                   //设置接口实现类,即服务类

                   bean.setServiceBean(new CxfOneServer());

                   bean.create();//发布服务

                   System.err.println("启动成功");

         }

}

 

1.3.2  使用JaxWsServerFactoryBean发布服务:(建议使用此类)

 

l  JaxWsServerFactoryBean是ServerFactoryBean的子类,也是功能扩展类。

l  但在CXF的API文档中没有提供此类API,请通过查看源代码的方式获取此类的帮助。

l  此类,必须要在被发布为服务的类上添加@WebService注解,如果不加注解,虽然不

出错,但也不会对外暴露任何方法。

使用此类生成的wsdl文件更加规范。

l  以下是从它的源代码中找到的对此类的说明。

 

 

package cn.leaf.one;

import javax.jws.WebService;

import org.apache.cxf.jaxws.JaxWsServerFactoryBean;

@WebService

public class OneService {

         public String sayHi(){

                   return "Good";

         }

         public static void main(String[] args) throws Exception {

                   JaxWsServerFactoryBean bean  //使用jaxWs对其进行发布

                     = new JaxWsServerFactoryBean();

                   bean.setServiceBean(new OneService());

                   bean.setServiceClass(OneService.class);

                   bean.setAddress("http://localhost:4444/one");

                   bean.create();

                   System.err.println("服务启动成功。。");

                   //Thread.sleep(1000*60*60);

                   //System.exit(0);

         }

}

 

 

 

 

 

1.3.3 使用ClientProxyFactoryBean客户端调用

在同一个项目中调用

package cn.itcast.cxf1;

import org.apache.cxf.frontend.ClientProxyFactoryBean;

public class Client {

      public static void main(String[] args) {

                ClientProxyFactoryBean bean = //创建客户端类

                         new ClientProxyFactoryBean();

                //设置访问地址

                bean.setAddress("http://localhost:9999/one");

                //设置服务接口,直接使用本项目中的接口

                bean.setServiceClass(CxfOne.class);

                //通过create方法返回接口实例

                CxfOne s =   (CxfOne) bean.create();

                String str = s.sayHi();//调用

                System.err.println(str);

      }

}

 

 

在不同的项目中调用

      public static void main(String[] args) {

                ClientProxyFactoryBean bean = //创建客户端类

                         new ClientProxyFactoryBean();

                //设置访问地址

                bean.setAddress("http://localhost:9999/one");

                //设置服务接口,直接使用本项目中的接口

                bean.setServiceClass(CxfOnePortType.class);

                //通过create方法返回接口实例

                CxfOnePortType one =   (CxfOnePortType) bean.create();

                String s = s.sayHi();//调用

                System.err.println(s);

      }

 

 

 

1.4    CXF的实践

1.4.1  使用CXF的类发布一个服务:

 

packagecn.leaf.one;

import javax.jws.WebService;

import org.apache.cxf.jaxws.JaxWsServerFactoryBean;

@WebService

publicclassOneService {

   publicString sayHi(){

      return"Good";

   }

   publicstaticvoidmain(String[] args)throwsException {

      JaxWsServerFactoryBeanbean//使用jaxWs对其进行发布

        = new JaxWsServerFactoryBean();

      bean.setServiceBean(new OneService());

      bean.setServiceClass(OneService.class);

      bean.setAddress("http://localhost:4444/one");

      bean.create();

      System.err.println("服务启动成功。。");

      //Thread.sleep(1000*60*60);

      //System.exit(0);

   }

}

 

 

1.4.2  使用JaxWsProxyFactoryBean客户端调用

 

packagecn.itcast.cxf2;

importorg.apache.cxf.jaxws.JaxWsProxyFactoryBean;

publicclassA {

publicstaticvoid main(String[] args) {

JaxWsProxyFactoryBean bean =

newJaxWsProxyFactoryBean();

bean.setAddress("http://localhost:9999/two");

//此外注册的必须是一个接口,否则将抛出异常信息

bean.setServiceClass(Cxf2Server.class);

Cxf2Server s = (Cxf2Server) bean.create();

System.err.println(s.sayHello());

}

}

 

 

1、在使用CXF发布服务时,需要首先写一个接口,用以声明服务类型。这有点类似于Spring中的服务层的实现。

package cn.test;

 

import javax.jws.WebService;

import javax.xml.ws.BindingType;

import javax.xml.ws.soap.SOAPBinding;

 

@WebService

@BindingType(value=SOAPBinding.SOAP12HTTP_BINDING)

 

publicinterface IHelloService {

 

   public String sayHello(String name);

}

 

 

1.4.2.1wsdl2java生成客户代码

l  在cxf中,也提供了一个用于生成客户端调用代码的工具。它的功能就如同wsimport一样。

l  先让我们了解一下cxf的wsdl2java工具,可以生成一堆客户端调用的代码。

l  此工具位于cxf_home/bin目录下。参数与wsimport有所不同。

l  它包含以下参数:

•    -d参数,指定代码生成的目录。

•    -p参数,指定生成的新的包结构。

l  需要说明的是,由于wsdl2java是根据jdk1.7生成的本地代码,所以,需要对生成的代码做一点点修改。

l  在命令行执行:

         wsdl2java–d . http://127.0.0.1:6666/helloworld?wsdl

 

1、注意:由于使用的是apache-cxf-2.4.0版本,它是支持jdk1.7的。所以,对于生成的Service要进行稍微的修改。

   在jdk1.6中的javax.xml.ws.Service的构造方法接收二个参数为:(String url,QName qname);

在jdk1.7中的javax.xml.ws.Service的构造方法中接收三个参数为:(String url,QName qname,features);

2、将生成的代码,拷贝到项目目录,然后使用以前相同方法调用。

    注意:如果你对@WebMethod设置了header=true参数,将会在调用时多传递一个参数。它参数可以直接传null值。

            对于这种情况,可以将header=true修改成header=false然后再重要获取客户端源代码。

3、大家可能发现了,使用cxf生成的客户端代码与wsimport差不多,甚至是一样,那为什么还要使用cxf呢?

它较好的发布方式、较容易的与其他服务器集成、及与Spring的完美结合都不得不让我们使用cxf。

 

调用端代码:

1、必须已经使用wsimport或wsdl2java生成了客户端代码。

以下是源代码:

packagecom.run;

importcom.itcast.cxfserver.javaclient.IHelloWorld;

importcom.itcast.cxfserver.javaclient.IHelloWorldPortType;

/**

 * 使用java6来调用cxf生成的客户端类的服务

 * 不管是用wsimport还是用wsdl2java生成的类基本上是完全一样的

 */

publicclassCxfServerJava6Client {

   publicstaticvoid main(String[] args) {

      //调用使用wsimport生成的代码

      IHelloWorldPortType hello = newIHelloWorld().getIHelloWorldPort();

      String str = hello.sayHello("小王");

      System.err.println(str);

     

      //调用使用wsdl2java生成的代码(一样)

      com.itcast.cxfserver2.javaclient.IHelloWorldPortType client =

         newcom.itcast.cxfserver2.javaclient.IHelloWorld().getIHelloWorldPort();

      String str2 = client.sayHello("CXF");

      System.err.println(str2);

   }

}

 

3、要想研究更多程序请见:cxf2.4_ws服务项目和cxf2.4_java6client客户端项目。

 

 

 

1.4.3 给服务添加消息拦截器:-这个非常有用:

在服务发布之前添加拦截器:

l  LoggingInInterceptor – 信息输入时的拦截器 –请求

l  LoggingOutInterceptor –信息输出时的拦截器-响应

 

         server.getInInterceptors().add(new LoggingInInterceptor());

         server.getOutInterceptors().add(new LoggingOutInterceptor());

 

给服务器添加拦截器,类似于使用TCP/IP Monitor来捕获SOAP消息的过程。

 

package cn.itcast.cxf;

 

import org.apache.cxf.interceptor.LoggingInInterceptor;

import org.apache.cxf.interceptor.LoggingOutInterceptor;

import org.apache.cxf.jaxws.JaxWsServerFactoryBean;

 

/**

 *

 * 使用JaxWsServerFactoryBean发布CXFWeb服务

 * 必须加入WebService注解,如果不加,虽然不报错,但是所有的方法都暴露不出来

 */

 

public class Server {

 

    public static void main(String[] args) {

        JaxWsServerFactoryBean bean = new JaxWsServerFactoryBean();

        bean.setAddress("http://192.168.1.100:7788/hello");

        //提供服务的类的类型或接口类型

        bean.setServiceClass(IHelloService.class);

        bean.setServiceBean(new HelloServiceImpl());

        //可以多次针对不同的对象在(srping)中配置

        //加入请求的消息拦截器

        bean.getInInterceptors().add(new LoggingInInterceptor());

        //加入请求的消息拦截器

        bean.getOutInterceptors().add(new LoggingOutInterceptor());

       

        bean.create();

        System.out.println("Hello Service ready...");

    }

}

 

1.4.4 使用JavaScript也可以访问WebServie:

l  jQuery访问WebService.

•    1、在本域准备jquery.js (由于jquery对跨域的请求做了限制,所以jquery仅限于在本域中使用。但为了快速解析XML文件,仍然可以使用jquery当成解析xml文件的工具。)。

•    2、通过js发起ajax请求。

<%@pagelanguage="java"import="java.util.*"pageEncoding="UTF-8"%>

      <%@ tagliburi="http://java.sun.com/jsp/jstl/core" prefix="c" %>

      <html>

      <head>

         <script type="text/javascript" src="<c:url value='/js/jquery-1.6.2.js'/>"></script>

      </head>

      <body>

      <p>用js来控制的客户端</p>

         <button id="all">显示所有</button><br/>

         <hr/>

         Name:<input type="text" id="_name">,Age:<input type="text" id="_age">

         <button id="add">增加一个</button><br/>

         <table id="tb" width="70%" border="1">

            <tr>

                <th>学生姓名</th>

                <th>学生年龄</th>

            </tr>

         </table>

      </body>

      <script type="text/javascript">

          $(function(){

             var url = "http://localhost:7777/xcxf3_ss/ws/studQuery";

             $("#all").click(function(){

                //查询时必须向服务器发以下xml文件

                 var xml = '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">'+

                      '<soap:Body><ns2:query xmlns:ns2="http://service.stud.cn/"/>'+

                      '</soap:Body></soap:Envelope>';

                 $.ajax({

                    url:url,

                    type:'post',

                    dataType:'xml',

                    contentType:'application/soap+xml;charset=UTF-8',

                    data:xml,

                    success:function(data){

                       $("#tb tr:gt(0)").remove();//删除所有列 

                      //遍历data

                       $(data).find("return").each(function(){

                          var name = $(this).find("name").text();

                          var age  = $(this).find("age").text();

                          var tr = $('<tr><td>'+name+'</td><td>'+age+'</td></tr>');

                          tr.appendTo("#tb");

                       });

                    }

                 });

                //以下是增加

                 $("#add").click(function(){

                    var nm = $("#_name").val();

                    var age = $("#_age").val();

                   if($.trim(nm)=="" || $.trim(age)==""){

                      alert('姓名和年龄必须输入'); 

                    }

                   //以下是保存服务的xml

                    var xml = '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">'

                            +'<soap:Body><ns2:add xmlns:ns2="http://service.stud.cn/">'

                            +'<arg0><age>'+age+'</age><name>'+nm+'</name></arg0></ns2:add>'

                            +'</soap:Body></soap:Envelope>';

                    $.ajax({

                       url:url,

                       type:'post',

                       dataType:'xml',

                       contentType:'application/soap+xml;charset=UTF-8',

                       data:xml,

                       success:function(){

                         alert('保存成功');                   

                       }

                    });

                 });

             });

          });

      </script>

      </html>

 

 

l  如何通过ant发布第一个cxf应用。

l  手工建立一个java项目发布cxf的ws.

l  Java项目和js访问webService

l  加入消息拦截器

l  将服务端改为SOAP1.2实现

l  SOAP1.1与1.2

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值