zoukankan      html  css  js  c++  java
  • WebService—CXF整合Spring实现接口发布和调用过程

    一、CXF整合Spring实现接口发布

    发布过程如下:

    1、引入jar包(基于maven管理)

    复制代码
    <!-- cxf -->
    <dependency>  
        <groupId>org.apache.cxf</groupId>  
        <artifactId>cxf-rt-frontend-jaxws</artifactId>  
        <version>2.7.18</version>  
    </dependency> 
    <dependency>       
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-transports-http</artifactId>
    <version>2.7.18</version>
    </dependency>
    复制代码

    会将cxf需要的jar都引入进来,最好是将全部jar都引入。

    2、 创建接口(用于向客户端暴露服务)

    创建接口

    复制代码
    package com.elgin.cxf.service;  
    import javax.jws.WebParam;  
    import javax.jws.WebService;  
    import com.elgin.cxf.entities.User; 
    @WebService public interface HelloService { public String sayHello(@WebParam(name="text")String text); public User getUserByName(String name); }
    复制代码

    接口实现类:

    复制代码
        package com.elgin.cxf.service.impl;  
        import javax.jws.WebService;    import com.elgin.cxf.entities.User;  
        import com.elgin.cxf.service.HelloService;    @WebService(endpointInterface="com.elgin.cxf.service.HelloService")  
        public class HelloServiceImpl implements HelloService {  
            @Override  
            public String sayHello(String text ) {  
                return "hello " + text;  
            }  
            @Override  
            public User getUserByName(String name) {  
                User user=new User(name);  
                return user;  
            }     
    }
    复制代码

    POJO类:

    复制代码
        package com.elgin.cxf.entities;    
    public class User { private String name; public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public User(){}
    public User(String name) { super(); this.name = name; }
    @Override public String toString() { return "User [name=" + name + "]"; }
    }
    复制代码

     

    3、 在工程的web.xml文件中增加支持spring与CXF的配置 

    复制代码
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
    <display-name>CXFWebDemo</display-name>
    <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
    </welcome-file-list>

    <!-- 加入CXF支持 -->
    <servlet>
    <description>Apache CXF Endpoint</description>
    <display-name>cxf</display-name>
    <servlet-name>cxf</servlet-name>
    <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
    <servlet-name>cxf</servlet-name>
    <url-pattern>/services/*</url-pattern>
    </servlet-mapping>

    <!-- 加入spring -->
    <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext*.xml</param-value>
    </context-param>

    <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    </web-app>
    复制代码

      

    4、 增加CXF的配置文件来发布WebService接口

    4.1、直接新建CXF的xml配置文件的方式

    新建包CXFConfig 用来保存CXF相关的配置文件, 并在此包下新建xml配置文件 CXFServices.xml 。具体配置内容如下:

     

    复制代码
        <?xml version="1.0" encoding="UTF-8"?>  
        <beans xmlns="http://www.springframework.org/schema/beans"  
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
            xmlns:jaxws="http://cxf.apache.org/jaxws"  
            xmlns:soap="http://cxf.apache.org/bindings/soap"  
            xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
                http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd  
                http://cxf.apache.org/bindings/soap http://cxf.apache.org/schemas/configuration/soap.xsd">  
            
           <!--   
                1.使用jaxws:endpoint标签的配置发布一个 webservice   
                2.服务提供实现类为 com.elgin.cxf.service.impl.HelloServiceImpl,用implementor属性配置  
                3.address属性配置外部访问的相对路径  
                4.使用  jaxws:inInterceptors 标签配置2个日志拦截器,用来打印调用时的日志信息  
                5.注意:在此配置文件中,需加入jaxws与soap命名空间  
           -->  
           <jaxws:endpoint id="helloService"   
                           implementor="com.elgin.cxf.service.impl.HelloServiceImpl"   
                           address="/hello" >   
                <jaxws:inInterceptors >  
                   <bean id="inMessageInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor"/>    
                   <bean id="outLoggingInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor"/>    
                </jaxws:inInterceptors>  
           </jaxws:endpoint>           
        </beans>
    复制代码

    将cxf的xml文件引入Spring的xml文件中:

    复制代码
        <?xml version="1.0" encoding="UTF-8"?>  
        <beans xmlns="http://www.springframework.org/schema/beans"  
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
            xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">  
             
           <!-- 用import标签引入cxf的xml配置文件-->  
           <import resource="/CXFConfig/CXFServices.xml"/>  
             
           <!-- 项目中其它bean配置 -->  
           <!--  ....    -->  
        </beans> 
    复制代码

    4.2、将CXF配置文件引入Spring的配置文件中

    (1) cxf.xml,cxf-extension-soap.xml,cxf-servlet.xml三个文件都在cxf-2.0.7.jar中把它们拷贝到META-INF/目录下。将cxf的配置文件拷贝出来,定制修改,再引入Spring的xml中。在2.4版本进行了修改,2.4版本以后,只需要引入classpath:META-INF/cxf/cxf.xml.即可。

    (2)<beans>元素里面的命名空间一定要正确,特别要增加xmlns:jaxws="http://cxf.apache.org/jaxws",http://cxf.apache.org/jaxws,http://cxf.apache.org/schemas/jaxws.xsd。 

    复制代码
        <?xml version="1.0" encoding="UTF-8"?>  
        <beans xmlns="http://www.springframework.org/schema/beans"  
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
            xmlns:p="http://www.springframework.org/schema/p"  
            xmlns:jaxws="http://cxf.apache.org/jaxws"  
            xmlns:cxf="http://cxf.apache.org/core"  
            xsi:schemaLocation="http://www.springframework.org/schema/beans   
            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd   
            http://cxf.apache.org/jaxws   
            http://cxf.apache.org/schemas/jaxws.xsd">  
              
            <import resource="classpath:META-INF/cxf/cxf.xml" />  
            <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />  
            <import resource="classpath:META-INF/cxf/cxf-servlet.xml" /><bean id="hello" class="cn.com.service.HelloWorldImpl"/><jaxws:endpoint id="helloWorld" implementor="#hello" address="/hello" />
    复制代码

    至此,CXF的相关配置完成,将项目加载到Tomcat ,并启动 ,访问 如下URL:http://localhost:8080/CXFWebDemo/services/hello?wsdl ,出现xml数据,说明发布成功。

    二、CXF整合Spring实现接口调用

    调用过程如下:

    1、使用wsdl2Java工具手动生成本地服务端接口代码调用

    A : 引入cxf的jar包(用maven管理jar包),生成本地代码。生成java代码后可以直接复制到客户端中再客户端中使用,也可打成jar包(建议)。 

    用wsdl2Java工具手动生成服务端接口代码,(首先配置cxf的环境变量,配置CXF_HOME 值为E:gavincxfapache-cxf-3.0.0,在PATH中加入%CXF_HOME%in(也可以直接进到bin目录下再使用命令)。方法如下: 

    D:personalapache-cxf-3.2.0in> 

    wsdl2java -d D:/ http://169.254.123.204:8080/CXFSpring/HelloWorld?wsdl 

    -d D:/ 表示生成的文件放在D盘下。空格之后跟上wsdl的url。(服务器必须开启,url才能连接上) 

    wsdl2java -p com -d src -all  wsdl  命令说明:

    -p  指定其wsdl的命名空间,也就是要生成代码的包名

    -d  指定要产生代码所在目录 

    -client 生成客户端测试web service的代码 

    -server 生成服务器启动web  service的代码 

    -impl 生成web service的实现代码 

    -ant  生成build.xml文件 

    -all 生成所有开始端点代码:types,service proxy,,service interface, server mainline, client mainline, implementation object, and an Ant build.xml file.

    补充:

    1::可以用eclipse自带的方式生成客户端代码

    2::可以通过soapUI等接口调试工具生成客户端代码(需要cxf的jar包,并配置cxf的环境变量)

    B : 在Spring的xml配置文件中管理客户端调用接口的Bean组件.

    复制代码
        <?xml version="1.0" encoding="UTF-8"?>  
        <xmlns="http://www.springframework.org/schema/beans"  
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
            xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">  
             
           <!-- 客户端调用配置 -->           
           <!-- service bean配置 -->  
           <bean id="helloService" class="com.elgin.cxf.service.HelloService"  
                                   factory-bean="clientFactory" factory-method="create"/>  
             
           <!-- client 工厂 ,用来产生service实例 -->  
           <bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean" >  
              <property name="serviceClass" value="com.elgin.cxf.service.HelloService"/>  
              <property name="address" value="http://localhost:8080/CXFWebDemo/services/hello"></property> 
           </bean>

    <!--另外一种jaxws:client方式 -->
      <!-- <jaxws:client id="clientFactory"
    serviceClass="com.elgin.cxf.service.HelloService"
    address="http://localhost:8080/CXFWebDemo/services/hello" />-->
        </beans> 
    
    
    复制代码

    说明:

    1:上述的配置文件中,指定了一个bean工厂:org.apache.cxf.jaxws.JaxWsProxyFactoryBean ,该工厂可以通过 serviceClass中的 值来产生对应的服务端接口 service bean

    2:同时 address 属性,指定了webservice服务的调用地址 。注意:<property name="address" value="http://localhost:8080/webws/HelloWorld" />中的/HelloWorld要与服务器端applicationContext.xml中的

          <jaxws:endpoint id="helloWorld" implementor="#hello" address="/HelloWorld" />的address属性对应。

    3:同时我们注意到,有一个类:com.elgin.cxf.service.HelloService ,其实这个类就是服务端的Helloservice接口。在客户端生成的代码中。

      

    C:在controller层调用

    复制代码
    @Controller
    @RequestMapping("webServiceTest")
    public class WebServiceTestController {
    
        @Autowired
        private HelloService helloService;
        
        @RequestMapping("test")
        public @ResponseBody String test(){        
            return  helloService.sayHello("xiaochangwei"); 
    }
    }
    复制代码

      

    2、用JaxWsDynamicClientFactory创建动态的客户端

    这种方法调用的优点就是不需要使用wsdl2java来生成服务端的代码。

    新建测试类:

    复制代码
        public class ClientDynamic {  
              
            public static void main(String[] args) {  
             method2();  
            }  
          
            public static void method2() {  
                //创建 JaxWsDynamicClientFactory 工厂实例  
                    JaxWsDynamicClientFactory factory=JaxWsDynamicClientFactory.newInstance();  
                //根据服务地址创建客户端  
                    Client client=factory.createClient("http://localhost:8080/CXFWebDemo/services/hello?wsdl");  
                Object [] result;  
                try {  
                    result=client.invoke("sayHello", "World");  
                    System.out.println(result[0]);  
                    result=client.invoke("getUserByName", "Jack");  
                    User user=(User) result[0];  
                    System.out.println(user);  
                } catch (Exception e) {  
                    e.printStackTrace();  
                }  
            }
    }
    复制代码

    动态调用常见的问题 1:

    错误产生的原因:

    JaxWsDynamicClientFactory是一个动态代理类,,执行到这里的时候需要编译生成java类,但是JRE是指可以运行class文件,并没有编译的能力,所以需要修改eclipse中的编译环境。产生的原因是没有获得编译环境,也就是JRE设置的问题,需要在eclipse里面把jre设置为jdk下的jre。打开Java的安装路径,发现会有2个jre目录 ,比我我自己的2个目录分别是:

    C:Program FilesJavajre7

    C:Program FilesJavajdk1.7.0_17jre

    现在需要把jre 为jdk下的jre目录 ,也就是上面的第二个。

    动态调用常见的问题 2:

    对于这条错误 ,根据报错信息来看 :在 http://impl.service.cxf.elgin.com/ 命名空间下没有 sayHello 这个操作。因为CXF发布用的是业务类(HelloServiceImpl.java),那么默认的命名空间就会是业务类所在包(路径),而对外界暴露的则是接口类(HelloService.java),那么对于客户端(第三方)调用访问时,需要按照接口类所在包(路径)进行命名空间的定义。在上述错误的情况下,我们有2种方式来处理 ,一种是在客户端调用时 ,指定接口的命名空间,另一种是在服务端发布WebService服务的时候,明确的指定命名空间,这样就不存在不统一的问题了。

    解决方法1:(客户端调用代码)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public static void method1(){ 
                //创建 JaxWsDynamicClientFactory 工厂实例 
                JaxWsDynamicClientFactory factory=JaxWsDynamicClientFactory.newInstance(); 
                //创建客户端 
                Client client=factory.createClient("http://localhost:8080/CXFWebDemo/services/hello?wsdl"); 
                Object [] result; 
                QName qname; 
                try 
                    //根据指定的命名空间(接口类包名)、方法名新建QName对象 
                    qname=new QName("http://service.cxf.elgin.com/""sayHello"); 
                    result=client.invoke(qname, "World"); 
                    System.out.println(result[0]); 
                    qname=new QName("http://service.cxf.elgin.com/""getUserByName"); 
                    result=client.invoke(qname, "Jack"); 
                    User user=(User) result[0]; 
                    System.out.println(user); 
                catch (Exception e) { 
                    e.printStackTrace(); 
                
        }

      

    解决方法2:(在服务端指定命名空间,修改服务端的HelloServiceImpl 类):

    复制代码
        ckage com.elgin.cxf.service.impl;  
          
        import javax.jws.WebService;  
        import com.elgin.cxf.entities.User;  
        import com.elgin.cxf.service.HelloService;  
          
        @WebService(endpointInterface="com.elgin.cxf.service.HelloService",  
                    targetNamespace="http://service.cxf.elgin.com/")  
        public class HelloServiceImpl implements HelloService {  
          
            @Override  
            public String sayHello(String text ) {  
                return "hello " + text;  
            }  
          
            @Override  
            public User getUserByName(String name) {  
                User user=new User(name);  
                return user;  
            }  
        }
    复制代码

    重新启动Tomcat,查看链接内容:http://localhost:8080/CXFWebDemo/services/hello?wsdl ,发现命名空间已变为我们指定的名字:

    至此,客户端调用完毕!

    from: http://www.cnblogs.com/domi22/p/8094517.html

  • 相关阅读:
    数据库表结构变动发邮件脚本
    .net程序打包部署
    无法登陆GitHub解决方法
    netbeans 打包生成 jar
    第一次值班
    RHEL6 纯命令行文本界面下安装桌面
    C语言中格式化输出,四舍五入类型问题
    I'm up to my ears
    How to boot ubuntu in text mode instead of graphical(X) mode
    the IP routing table under linux@school
  • 原文地址:https://www.cnblogs.com/GarfieldEr007/p/10140873.html
Copyright © 2011-2022 走看看