web service 之 CXF(1)

本文深入探讨了WebService的概念,详细介绍了其组成部分,包括Web服务服务器和客户端的交互流程,以及如何通过标准Web协议如HTTP、XML和SOAP进行调用。文章还概述了Apache CXF框架在构建和开发WebService时的用法,包括如何利用Frontend编程API、支持多种协议和集成Spring。此外,文章解释了WSDL文件的作用,如何描述Web服务的接口和操作,并提供了实际的WSDL示例。最后,文章简要介绍了SOAP协议、JAXB技术以及CXF与Spring的集成方法。
理解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服务器是相同的。
它主要做下面这些事:
 监听网络端口(监听服务端口)
 接收客户端请求(接收SOAP请求)
 解析客户端请求(解析SOAP消息,将SOAP消息转换为数据对象)
 调用业务逻辑 (调用Web Service实现类的特定操作,参数是由SOAP消息转换而来的数据对象)
 生成响应 (将返回值转换为SOAP消息)
 返回响应 (返回SOAP响应)
Web Service客户端
一个Web Service客户端,顾名思义是和一个Web Service服务器进行交互。
下面是一个Web Service客户端调用Web Service的基本过程。
 构造SOAP请求消息
 发送SOAP消息到Web Service服务器的指定端口
 接收SOAP响应消息
 将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服务的定义中使用下列元素:
 Types - 数据类型定义的容器,它使用某种类型系统(一般地使用XML Schema中的类型系统)。
 Message - 通信消息的数据结构的抽象类型化定义。使用Types所定义的类型来定义整个消息的数据结构。
 Operation - 对服务中所支持的操作的抽象描述,一般单个Operation描述了一个访问入口的请求/响应消息对。
 PortType - 对于某个访问入口点类型所支持的操作的抽象集合,这些操作可以由一个或多个服务访问点来支持。
 Binding - 特定端口类型的具体协议和数据格式规范的绑定。
 Port - 定义为协议/数据格式绑定与具体Web访问地址组合的单个服务访问点。
 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>,再对其封装传递
代码转载自:https://pan.quark.cn/s/f87b8041184b Language: 中文 欢迎来到戈戈圈! 当你点开这个存储库的时候,你会看到戈戈圈的图标↓ 本图片均在知识共享 署名-相同方式共享 3.0(CC BY-SA 3.0)许可协议下提供,如有授权遵照授权协议使用。 那么恭喜你,当你看到这个图标的时候,就代表着你已经正式成为了一名戈团子啦! 欢迎你来到这个充满爱与希望的大家庭! 「与大家创造更多快乐,与人们一起改变世界。 」 戈戈圈是一个在中国海南省诞生的创作企划,由王戈wg的妹妹于2018年7月14日正式公开。 戈戈圈的创作类型广泛,囊括插画、小说、音乐等各种作品类型。 戈戈圈的目前成员: Contributors 此外,支持戈戈圈及本企划的成员被称为“戈团子”。 “戈团子”一词最初来源于2015年出生的名叫“团子”的大熊猫,也因为一种由糯米包裹着馅料蒸熟而成的食品也名为“团子”,不仅有团圆之意,也蕴涵着团结友爱的象征意义和大家的美好期盼,因此我们最终于2021年初决定命名戈戈圈的粉丝为“戈团子”。 如果你对戈戈圈有兴趣的话,欢迎加入我们吧(σ≧︎▽︎≦︎)σ! 由于王戈wg此前投稿的相关视频并未详细说明本企划的信息,且相关视频的表述极其模糊,我们特此创建这个存储库,以文字的形式向大家介绍戈戈圈。 戈戈圈自2018年7月14日成立至今,一直以来都秉持着包容开放、和谐友善的原则。 我们深知自己的责任和使命,始终尊重社会道德习俗,严格遵循国家法律法规,为维护社会稳定和公共利益做出了积极的贡献。 因此,我们不允许任何人或组织以“戈戈圈”的名义在网络平台或现实中发布不当言论,同时我们也坚决反对过度宣传戈戈圈的行为,包括但不限于与戈戈圈无关的任何...
内容概要:本文详细介绍了一个基于YOLOv8的血细胞智能检测系统全流程开发指南,涵盖从环境搭建、数据准备、模型训练与验证到UI交互系统开发的完整实践过程。项目利用YOLOv8高精度、高速度的优势,实现对白细胞、红细胞和血小板的自动识别与分类,准确率超过93%,单张图像检测仅需0.3秒。通过公开或自建血细胞数据集,结合LabelImg标注工具和Streamlit开发可视化界面,构建了具备图像上传、实时检测、结果统计与异常提示功能的智能系统,并提供了论文撰写与成果展示建议,强化其在医疗场景中的应用价值。; 适合人群:具备一定Python编程与深度学习基础,从事计算机视觉、医疗AI相关研究或项目开发的高校学生、科研人员及工程技术人员,尤其适合需要完成毕业设计或医疗智能化项目实践的开发者。; 使用场景及目标:①应用于医院或检验机构辅助医生进行血涂片快速筛查,提升检测效率与一致性;②作为深度学习在医疗影像领域落地的教学案例,掌握YOLOv8在实际项目中的训练、优化与部署流程;③用于学术论文写作与项目成果展示,理解技术与临床需求的结合方式。; 阅读建议:建议按照“数据→模型→系统→应用”顺序逐步实践,重点理解数据标注规范、模型参数设置与UI集成逻辑,同时结合临床需求不断优化系统功能,如增加报告导出、多类别细粒度分类等扩展模块。
基于蒙特卡洛,copula函数,fuzzy-kmeans获取6个典型场景进行随机优化多类型电动汽车采用分时电价调度,考虑上级电网出力、峰谷差惩罚费用、风光调度、电动汽车负荷调度费用和网损费用内容概要:本文围绕多类型电动汽车在分时电价机制下的优化调度展开研究,采用蒙特卡洛模拟、Copula函数和模糊K-means聚类方法获取6个典型场景,并在此基础上进行随机优化。模型综合考虑了上级电网出力、峰谷差惩罚费用、风光可再生能源调度、电动汽车负荷调度成本以及电网网损费用等多个关键因素,旨在实现电力系统运行的经济性与稳定性。通过Matlab代码实现相关算法,验证所提方法的有效性与实用性。; 适合人群:具备一定电力系统基础知识和Matlab编程能力的研究生、科研人员及从事新能源、智能电网、电动汽车调度相关工作的工程技术人员。; 使用场景及目标:①用于研究大规模电动汽车接入电网后的负荷调控策略;②支持含风光等可再生能源的综合能源系统优化调度;③为制定合理的分时电价政策及降低电网峰谷差提供技术支撑;④适用于学术研究、论文复现与实际项目仿真验证。; 阅读建议:建议读者结合文中涉及的概率建模、聚类分析与优化算法部分,动手运行并调试Matlab代码,深入理解场景生成与随机优化的实现流程,同时可扩展至更多元化的应用场景如V2G、储能协同调度等。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值