苏铭客

导航

Apache CXF WebService 分布式跨域调用

一.Apache CXF 介绍

      Apache CXF 是一个开放源代码框架,提供了用于方便地构建和开发 Web 服务的可靠基础架构。它允许创建高性能和可扩展的服务,您可以将这样的服务部署在 Tomcat 和基于 Spring 的轻量级容器中,以及部署在更高级的服务器上,例如 Jboss、IBM® WebSphere® 或 BEA WebLogic。

二.Apache CXF 下载

     Apache官网提供下载地址:  http://mirrors.cnnic.cn/apache/cxf/   我这里选择了3.0.11版本

三.接下来我们新建一个web Project项目。项目名叫cxfWebPrj。

     将我们之前下载下的CXF包解压,将lib目录下的jar文件拷贝到项目WEB—INFO/lib目录下。这是该项目所需的jar,这类jar包含了cxf的服务包,jetty服务的支持以及spring的相关jar包。具体的应用我还没分包。

四.首先新建一个接口 和 实现类

package com.zhj.servers;

import javax.jws.WebService;

@WebService
public interface CxfInterface {
    public String sayHello(String name);  
}
View Code
package com.zhj.servers.impl;

import javax.jws.WebService;
import javax.xml.ws.Endpoint;

import com.zhj.servers.CxfInterface;

@WebService(endpointInterface="com.zhj.servers.CxfInterface",serviceName="CxfInterface",targetNamespace="http://servers.zhj.com/")
public class CxfWebServerImpl implements CxfInterface{
    
    
    @Override
    public String sayHello(String name) {
        // TODO Auto-generated method stub
        return "hello " + name;
    }
    
    
    public static void main(String[] args) {
        System.out.println("web service start");
        CxfInterface implementor= new CxfWebServerImpl();
        String address="http://localhost:8081/webPrj1";
        Endpoint.publish(address, implementor);
        System.out.println("web service started");
    }

}
View Code

五.建立一个客户端类,调用服务接口。

package com.zhj.client;

import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import com.zhj.servers.CxfInterface;

public class CxfClientTest {
     public static void main(String[] args) {
         JaxWsProxyFactoryBean svr = new JaxWsProxyFactoryBean();
         svr.setServiceClass(CxfInterface.class);
         svr.setAddress("http://localhost:8081/webPrj1");
         CxfInterface hw = (CxfInterface) svr.create();
         System.out.println(hw.sayHello("zhjtest"));
     }
}
View Code

六.先启动服务端的main方法。在执行客户端的方法。

简单的测试过程,是利用jetty服务发布的webService,比较便捷的是服务地址可自由定制,我自行约定服务地址:http://localhost:8081/webPrj1

相对于的客户端也通过该地址调用接口访问,比Axis2较为方便灵活。

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

下面介绍与spring结合发布服务及调用。

一.WEB-INFO目录下新建spring配置文件:applicationContext.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:p="http://www.springframework.org/schema/p"  
    xmlns:tx="http://www.springframework.org/schema/tx"  
    xmlns:aop="http://www.springframework.org/schema/aop"  
    xmlns:jaxws="http://cxf.apache.org/jaxws"    
    xmlns:jaxrs="http://cxf.apache.org/jaxrs"    
    xsi:schemaLocation="http://www.springframework.org/schema/beans   
                        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
                        http://www.springframework.org/schema/tx  
                        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd  
                        http://www.springframework.org/schema/aop  
                        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd  
                        http://cxf.apache.org/jaxws    
                        http://cxf.apache.org/schemas/jaxws.xsd    
                        http://cxf.apache.org/jaxrs    
                        http://cxf.apache.org/schemas/jaxrs.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" />   --> 
      
    <!--<jaxws:endpoint id="helloWorld" implementor="com.zhj.servers.impl.CxfWebServerImpl"  address="/CxfInterface1" /> 
        id:定义的别名   implementor:实现类的接口路径; (address:是指定发布接口的名称,可以和接口定义的名称不同)
       -->
    <jaxws:endpoint id="helloWorld" implementor="com.zhj.servers.impl.CxfWebServerImpl"  address="/testCxf" />
    <bean id="client" class="com.zhj.servers.CxfInterface"  factory-bean="factorybean" factory-method="create"/>
    <bean id="factorybean" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
        <property name="serviceClass" value="com.zhj.servers.CxfInterface"/>
        <property name="address" value="http://localhost:8080/cxfWebPrj/webservice/testCxf"/>
    </bean>
</beans>

在这段配置里,我需要说明,咱们发布的服务地址是该配置文件暴露的。其中

    1.<jaxws:endpoint id="helloWorld" implementor="com.zhj.servers.impl.CxfWebServerImpl" address="/testCxf" />  其中address的名称,可自行定义。

    2.<property name="address" value="http://localhost:8080/cxfWebPrj/webservice/testCxf"/> 但是最后暴露的服务地址必须指向该定义的地址名称,其中cxfWebPrj为本项目名称,这与jetty发布的服务不同,不能随意改动。

   3.DDT 必须要引入cxf地址

 xmlns:jaxws="http://cxf.apache.org/jaxws"    
 xmlns:jaxrs="http://cxf.apache.org/jaxrs" 

 http://cxf.apache.org/jaxws    
 http://cxf.apache.org/schemas/jaxws.xsd    
 http://cxf.apache.org/jaxrs    
 http://cxf.apache.org/schemas/jaxrs.xsd
spring就不用说了,毫无疑问要加上。

二.配置web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
 
    <display-name>My Web Application</display-name>
 
    <!-- location of spring xml files -->
    <!-- <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:camel-config.xml</param-value>
    </context-param> -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>WEB-INF/applicationContext.xml</param-value>
    </context-param>

    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>
 
    <!-- CXF servlet -->
    <servlet>
        <servlet-name>CXFServlet</servlet-name>
        <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
        <!-- If you want to leverage the Servlet3's async feature in Tomcat, 
         please enable this feature 
        <async-supported>true</async-supported>
        -->
    </servlet>
 
    <!-- all our webservices are mapped under this URI pattern 必须指定成/webservice/*-->
    <servlet-mapping>
        <servlet-name>CXFServlet</servlet-name>
        <url-pattern>/webservice/*</url-pattern>
    </servlet-mapping>
 </web-app>

     web.xml配置主要是指定spring配置的路径,还有配置cxf Servlet映射。

三.新建一个客户端调用:

package com.zhj.client;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.zhj.servers.CxfInterface;

public class CxfSpringClientTest {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("file:WebRoot/WEB-INF/applicationContext.xml");
        CxfInterface client = (CxfInterface)context.getBean("client");
        System.out.println(client.sayHello("zhj"));
    }

}
View Code

     其中 context.getBean("client"); client 是applicationContext.xml 中配置的bean。

四.部署项目,启动服务。然后在客户端运行CxfSpringClientTest类。

    

 

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

 

接下来,我贴近大部分业务需要说下cxf webService分布式跨域调用.

cxf 服务还是使用上面所写的webService 服务实现。

在另一个web项目中,新建一个webServiceClient类,采用动态调用方式 如下:

package com.ywkj.action.webServiceClient;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.namespace.QName;

import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.ywkj.action.BaseAction;

@Controller
public class WebServiceClient extends BaseAction {
    //webService服务地址
    private static final String WSDL_URL = "http://127.0.0.1:8080/cxfWebPrj/webservice/testCxf?wsdl";  
    
   @RequestMapping(value = "web/webServerTest")
    public void callWebServertoCommand(HttpServletRequest request,
            HttpServletResponse response){
         JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance(); 
          Client client = dcf.createClient(WSDL_URL); 
          //指定到接口类所在包 ,sayHello 为接口中定义的方法名称   张三为传递的参数   返回一个Object数组 
          QName opName = new QName("http://servers.zhj.com/","sayHello"); 
          Object[] objects = null;
            try {
                objects = client.invoke(opName, "张三");
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }    
            //输出调用结果 
            System.out.println(objects[0].toString()); 
    }
    
}
View Code

 

编写前端调用方法(此处省略前端调用代码),调用该callWebServertoCommand的Action方法。我这里输出了,调用webService服务返回的字符串

 

 

在客户端调用需要引入两个jar包

 

需要注意的是:QName 类实例化时,第一个参数 namespaceURI 是包反序列的路径,这是Java定义的规范。第二参数,是你要调用的方法名。然后用cxf 自带的client 反射调用webService方法。

至此,简单的cxf服务端发布和客户端调用以及分布式跨域调用已全部实现,如有不合理之处请小伙伴指点出来,thank you!

 

posted on 2016-11-16 14:46  苏铭客  阅读(1218)  评论(0编辑  收藏  举报