web service 之 CXF

理解Web Service
什么是 Web Service
Web Service 是为其它应用提供数据和服务的应用逻辑单元,应用程序通过标准的Web 协议和数据格式获得Web Service,如HTTP 、XML 和SOAP 等,每个Web Service 的实现是完全独立的。
简单地讲,Web 服务是一个URL 资源,客户端可以通过编程方式请求得到它的服务,而不需要知道所请求的服务是怎样实现的。
调用 Web Service
每个Web Service 都有一个描述文件(WSDL )
它描述 一个 Web Service 的如下方面:
   (1)服务的端口(接收SOAP消息的端口)
   (2)服务提供的操作
   (3)操作的输入输出格式的定义(通过XMLSchema定义输入输出格式)
    有了Web Service 的描述文件(WSDL),我们就知道怎样调用这个Web Service 中定义的操作了。
   (1)通过服务提供的操作找到你想调用的操作
   (2)找到这个操作的输入格式的定义(XMLSchema),按照这种输入格式构造一个SOAP消息
   (3)将这个SOAP消息发送到服务的指定端口
   (4)准备接收一个从Web Service服务器返回的 SOAP 响应吧 !
Web Service服务器
一个Web Service服务器,本质上和一个Web服务器是相同的。
它主要做下面这些事:
    (1)监听网络端口(监听服务端口)
    (2)接收客户端请求(接收SOAP请求)
    (3)解析客户端请求(解析SOAP消息,将SOAP消息转换为数据对象)

    (4)调用业务逻辑 (调用Web Service实现类的特定操作,参数是由SOAP消息转换而来的数据对象)
    (5)生成响应 (将返回值转换为SOAP消息)
    (6)返回响应 (返回SOAP响应)
Web Service客户端
一个Web Service客户端,顾名思义是和一个Web Service服务器进行交互。
下面是一个Web Service客户端调用Web Service的基本过程。
    (1)构造SOAP请求消息
    (2)发送SOAP消息到Web Service服务器的指定端口
    (3)接收SOAP响应消息
    (4)将SOAP响应消息转换为本地数据对象
CXF 简介
Apache CXF 是一个开源的 Services 框架,CXF 帮助您利用 Frontend 编程 API 来构建和开发 Services ,像 JAX-WS 。这些 Services 可以支持多种协议,比如:SOAP、XML/HTTP、RESTful HTTP 或者 CORBA ,并且可以在多种传输协议上运行,比如:HTTP、JMS 或者 JBI,CXF 大大简化了 Services 的创建,同时它继承了 XFire 传统,一样可以天然地和 Spring 进行无缝集成。
CXF 包含了大量的功能特性,但是主要集中在以下几个方面:
支持 Web Services 标准:CXF 支持多种 Web Services 标准,包含 SOAP、Basic Profile、WS-Addressing、WS-Policy、WS-ReliableMessaging 和 WS-Security。
Frontends:CXF 支持多种“Frontend”编程模型,CXF 实现了 JAX-WS API (遵循 JAX-WS 2.0 TCK 版本),它也包含一个“simple frontend”允许客户端和 EndPoint 的创建,而不需要 Annotation 注解。CXF 既支持 WSDL 优先开发,也支持从 Java 的代码优先开发模式。
支持二进制和遗留协议:CXF 的设计是一种可插拨的架构,既可以支持 XML ,也可以支持非 XML 的类型绑定,比如:JSON 和 CORBA。
WSDL
    WSDL(Web Service Description Language)Web服务器描述语言是用XML文档来描述Web服务的标准,是Web服务的接口定义语言,由Ariba、Intel、IBM、MS等共同提出,通过WSDL,可描述Web服务的三个基本属性:
•服务做些什么——服务所提供的操作(方法)
•如何访问服务——和服务交互的数据格式以及必要协议
•服务位于何处——协议相关的地址,如URL
WSDL 文档将Web服务定义为服务访问点或端口的集合。在 WSDL 中,由于服务访问点和消息的抽象定义已从具体的服务部署或数据格式绑定中分离出来,因此可以对抽象定义进行再次使用:消息,指对交换数据的抽象描述;而端口类型,指操作的抽象集合。用于特定端口类型的具体协议和数据格式规范构成了可以再次使用的绑定。将Web访问地址与可再次使用的绑定相关联,可以定义一个端口,而端口的集合则定义为服务。因此,WSDL 文档在Web服务的定义中使用下列元素:
(1)Types - 数据类型定义的容器,它使用某种类型系统(一般地使用XML Schema中的类型系统)。
(2) Message - 通信消息的数据结构的抽象类型化定义。使用Types所定义的类型来定义整个消息的数据结构。
(3) Operation - 对服务中所支持的操作的抽象描述,一般单个Operation描述了一个访问入口的请求/响应消息对。
(4)PortType - 对于某个访问入口点类型所支持的操作的抽象集合,这些操作可以由一个或多个服务访问点来支持。
(5) Binding - 特定端口类型的具体协议和数据格式规范的绑定。
(6) Port - 定义为协议/数据格式绑定与具体Web访问地址组合的单个服务访问点。
(7) Service - 相关服务访问点的集合。
一个WSDL文件

<?xml version="1.0" encoding="UTF-8" ?>
- <wsdl:definitions name="CountImplService" targetNamespace="http://impl.server/" xmlns:ns1="http://server/" xmlns:ns2="http://cxf.apache.org/bindings/xformat" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://impl.server/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<wsdl:import location="http://localhost:8080/mycxf/count?wsdl=Count.wsdl" namespace="http://server/" />
-<wsdl:binding name="CountImplServiceSoapBinding" type="ns1:Count">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
- <wsdl:operation name="multiply">
  <soap:operation soapAction="" style="document" />
- <wsdl:input name="multiply">
  <soap:body use="literal" />
  </wsdl:input>
- <wsdl:output name="multiplyResponse">
  <soap:body use="literal" />
  </wsdl:output>
  </wsdl:operation>
- <wsdl:operation name="subtract">
  <soap:operation soapAction="" style="document" />
- <wsdl:input name="subtract">
  <soap:body use="literal" />
  </wsdl:input>
- <wsdl:output name="subtractResponse">
  <soap:body use="literal" />
  </wsdl:output>
  </wsdl:operation>
- <wsdl:operation name="divide">
  <soap:operation soapAction="" style="document" />
- <wsdl:input name="divide">
  <soap:body use="literal" />
  </wsdl:input>
- <wsdl:output name="divideResponse">
  <soap:body use="literal" />
  </wsdl:output>
  </wsdl:operation>
- <wsdl:operation name="add">
  <soap:operation soapAction="" style="document" />
- <wsdl:input name="add">
  <soap:body use="literal" />
  </wsdl:input>
- <wsdl:output name="addResponse">
  <soap:body use="literal" />
  </wsdl:output>
  </wsdl:operation>
  </wsdl:binding>
- <wsdl:service name="CountImplService">
- <wsdl:port binding="tns:CountImplServiceSoapBinding" name="CountImplPort">
  <soap:address location="http://localhost:8080/mycxf/count" />
  </wsdl:port>
  </wsdl:service>
  </wsdl:definitions>
 


SOAP
SOAP(Simple Object Access Protocol )简单对象访问协议是在分散或分布式的环境中交换信息的简单的协议,是一个基于XML的协议,它包括四个部分:SOAP封装(envelop),封装定义了一个描述消息中的内容是什么,是谁发送的,谁应当接受并处理它以及如何处理它们的框架;SOAP编码规则(encoding rules),用于表示应用程序需要使用的数据类型的实例; SOAP RPC表示(RPC representation),表示远程过程调用和应答的协定;SOAP绑定(binding),使用底层协议交换信息。

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:divideResponse xmlns:ns2="http://server/">
<return>7</return>
</ns2:divideResponse></soap:Body></soap:Envelope>
 


JAXB
JAXB(Java Architecture for XML Binding) 是一个业界的标准,是一项可以根据XML Schema产生Java类的技术。该过程中,JAXB也提供了将XML实例文档反向生成Java对象树的方法,并能将Java对象树的内容重新写到 XML实例文档。从另一方面来讲,JAXB提供了快速而简便的方法将XML模式绑定到Java表示,从而使得Java开发者在Java应用程序中能方便地结合XML数据和处理函数。
@XmlRootElement
表示 xml 文件的根元素
@XmlElement    
表示xml 文件中的元素
@XmlAccessorType
说明类内,什么样的成员是可以被xml转化传输的 ,可以是FIELD或 PROPERTY,具体格式如下:            
@XmlAccessorType(XmlAccessType.PROPERTY)或@XmlAccessorType(XmlAccessType. FIELD)
@XmlTransient
@XmlTransient 注释对于解决 JavaBean 属性名称与字段名称之间的名称冲突,或者用于防止字段/属性的映射。当取消首字母大写的 JavaBean 属性名称与字段名称相同时,就可能发生名称冲突。如果 JavaBean 属性引用该字段,那么可以通过防止映射使用 @XmlTransient 注释的字段或 JavaBean 属性来解决名称冲突。
@XmlJavaTypeAdapter(AddressAdapter.class)
表示当被暴露的接口传进来的参数是一个接口时,需要用它来指定其具体实现。
CXF与Spring
CXF可以天然地和 Spring 进行无缝集成,其配置如下:
Spring服务器端配置文件

<!--必须要加  在cxf-2.2.7.jar里的META-INF-cxf-osgi文件夹下可以找到-->
<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" />

<!-- intercepttor -->
<bean id ="LongingInInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean>
<bean id ="LongingOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean>
<!--
注意:<jaxws:server id="surveyService" implementor="ws.cxf.impl.SurveyService"
address="/SurveyWebService" />

    id:指在spring配置的bean的ID.

Implementor:指明具体的实现类.

Address:指明这个web service的相对地址,
-->
<jaxws:endpoint id="count" implementor="server.impl.CountImpl" address="/count">
<jaxws:inInterceptors>
<ref bean ="LongingInInterceptor"/>
</jaxws:inInterceptors>
<jaxws:outInterceptors>
<ref bean ="LongingOutInterceptor"/>
</jaxws:outInterceptors>

</jaxws:endpoint> -
 




客户端bean.xml
<!-- 定义一个工厂  -->

<bean id="counter" class="server.Count" factory-bean="clientFactory"
factory-method="create" />
<!-- 创建实例  -->
<bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
<property name="serviceClass" value="server.Count" />
<property name="address" value="http://localhost:8080/mycxf/count" />
</bean>
 



Web.xml

<!-- Spring 配置文件路径 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/serverBean.xml</param-value>
</context-param>
<!-- Spring ContextLoaderListener -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Apache CXFServlet -->
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
</servlet>
<!-- CXFServlet Mapping -->
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
 



一个CXF实例
实例使用CXF 2.2.7,实现远程调用加减乘除及基本的拦截器
Count.java

package server;

import javax.jws.WebService;

@WebService
public interface Count {

/**
* 进行加减乘除
* @param a
* @param b
* @return
*/
public int add(int a,int b);

public int subtract(int a,int b);

public int multiply(int a,int b);

public int divide(int a,int b);
}
CountImpl.java
 
package server.impl;

import javax.jws.WebService;

import server.Count;
@WebService(endpointInterface = "server.Count")
public class CountImpl implements Count {

public int add(int a, int b) {
return a+b;
}

public int divide(int a, int b) {
return a-b;
}

public int multiply(int a, int b) {
return a*b;
}

public int subtract(int a, int b) {
return a/b;
}

}}
 


ServerBean.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:jaxrs="http://cxf.apache.org/jaxrs"
xmlns:util="http://www.springframework.org/schema/util" xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxrs
http://cxf.apache.org/schemas/jaxrs.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.0.xsd"
default-lazy-init="false">

<!--必须要加  在cxf-2.2.7.jar里的META-INF-cxf-osgi文件夹下可以找到-->
<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" />

<!-- intercepttor -->
<bean id ="LongingInInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean>
<bean id ="LongingOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean>
<!--
注意:<jaxws:server id="surveyService" implementor="ws.cxf.impl.SurveyService"
address="/SurveyWebService" />

    id:指在spring配置的bean的ID.

Implementor:指明具体的实现类.

Address:指明这个web service的相对地址,
-->
<jaxws:endpoint id="count" implementor="server.impl.CountImpl" address="/count">
<jaxws:inInterceptors>
<ref bean ="LongingInInterceptor"/>
</jaxws:inInterceptors>
<jaxws:outInterceptors>
<ref bean ="LongingOutInterceptor"/>
</jaxws:outInterceptors>

</jaxws:endpoint>
</beans>
}}
 

Web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 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_2_5.xsd">
<!-- Spring 配置文件路径 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/serverBean.xml</param-value>
</context-param>
<!-- Spring ContextLoaderListener -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Apache CXFServlet -->
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
</servlet>
<!-- CXFServlet Mapping -->
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>

</web-app>
}}

 


ClientMain.java

package client;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import server.Count;

public class ClientMain {

public static void main(String[] args){

ClassPathXmlApplicationContext con = new ClassPathXmlApplicationContext("client/clientbeans.xml");
System.out.println("-------加载属性文件成功-------");
Count coun =(Count)con.getBean("counter");
System.out.println(coun.add(1, 1));
int a = coun.divide(8,1);
System.out.println(a);
}
}
 


ClientBean.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schema/jaxws.xsd">

<!-- 定义一个工厂  -->
<bean id="counter" class="server.Count" factory-bean="clientFactory"
factory-method="create" />
<!-- 创建实例  -->
<bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
<property name="serviceClass" value="server.Count" />
<property name="address" value="http://localhost:8080/mycxf/count" />
</bean>

</beans>
 


要注意的问题
服务端不能返回接口,如果要返回类型是接口必须用注释 @XmlJavaTypeAdapter(AddressAdapter.class) 来指定其具体实现类

遇到的问题
Hashtable<String,String>传递:
当CXF返回一个Map<String,String>类型的值时,客户端不能接收到里面相应的值
解决方法1:
用Bean对象将其封装
不能传递Hashtable<String, Hashtable <String,String>>.
解决办法1:
将其拆分为两个Hashtable<String,String>,再对其封装传递

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值