CXF WebService 教程
业务需求:常见WEB服务:
- 手机淘宝、京东….
- 天气预报
- 手机号归属地
- 股票查询
- 发手机短消息
- 手机充值功能
- 中英文翻译
- 银行转账业务
- 公司的“进销存系统”在某商品缺货时自动给供应商下订单
- .....
需求总结:目前软件应用中会出现大量的需求:同一个应用会有不同的客户端访问,或者不同的应用之间也会相互调用服务(A程序和B程序可能不是同一个语言开发的应用)
基于Socket创建Web服务
为什么要使用Socket呢,我们来看下图
Socket原理图回顾:
编写SocketService,完成字母小写转大写功能
ServerSocket服务器端代码如下:
public static void main(String[] args) throws IOException { // 1:建立服务器端的tcp socket服务,必须监听一个端口 ServerSocket ss = new ServerSocket(9999); // 2: 通过服务器端的socket对象的accept方法获取连接上的客户端对象 Socket s = null; // 3:获取客户端的数据 while (true) { // 接受Socket服务,如果有,没有则堵塞,等待 s = ss.accept(); System.out.println("accept success......."); // 从Socekt输入流中获取客户端发送过来的输出流 InputStream in = s.getInputStream(); byte[] buf = new byte[1024]; int len = in.read(buf); String str = new String(buf, 0, len); System.out.println("从客户端传送来的数据如下:"); System.out.println(str); // 通过服务器端Socket输出流,写数据,会传送到客户端Socket输入流中 OutputStream out = s.getOutputStream(); // 把字母转化为大写 out.write(str.toUpperCase().getBytes()); s.close(); } } |
通过Java客户端访问SocketService服务
public static void main(String[] args) throws Exception { Scanner input=new Scanner(System.in); // 1: 创建一个基于TCP协议的socket服务,在建立对象时,要指定连接服务器和端口号 Socket s=new Socket("127.0.0.1",9999); // 2: 通过建立的Socket对象获取Socket中的输出流,的调用getOutStream方法 OutputStream out=s.getOutputStream(); System.out.println("请输入要转化的字母,或者单词!"); // 3: 写入到Socket输出流中 String word=input.next(); out.write(word.getBytes()); // 4: 通过建立的Socket对象获取Socket中的输入流,输入流会接受来自服务器端数据 InputStream in=s.getInputStream(); byte[] buf=new byte[1024]; // 5: 获取输入字节流的数据,注意此方法是堵塞的,如果没有获取数据会一直等待 int len=in.read(buf); String str=new String(buf,0,len); System.out.println("服务返回来的结果如下:"); System.out.println(str); // 关闭Socket s.close(); } } |
注意先启动服务器端在启动客户端:否则会出现连接异常
服务器端显示结果如下:
accept success....... 从客户端传送来的数据如下: hello |
客户端端显示结果如下:
请输入要转化的字母,或者单词! hello 服务返回来的结果如下: HELLO |
通过C#客户端来访问Java的Socket服务
采用C#访问普通的Socket服务
但是我们现在的很多项目都是web项目,也就是通过浏览器来交互的,我们来看下通过IE的方式访问socketService服务的情况
通过IE来访问SocketService
accept success....... 从客户端传送来的数据如下: POST / HTTP/1.1 Accept: image/jpeg, application/x-ms-application, image/gif, application/xaml+xml, image/pjpeg, application/x-ms-xbap, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */* Accept-Language: zh-CN User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0) Content-Type: application/x-www-form-urlencoded Accept-Encoding: gzip, deflate Host: 127.0.0.1:9999 Content-Length: 10 Connection: Keep-Alive Cache-Control: no-cache word=hello |
返回给IE客户端结果如下:
POST / HTTP/1.1 ACCEPT: IMAGE/JPEG, APPLICATION/X-MS-APPLICATION, IMAGE/GIF, APPLICATION/XAML+XML, IMAGE/PJPEG, APPLICATION/X-MS-XBAP, APPLICATION/VND.MS-EXCEL, APPLICATION/VND.MS-POWERPOINT, APPLICATION/MSWORD, */* ACCEPT-LANGUAGE: ZH-CN USER-AGENT: MOZILLA/4.0 (COMPATIBLE; MSIE 8.0; WINDOWS NT 6.1; TRIDENT/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; MEDIA CENTER PC 6.0) CONTENT-TYPE: APPLICATION/X-WWW-FORM-URLENCODED ACCEPT-ENCODING: GZIP, DEFLATE HOST: 127.0.0.1:9999 CONTENT-LENGTH: 8 CONNECTION: KEEP-ALIVE CACHE-CONTROL: NO-CACHE WORD=AAA |
HTTP协议格式简单回顾:
Http请求由三部分组成,分别是:请求行、消息报头、请求正文
请求行:
以一个方法符号开头,以空格分开,后面跟着请求的URI和协议的版本,格式如下:Method Request-URI HTTP-Version
消息报头:
Accept: Accept请求报头域用于指定客户端接受哪些类型的信息
Host:(发送请求时,该报头域是必需的)请求报头域主要用于指定被请求资源的Internet主机和端口号,它通常从HTTP URL中提取出来的 默认80则省略
Content-Type报头域中所引用的媒体类型,必须采用相应的解码机制
Content-Type:text/html;charset=UTF-8
HTTP响应也是由三个部分组成,分别是:状态行、消息报头、响应正文
HTTP-Version Status-Code Reason-Phrase
其中,HTTP-Version表示服务器HTTP协议的版本;Status-Code表示服务器发回的响应状态代码;Reason-Phrase表示状态代码的文本描述。
HTTP/1.1
200 OK
问题思考
目前我们用Java语言创建一个Socket服务器端, 然用 Java Socket访问没有任何问题. 用C# Socket客户端访问也没有任何问题(说明不同过的语言编写的程序可以通过Socket通信) 用IE访问Socket服务端同样也没问题,IE本身是用VC++语言开发的
但是, 如果我们的服务复杂一点呢. 例如 我过去的单词 操作1:小写转大写,2:大写转小写 3:英文转中文…… 而且我们发现IE在发送请求的时候不但传输的数据还传输了协议. 而且目前我们的很多应用都是基于Web开发的. 如果我们处理Web的请求. 那么还需要从发送过来的协议中获取数据.所以最好的解决办法就是规定格式, 客户端统一格式发送,只要格式统一,服务器端就从指定的格式中获取数据就OK了
“Socket+规范格式”创建Web服务
服务器端代码修改后如下:
public static void main(String[] args) throws Exception { // 1:建立服务器端的tcp socket服务,必须监听一个端口 ServerSocket Socket while (true) { // 接受Socket服务,如果有,没有则堵塞,等待 socket // 从Socekt输入流中获取客户端发送过来的输出流 InputStream byte[] bytes = new byte[1024]; int size = String System.out.println("字节数为:" + size + "内容为:" + word); /*--根据不同的类型选择不同的服务,格式是由服务器端制定 type=int,word=string--*/ String[] // 获取服务的类型 int type=Integer.parseInt(content[0].split("=")[1]); // 获取处理服务的数据 String String OutputStream System.out.println("返回的结果如下:" + result); out.write(result.getBytes()); socket.close(); } } // type=1 小写转大写 type=2大写转小写 public static String wordService(String val,int type){ return } |
C#客户端访问SocektFormatService服务端代码如下:
实现小写转大写功能
实现大写转小写功能:
Socket客户端访问SocektFormatService服务端代码如下:
public static void main(String[] // 1: 创建一个基于TCP协议的socket服务,在建立对象时,要指定连接服务器和端口号 Socket s=new // 2: 通过建立的Socket对象获取Socket中的输出流,的调用getOutStream方法 OutputStream // out.write("type=2,word=HELLO".getBytes()); out.write("type=1,word=hello".getBytes()); // 4: 通过建立的Socket对象获取Socket中的输入流,输入流会接受来自服务器端数据 InputStream byte[] // 5: 获取输入字节流的数据,注意此方法是堵塞的,如果没有获取数据会一直等待 int String str=new System.out.println("服务返回来的结果如下:"); System.out.println(str); // 关闭Socket s.close(); } |
IE调用SocektFormatService服务:
如果要让IE调用则 Socket服务端首先要从传输过来的HTTP协议中获取传输过来的信息(去除请求行、消息报头)然后在进行服务的处理.因为Socket是基于TCP协议的 而IE是基于HTTP协议的,不同协议格式不一样. 所以处理起来比较麻烦,此处省略
解决方案一的缺点:
- Socket服务不利于推广(如果让别人知道你的Socket服务)
- Socket处于传输层, 有可能无法穿越防火墙
- Socket本身处于传输层,要处理应用层的服务要解析HTTP协议比较麻烦,但是现在我们的应用都是基于web的, web中的数据传输就需要HTTP协议
- 即使定义了格式.
后面如果格式改变则客户端格式都需要同步变化维护困难
WebService相关介绍
WebService概念介绍:
Web Service是一项新技术, 能使得运行在不同机器上的不同应用无须借助附加的、专门的第三方软件或硬件,
就可相互交换数据或集成。依据Web Service规范实施的应用之间, 无论它们所使用的语言、 平台或内部协议是什么, 都可以相互交换数据
通俗的讲,Web Service就是一个部署在Web服务器上的一个应用程序,它向外界暴露出一个能够通过Web进行调用的API。这就是说,你能够用编程的方法通过Web来调用这个应用程序。我们把调用这个Web Service 的应用程序叫做客户端,发布这个web服务的机器称为Web Service服务器
WebService的优势介绍:
a)
异构平台的互通性
理论上, Web Service 最大的优势是提供了异构平台的无缝街接技术手段。由于不同的用户使用不同的硬件平台,不同的操作平台,不同的操作系统,不同的软件,不同的协议通信,这就产生了互相通信的需求。 Web Service 使任何两个应用程序,只要能读写XML,那么就能互相通信。
b) 更广泛的软件复用[F1]
软件的复用技术通过组合已有模块来搭建应用程序,能大幅度提高软件的生产效率和质量。用户只要获得了描述 Web Service 的 WSDL 文件,就可以方便地生成客户端代理,并通过代理访问 Web Service 。
c) 成本低、可读性强、应用范围广
Web Service 可用基于
XML 的 SOAP 来表示数据和调用请求。并且通过 HTTP
协议传输 XML 格式的数据
d) 迅捷的软件发行方式[F2]
Web Service 将彻底地改变软件的发行方式。软件供应商可以把软件分解成若Web Service 模块构成的系统,直接在 Web 上发布软件
普通web项目架构原理分析
商业项目的应用趋势
调用已发布的WebService
WebService服务演示
b)
单击手机查询服务
c)
选择要调用的方法 例如: getMobileCodeInfo
d)
输入要查询的手机号单击”调用” 截图如下, 免费用户 UserID为null
e)
可以看到返回如下结果:
<?xml version="1.0" <string xmlns="http://WebXml.com.cn/">18323455678:重庆 重庆 重庆移动全球通卡</string> |
HttpClient工具使用
HttpClient 是 Apache Jakarta Common 下的子项目,可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。
为什么要使用HttpClient工具:
原生态的Socket基于传输层,现在我们要访问的WebService是基于HTTP的属于应用层,所以我们的Socket通信要借助HttpClient发HTTP请求,这样格式才能匹配
HttpClient使用步骤如下:
- 创建
HttpClient 的实例 - 创建某种连接方法的实例,在这里是 GetMethod。在 GetMethod 的构造函数中传入待连接的地址
- 配置要传输的参数,和消息头信息
- 调用第一步中创建好的实例的 execute 方法来执行第二步中创建好的 method 实例
- 通过response读取字符串
- 释放连接。无论执行方法是否成功,都必须释放连接
Socket + HttpClient 访问WS
Get方式:
public static void getMethod() throws Exception { // 创建get对象,类似get请求 GetMethod // 发送get请求 int code = http.executeMethod(getMethod); System.out.println("返回的消息码为:" + code); System.out.println("返回的消息为:" + getMethod.getResponseBodyAsString()); getMethod.releaseConnection(); } |
POST方式:
public static void postMethod() throws Exception { // 创建post请求,类似Post请求 PostMethod // 设置请求的正文内容 postMethod.setRequestBody("mobileCode=18373551982&userID="); // 设置传送信息的格式 postMethod.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); // 发送post请求 int code = http.executeMethod(postMethod); System.out.println("返回消息码为:" + code); System.out.println("返回的消息为:" + postMethod.getResponseBodyAsString()); postMethod.releaseConnection(); } |
SOAP1.1方式:
public static void postSoap1() throws Exception { // 创建一个post请求,类似Post请求 PostMethod // 设置传送信息的格式 postMethod.setRequestHeader("Content-Type","text/xml; charset=utf-8"); postMethod.setRequestBody(new FileInputStream("C:/a.txt")); int code = http.executeMethod(postMethod); System.out.println("消息码为:" + code); System.out.println("返回的消息为:" + postMethod.getResponseBodyAsString()); postMethod.releaseConnection(); } |
Java方式访问WebService
- 选中要调用的服务单击”服务说明”
a)
例如选中:
b)
http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx?WSDL
- 获取wsdl文件.使用JDK1.6以上的版本的wsimport命令
- 切换到c:\ws文件夹 在dos输入:wsimport wsdl目标地址
a)
C:\ws>wsimport http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx?WSDL
- 可以把class文件打成jar包 jar cvf
test.jar 打包目录 - 拷贝的项目中调参考WSDL用即可调用源码如下:
public static void main(String[] MobileCodeWS MobileCodeWSSoap String System.out.println(tel); } |
WSDL协议简单介绍
WSDL –
WebService Description Language – Web服务描述语言
通过XML形式说明服务在什么地方-地址。
通过XML形式说明服务提供什么样的方法
– 如何调用。
<wsdl:service <wsdl:documentation - <soap:address </wsdl:port> |
<wsdl:binding |
JDK6的WebService发布
注意MyEclipse8.5自带的JDK版本太低, 如果要发布自己的WebService则要升级到jdk1.6.0_22及以后版本
创建第一个Web服务:
WebService服务类代码如下:
@WebService // 添加了此注解,代表是一个WebService public class // 非 static final private 方法默认会发布 public String return } } |
发布web服务:
public static String // 注册并且发布一个服务,arg0: 服务地址 , arg1:要发布的服务对象 Endpoint endPoint=Endpoint.publish(address,new // 可以停止服务,或者手动停止 //endPoint.stop(); } |
获取发布web服务的信息
访问wsdl网址为: http://127.0.0.1:9999/helloworld?wsdl 通过wsimport生成Java代码: Wsimport wsimport Wsimport http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx?WSDL jar |
调用第一个WebService服务
public static HelloWorldService HelloWorld System.out.println(helloWorld.sayHi("china")); } |
代码注意事项:
- 在类上添加@WebService注解,代表发布一个WebService服务
- 通过EndPoint(端点服务)发布一个webService。Endpoint也是jdk提供的一个专门用于发布服务的类,它的publish方法接收两个参数,一个是本地的服务地址,二是提供服务的类。它位于javax.xml.ws.*包中。
- Endpoint.publish(String address,
Object implementor) 静态方法在给定地址处针对指定的实现者对象创建并发布端点 - 给类添加上@WebService注解后,类中所有的非静态方法都将会对外公布
- 如果希望某个方法不对外公开,可以在方法上添加@WebMethod(exclude=true),阻止对外公开。
- 如果一个类上,被添加了@WebService注解,则必须此类至少有一个可以公开的方法,否则将会启动失败。
- protected、private、final、static方法不能对外公开 代码如下:
@WebService // 添加了此注解,代表是一个WebService public class // 非 static final private 方法默认会发布 public String return } @WebMethod(exclude=true) public void // 被注解排除的方法 } protected void //受保护的方法默认不发布 } private void private1(){ // 私有方法默认不发布 } public static void // static 方法默认不发布 } public final void // final 方法默认不发布 } } |
WSDL语法分析
前面获取web的发布信息是通过wsimport 来解析wsdl文件得到Java类来实现的. 如论是获取发布的服务,还是调用发布的服务.都需要参考wsdl文件.接下面我们就来分析wsdl文件的结构
分析服务类相关信息
// HelloWorldService <service // 可以通过getHelloWroldPort()获取基于soap1.1的服务,此服务接受的类型取决, // HelloWorldServiceSoapBinding绑定的类型 <port // 提供服务的地址,和端口,SOAP后面介绍 <soap:address </port> </service> |
分析如何调用服务方法
// 上图中的HelloWorldPortBinding参照的就是此HelloWorldPortBinding它的类型为HelloWorld接口类型. <binding // SOAP1.1协议 http://schemas.xmlsoap.org/soap/http <soap:binding <operation <soap:operation soapAction="" <input> <soap:body </input> <output> <soap:body use="literal" /> </output> </operation> </binding> |
WSDL详解
WSDL 文档的组成部分
元素 |
定义 |
<portType> |
web service 执行的操作 |
<message> |
web service 使用的消息 |
<types> |
web service 使用的数据类型 |
<binding> |
web service 使用的通信协议 |
WSDL 文档的主要结构:
<definitions> <types> definition of </types> <message> definition of </message> <portType> definition of </portType> <binding> definition of </binding> </definitions> |
WSDL元素介绍
定义一个功能,在Java中叫做方法,在C中叫做函数;在Java中叫类,在C语言中叫做结构体。这些名词都不一样。
WSDL规范为了不会产生歧义,就定义了一些新的名词来表述功能与服务。
<portType>(WSDL端口[t3] )
<portType> 元素是最重要的 WSDL 元素。 它可描述一个 web service、可被执行的操作,以及相关的消息。 可以把 <portType>
元素比作传统编程语言中的一个函数库(或一个模块、或一个类)。
<operation>子元素:
对服务中所支持的操作的抽象描述,一般单个Operation描述了一个访问入口的请求/响应消息对。
<message> (WSDL消息)
<message> 元素定义一个操作的数据元素。 每个消息均由一个或多个部件组成。可以把这些部件比作传统编程语言中一个函数调用的参数。
通信消息的数据结构的抽象类型化定义。使用Types所定义的类型来定义整个消息的数据结构。
<types>(WSDL types[t4] )
<types>
元素定义 web service 使用的数据类型。 为了最大程度的平台中立性,WSDL 使用 XML Schema 语法来定义数据类型。
<binding> (WSDL Bindings[t5] )
<binding> 元素为每个端口定义消息格式和协议细节。
示例
这是某个 WSDL 文档的简化的片段:
<message name="getTermRequest"> <part name="term" </message> <message name="getTermResponse"> <part name="value" </message> <portType name="glossaryTerms"> <operation <input <output message="getTermResponse"/> </operation> </portType> |
在这个例子中,<portType>
元素把 "glossaryTerms" 定义为某个端口的名称,把 "getTerm" 定义为某个操作的名称。
操作
"getTerm" 拥有一个名为 "getTermRequest" 的输入消息,以及一个名为 "getTermResponse" 的输出消息。
<message>
元素可定义每个消息的部件,以及相关联的数据类型。
对比传统的编程,glossaryTerms 是一个函数库,而 "getTerm" 是带有输入参数 "getTermRequest" 和返回参数
getTermResponse 的一个函数。
说明
Types、Message、PortType、Opration为抽象定义。
Binding、Port、Service是实现。
Port:
定义为协议/数据格式绑定与具体web访问地址组合的单个服务访问点。
Service:
相关服务访问点的集合。
问题思考:
通过上面的学习我们已经知道如何通过阅读WSDL文档来调用Web服务.但是到目前为止我们还不能通过AJAX的方式来调用我们自己发布的服务.因为我们并不知道我们自己发布服务的SOAP信息,可以使用MyEclipse提供的工具WebServiceExplorer
WebServiceExplorer使用
WebServiceExplorer使用步骤
- 首先打开web service Explore浏览器à单击右边的WSDL PAGEà在Open WSDL中输入网址http://127.0.0.1:9999/helloworld?wsdl 然后单击go既可
- 在图的左边会罗列出已经注册的web服务类和服务方法(注意JDK1.6不支持SOAP1.2协议.所以在网上发布了wsdl服务如果是基于1.2的则得不到任何有效信息),测试任何一个方法可以得到类似如下格式的代码:
SOAP Request Envelope:
<soapenv:Envelope <soapenv:Body> <q0:sayHi> <arg0>china</arg0> </q0:sayHi> </soapenv:Body> </soapenv:Envelope> |
SOAP Response Envelope:
<S:Envelope <S:Body> <ns2:sayHiResponse <return>hello---->china</return> </ns2:sayHiResponse> </S:Body> </S:Envelope> |
我们通过WebServiceExplorer工具会发现.基于Java代码的WS服务的调用本质上还是发送了HTTP1.1协议+传输的数据, 不但有数据本身而且还有对数据的描述. HTTP 请求体传输的是一种特殊的XML,它就是SOAP
SOAP协议简单介绍
名词3:SOAP-Simple Object Access Protocol(简单对象访问协议)
1
SOAP作为一个基于XML语言的协议用于有网上传输数据。
2
SOAP = 在HTTP的基础上+XML数据。
3
SOAP的组成
Envelope – 必须的部分。以XML的根元素出现。
Headers – 可选的。
Body – 必须的。在body部分包含要执行的服务器的方法。和发送到服务器数据。
Soap:是HTTP POST的一个专用版本,遵循一种特殊的xml消息格式Content-type设置为: text/xml任何数据都可以xml化。
采用AJAX 调用自己发布的WebService
<body> <button </body> <script // 1:创建XMLHTTP对象 var xhr=null; function mobile(){ // 声明在访问的ws的地址 var // 书写要发送的XML文件,即 SOAP var 'xmlns:q0="http://myws.ws.e.oocl.cn/" 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' '<soapenv:Body>' + '<q0:sayHi>' + '<arg0>china</arg0>' '</q0:sayHi>' + '</soapenv:Body>' + '</soapenv:Envelope>' // 3:打开连接 xhr.open("post",url,true); xhr.onreadystatechange=callBack; xhr.setRequestHeader("Content-Type","text/xml; xhr.send(soap); } function callBack(){ if(xhr.readyState==4){ var a=xhr.responseXML; alert(xhr.responseXML.getElementsByTagName("return")[0].text); } } function init(){ xhr=new } init(); </script> |
ServiceExplorer阶段总结:
通过上面的AJAX调用我们会发现. 的确可以实现相同的功能. 但是细心的同学们会发现. 我们自己生成的SOAP和官方提供的SOAP不同. 那么我们如何来修改标签和命名空间的潜前缀呢. 这就要我们下面学到的注解了
使用WebService注解来修改WSDL文件
WSDL文件的内容,一般由服务默认生成,但为了更好的向开发人员提供使用说明书,一般应做一些简单的修改。至少不应该暴露我们的包结构。而targetNamespace默认情况下为倒置的包名,这已经暴露了我们的包结构。通过在类文件上添加以下注解,可以修改wsdl生成的各元素,而不是直接去修改wsdl文件,直接去修改wsdl文件是无效的。
WebService的注解包括:
- @WebService-定义服务 --类上
- @WebMethod-定义方法 - 方法
- @WebResult-定义返回值 – 返回值
- @WebParam-定义参数 – 参数
WebService注解的使用
- 通过WebService的注解,可以更加形像的描述Web服务。从而生成WSDL文档。
- 当修改了WebService注解之后,同时会影响客户端生成的代码。
- 调用的方法名和参数名也发生了变化。
- 即使是没有修改源代码,只修改了注解,客户端的代码也必须要重新生成(注意是生成而不是下载)。否则调用将会失败。
- 生成本地调用代码,依然使用wsimport工具
@WebService注解:
- @WebService 标注要暴露为Web Services的类或接口 ,用于修饰类或接口,包含的属性有:
- 2.
targetNamespace属性:定义命名空间,默认为”http://”+”包名倒排” - 3.
name属性:Web Service 的名称,默认为发布服务的类名。 - 4.
serviceName: ws服务的名词,默认在类名后面添加了service - endpointInterface属性:定义服务抽象 Web Service 协定的服务端点接口的完整名称,接口也必须声明WebService注解,包括方法的注解必须也要添加到接口中,否则会无效,
而且WS在没有注解的情况下.生成WS的时候会自动生成一个注解.所以可以不用指定接口
@WebMethod
- 此注解用在方法上,用于修改对外暴露的方法
- 2.
operationName属性:与此方法匹配的 wsdl:operation 的名称 - 3.
exclude属性:标注此方法是否被暴露,默认为false
注意:如果所有方法上都没有指定@WebMethod,则默认是所有的方法都是对外暴露的方法。如果有任一方法指定了@WebMethod,则只有指定这个注解的才是对外暴露的方法。
@WebResult
@WebResult 定义返回值,返回值类型不能为接口类或抽象类,而且必须有个不带参的构造函数,包含属性
name属性:返回值的名称
一个添加注解的案例:
// 修改web服务的名称,和命名空间 @WebService(name="Hello",targetNamespace="http://icast.cn") public class HelloWorld { @WebMethod(operationName="aaa") // 修改webResult 和 public return } public static // 发布一个web服务,指定IP和实现者 Endpoint end=Endpoint.publish("http://127.0.0.1:4567/hello",new } } |
CXF框架概念介绍
Apache CXF 是一个开源的 Services 框架,CXF
帮助您来构建和开发 Services 这些 Services
可以支持多种协议,比如:SOAP1.1/1.2、POST/HTTP、RESTful HTTP CXF 大大简化了
Service可以天然地和 Spring 进行无缝集成。
ServerFactoryBean来发布web服务
服务类代码如下:
// 注解是无效的 @WebService(name="Hello",targetNamespace="http://icast.cn") public class HelloWorld { public return } } |
发布类代码如下:
public static void main(String[] // 发布服务的类, 类似Endpoint ServerFactoryBean // 注册服务器地址和端口 serverFactoryBean.setAddress("http://127.0.0.1:9999/hello"); // 注册哪个类提供服务 serverFactoryBean.setServiceBean(new // 发布一个cxf服务 serverFactoryBean.create(); // 一分钟有服务终止 Thread.sleep(1 // 正常退出程序 System.exit(0); } |
ServerFactoryBean注意事项:
这种方式没有添加webService注解,也就是说没有注解也可以发布webService服务,但是这种方式不是很规范,比如我们不可以通过注解的方式来修改WSDL的标签信息,
JaxWsServerFactoryBean来发布web服务
- JaxWsServerFactoryBean是ServerFactoryBean的子类,也是功能扩展类。
- 此类,必须要在被发布为服务的类上添加@WebService注解,如果不加注解,虽然不出错,但也不会对外暴露任何方法。使用此类生成的wsdl文件更加规范
- 更重要的是可以通过添加拦截器拦截请求.
客户端代码如下:
@WebService public class HelloWorld { public return } } |
发布类代码如下:
public static void main(String[] // 发布服务的类, 类似Endpoint JaxWsServerFactoryBean // 注册服务器地址和端口 jaxWsServer.setAddress("http://127.0.0.1:9999/hello"); // 注册哪个类提供服务 jaxWsServer.setServiceBean(new // 配置输入输出日志拦截器 jaxWsServer.getInInterceptors().add(new jaxWsServer.getOutInterceptors().add(new // 发布一个cxf服务 jaxWsServer.create(); // 一分钟有服务终止 Thread.sleep(1 // 正常退出程序 System.exit(0); } |
访问:http://127.0.0.1:9999/hello?wsdl 控制台第一次握手拦截器日志如下:
---------------------------- ID: 1 Address: http://127.0.0.1:9999/hello?wsdl Http-Method: GET Content-Type: Headers: {Accept=[*/*], accept-encoding=[gzip, -------------------------------------- |
通过Java客户端调用服务类
public static void main(String[] HelloWorldService HelloWorld System.out.println(helloWorld.sayHi("test")); } |
拦截器日志如下:
---------------------------- ID: 1 Address: http://127.0.0.1:9999/hello?wsdl Http-Method: GET Content-Type: text/xml Headers: {Accept=[*/*], Cache-Control=[no-cache], -------------------------------------- 2013-1-6 11:28:17 信息: Inbound Message ---------------------------- ID: 2 Address: http://127.0.0.1:9999/hello Encoding: UTF-8 Http-Method: POST Content-Type: text/xml; charset=UTF-8 Headers: {Accept=[*/*], Cache-Control=[no-cache], Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHi -------------------------------------- 2013-1-6 11:28:17 信息: Outbound Message --------------------------- ID: 2 Encoding: UTF-8 Content-Type: text/xml Headers: {} Payload: <soap:Envelope -------------------------------------- |
CXF与Spring集成发布WebService
前面的服务发布包括创建服务类都是硬编码的方式.是否可以使用配置的方式来发布服务类呢. 答案是肯定的这就要同Spring集成了, 由于cxf的项目已经集成了Spring(自带了Spring
lib)所以CXF的服务都是在Spring的配置文件中完成的, 并且我们需要把项目发布到tomcat中,所以我们可以创建一个web项目
配置开发环境:
l
建立一个web项目
l
准备所有jar包,将CXF_HOME\lib项目下的所有jar包,全部都拷贝新项目的lib目录下.其中里面已经包含了Sring3.0的jar包 其中jetty 服务器的包可以不要.因为我们要部署的tomcat服务器中了
l
在web.xml中配置cxf的核心servlet,CXFServlet
l
此配置文件的作用类 拦截/ws/*的所有请求 类似Struts2的过滤器
<servlet> <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>/ws/*</url-pattern> </servlet-mapping> |
通过Spring配置文件发布服务
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/context http://cxf.apache.org/core http://cxf.apache.org/jaxws <!-- 这样配置自身的服务也可以使用 --> <bean id="userImpl" <!-- id:逻辑名 <jaxws:server <jaxws:serviceBean> <ref </jaxws:serviceBean> <jaxws:inInterceptors> <bean </jaxws:inInterceptors> <jaxws:outInterceptors> <bean </jaxws:outInterceptors> </jaxws:server> </beans> |
服务接口如下:
@WebService public interface IUser { public void public } |
服务类如下:
public class UserImpl implements private public for(User if(temp.getUid()==uid){ return } } return } public void // TODO users.add(user); } } |
实体类如下:
public class User { private private public int return } public void this.uid } public return } public void this.uname } } |
通过JSP+Servlet调用本地服务:
Servlet在web.xml中配置如下:
<servlet> <servlet-name>cxf</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet> <servlet-name>UserServlet</servlet-name> <servlet-class>cn.oocl.i.cxf.servlet.UserServlet</servlet-clas> </servlet> |
Servlet核心代码调用如下:
public void doPost(HttpServletRequest throws User user = new User(); user.setUid(Integer.parseInt(request.getParameter("uid"))); user.setUname(request.getParameter("uname")); userImpl.saveUser(user); } public void // Put your WebApplicationContext .getWebApplicationContext(this.getServletContext()); userImpl = } |
WEB页面调用代码如下:
<form 用户编号:<input 用户名:<input <input type="submit" </form> |
通过Java远程调用访问CXF+Spring服务如下:
public static IUserService User user=new user.setUid(1); user.setUname("admin"); userService.getIUserPort().saveUser(user); User System.out.println(temp.getUid() } |
通过ajax远程调用访问CXF+Spring服务如下:
<body> <button onclick="mobile()">cxf+Spring测试</button> </body> <script // 1:创建XMLHTTP对象 var xhr=null; function mobile(){ // 声明在访问的ws的地址 var // 书写要发送的XML文件,即 SOAP var '<ns2:getUser // 3:打开连接 xhr.open("POST",url,true); xhr.setRequestHeader("Content-Type","text/xml; xhr.setRequestHeader("Accept","*/*"); xhr.onreadystatechange=callBack; xhr.send(soap); } function callBack(){ if(xhr.readyState==4){ var alert(xhr.responseXML.getElementsByTagName("uid")[0].text); alert(xhr.responseXML.getElementsByTagName("uname")[0].text); } } function init(){ xhr=new } init(); </script> |
天气预报的案例:(每天限制访问数量)
访问:http://www.webxml.com.cn 获取天气预报服务 通过wsImport转化为Java代码调用如下:可以获取省份、城市的最后获取具体城市的天气预报
注意事项:我们可以通过AJAX的方式调用Java代码, 然后发送请求,这样回来只有数据没有XML文件,不存在解析问题, 看是很好,但是Java代码本质上也发送的是SOAP请求。
这样设计效率很低, 除非回来的数据需要处理,例如中文翻译的时候下载的声音。其它的情况还是建议直接发送XML数据的
采用纯Java方式了解天气预报调用流程
public static void main(String[] args) { // 通过查看WSDL文档获取服务 WeatherWS // 获取SOAP1.1服务 JDK默认不支持1.2 WeatherWSSoap // 获得中国省份、直辖市、地区和与之对应的ID for(String System.out.println("支持的省份ID" + temp); } // 输入参数:theRegionCode =市、ID和名称 for(String System.out.println("支持的城市ID:" + temp); } System.out.println("------获取获得某个城市天气预报数据--------"); for(String System.out.println(temp); } } |
例如手机淘宝可以复用已有淘宝的业务逻辑.
每个web Service称为一个生产者.不同的生产者可以相互协同合作完成整个应用
对于某个访问入口点类型所支持的操作的抽象集合,这些操作可以由一个或多个服务访问点来支持。
数据类型定义的容器,它使用某种类型系统(一般地使用XML
Schema中的类型系统)。Types中有simplexType
和
complexType两种。
特定端口类型的具体协议和数据格式规范的绑定。
CXF WebService 教程的更多相关文章
- Java WebService 教程系列之 Spring 整合 CXF
Java WebService 教程系列之 Spring 整合 CXF 一.引入 jar 包 <dependency> <groupId>org.apache.cxf</ ...
- java调用CXF WebService接口的两种方式
通过http://localhost:7002/card/services/HelloWorld?wsdl访问到xml如下,说明接口写对了. 2.静态调用 // 创建WebService客户端代理工厂 ...
- CXF WebService整合SpringMVC的maven项目
首先推荐博客:http://www.cnblogs.com/xdp-gacl/p/4259481.html http://blog.csdn.net/hu_shengyang/article/de ...
- Spring 3 整合Apache CXF WebService[转]
http://www.cnblogs.com/hoojo/archive/2012/07/13/2590593.html 在CXF2版本中,整合Spring3发布CXF WebService就更加简单 ...
- Spring整合CXF webservice restful 实例
webservice restful接口跟soap协议的接口实现大同小异,只是在提供服务的类/接口的注解上存在差异,具体看下面的代码,然后自己对比下就可以了. 用到的基础类 User.java @Xm ...
- 《转》CXF WebService 开发文档-目录索引
CXF WebService 开发文档-目录索引 上次介绍了Axis的WebService,现在我们来看看CXF是怎么完成WebService的. Axis1 WebService 在线博文: htt ...
- 史上最详cxf-Springmvc-maven实现webservice教程(转)
虽知道webservice,工作两年一直没使用过,最近不忙趁机研究了下,实现了简单的服务端及客户端调用.鉴于慕课网没有webservice的教程,大多又都是学生,就在这里跟大家分享下,内容比较详细.大 ...
- cxf webservice 生成wsdl方法参数名称为arg0问题
在通过cxf生成webservice服务时,如果你是用ServerFactoryBean,那么在生成wsdl时,方法的参数名称会被自动命名为arg0,arg1...,如: <xsd:comple ...
- cxf WebService设置wsdl中soapAction的值
用cxf开发一个WebService很简单,只需要下面几步: 1.定义接口 public interface HelloService { String hello(); } 2.实现 public ...
随机推荐
- jQuery 简单归纳总结
jQuery语法是为HTML元素的选取编制的,能够对元素运行某些操作. 基础语法是:$(selector).action() +美元符号定义 jQuery +选择符(selector)"查询 ...
- http://poj.org/problem?id=2253
floyd的应用求每条路径两点之间最大距离的最小值 #include <iostream> #include <cstdio> #include <algorithm&g ...
- [TypeScript] Understanding Decorators
Decorators are a feature of TypeScript that are becoming more and more common in many major librarie ...
- GO的跨平台数扰类型
基本数据类型的包装: 1.跨平台,用于移植 2.不同的框架类型包装的类型(MFC ,WIN32SDK,C) 3.基本数据类型的组装成的结构体 4.宏定义 数字类型 Go 也有基于架构的类型,例如:in ...
- 2014-08-05 pig
Pig的数据类型能够分为两种:一种是scalar类型,包含单一的value,一种是complex类型,包含有其他的类型. 对于scalar类型: int,long,float,double,chara ...
- PureMVC(JS版)源码解析(七):Mediator类
之前的博文中,我们分析了SimpleCommand类和MacroCommand类,这两个类用作"业务逻辑(business logic)"处理,今天,我们讲一些和UI界面相关联的M ...
- C#/.net七牛云存储上传图片(文件)操作
七牛云存储官方: C#SDK(http://developer.qiniu.com/docs/v6/sdk/csharp-sdk.html) 注册成为标准用户就可获得:10GB永久免费存储空间/ 每月 ...
- html学习的一些问题
1,什么是 W3C标准?w3c 标准不是一个标准,而是一系列标准,包括:结构标准,表现标准,动作标准. 2,内链元素和块状元素的区别内链元素允许与其他内链元素位于同一行,没有宽和高,如果想设置宽和搞, ...
- 使用Github建立个人博客
总的说来 这个当有node.js 和gitbub的账号后,搭建一个自己的博客,想想还是挺美的事! 由于要把整个流程说清楚 估计lz还没这个实力,所以都是继承前辈们的经验,自己再添加一点遇到的问题和解决 ...
- C++话题
1.多态地实现 A:C++中多态的实现原理是怎样的? Q:通过迟邦定技术(late binding)实现. 具体实现原理如下: 1. 基类中函数带virtual关键字,表示该方法为虚函数. 2. 子类 ...