- 浏览: 498190 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (271)
- json (6)
- hibernate (12)
- javascript (25)
- session cookie (2)
- struts2 (12)
- 数据库 (23)
- spring (25)
- freemarker (2)
- 其它 (17)
- ibatis (5)
- Web Service (5)
- java基础 (54)
- hessian (2)
- lucene (7)
- DWR (1)
- 导出excel (1)
- CSS (1)
- java 邮件 (5)
- SSH转载 (5)
- 文件断点 上传 (8)
- jQuery (7)
- ant (2)
- tuscany (5)
- maven (7)
- rsa (2)
- tomcat (2)
- svn (3)
- comet (2)
- log4j (2)
- linux (4)
- hadoop (1)
- 设计模式 (4)
- ssh (2)
- git (3)
- quartz (1)
- dubbo (2)
- mysql (2)
- 注解 (1)
- easyui (1)
- tree (1)
- 堆栈 (1)
- 泛型 (1)
- eclipse (1)
- annotation (1)
- mvc (3)
- shiro (1)
- Nexus (1)
- jackson (1)
- itext (1)
- mina (1)
- nio (1)
- ehcache (2)
- memcached (1)
- restful (2)
- mongodb (1)
- solr (1)
- zookeeper (1)
- redis (1)
- vpn (0)
- elastic (2)
- xxl-job (1)
最新评论
-
g_tao:
作者你好,你这个例子中服务端是跑在tomcat中吗
阿里巴巴dubbo处理文件上传下载 -
g_tao:
作者你好,能把整个项目给我发一份吗?guotao114@126 ...
阿里巴巴dubbo处理文件上传下载 -
tanmingjuntan:
楼上 本文提供的代码样例 和 你之前提供的例子有出入好多都没 ...
使用HttpURLConnection.setChunkedStreamingMode(10*1024);的时候,不同的参数导致文件上传损坏 -
dreamoftch:
dannielhome 写道请问下这个upload.exe是什 ...
断点文件上传流程 -
dannielhome:
请问下这个upload.exe是什么东西呢
断点文件上传流程
http://www.iteye.com/topic/166314
Web Service概述
Web Service的定义
W3C组织对其的定义如下,它是一个软件系统,为了支持跨网络的机器间相互操作交互而设计。Web Service服务通常被定义为一组模块化的API,它们可以通过网络进行调用,来执行远程系统的请求服务。
这里我们从一个程序员的视角来观察web service。在传统的程序编码中,存在这各种的函数方法调用。通常,我们知道一个程序模块M中的方法A,向其发出调用请求,并传入A方法需要的参数P,方法A执行完毕后,返回处理结果R。这种函数或方法调用通常发生在同一台机器上的同一程序语言环境下。现在的我们需要一种能够在不同计算机间的不同语言编写的应用程序系统中,通过网络通讯实现函数和方法调用的能力,而Web service正是应这种需求而诞生的。
最普遍的一种说法就是,Web Service = SOAP + HTTP + WSDL。其中,SOAP Simple Object Access Protocol)协议是web service的主体,它通过HTTP或者SMTP等应用层协议进行通讯,自身使用XML文件来描述程序的函数方法和参数信息,从而完成不同主机的异构系统间的计算服务处理。这里的WSDL(Web Services Description Language)web 服务描述语言也是一个XML文档,它通过HTTP向公众发布,公告客户端程序关于某个具体的 Web service服务的URL信息、方法的命名,参数,返回值等。
下面,我们先来熟悉一下SOAP协议,看看它是如何描述程序中的函数方法、参数及结果对象的。
SOAP协议简介
什么是SOAP
SOAP 指简单对象访问协议,它是一种基于XML的消息通讯格式,用于网络上,不同平台,不同语言的应用程序间的通讯。可自定义,易于扩展。一条 SOAP 消息就是一个普通的 XML 文档,包含下列元素:
• Envelope 元素,标识XML 文档一条 SOAP 消息
• Header 元素,包含头部信息的XML标签
• Body 元素,包含所有的调用和响应的主体信息的标签
• Fault 元素,错误信息标签。
以上的元素都在 SOAP的命名空间http://www.w3.org/2001/12/soap-envelope中声明;
SOAP的语法规则
• SOAP 消息必须用 XML 来编码
• SOAP 消息必须使用 SOAP Envelope 命名空间
• SOAP 消息必须使用 SOAP Encoding 命名空间
• SOAP 消息不能包含 DTD 引用
• SOAP 消息不能包含 XML 处理指令
SOAP 消息的基本结构
Java代码 收藏代码
<? xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<soap:Header>
...
...
</soap:Header>
<soap:Body>
...
...
<soap:Fault>
...
...
</soap:Fault>
</soap:Body>
</soap:Envelope>
SOAP Envelope 元素
Envelope 元素是 SOAP 消息的根元素。它指明 XML 文档是一个SOAP 消息。它的属性 xmlns:soap的值必须是http://www.w3.org/2001/12/soap-envelope。
encodingStyle 属性,语法:soap:encodingStyle="URI"
encodingStyle 属性用于定义文档中使用的数据类型。此属性可出现在任何 SOAP 元素中,并会被应用到元素的内容及元素的所有子元素上。
Java代码 收藏代码
<? xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
...
Message information goes here
...
</soap:Envelope>
SOAP Header 元素
actor 属性,语法soap:actor="URI"
通过沿着消息路径经过不同的端点,SOAP 消息可从某个发送者传播到某个接收者。并非 SOAP 消息的所有部分均打算传送到 SOAP 消息的最终端点,不过,另一个方面,也许打算传送给消息路径上的一个或多个端点。SOAP 的 actor 属性可被用于将 Header 元素寻址到一个特定的端点。
mustUnderstand 属性 ,语法soap:mustUnderstand="0|1"
SOAP 的 mustUnderstand 属性可用于标识标题项对于要对其进行处理的接收者来说是强制的还是可选的。假如您向 Header 元素的某个子元素添加了 "mustUnderstand="1",则要求处理此头部的接收者必须认可此元素。
Java代码 收藏代码
<? xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<soap:Header>
<m:Trans
xmlns:m="http://www.jsoso.net/transaction/"
soap:mustUnderstand="1"
soap:actor="http://www.w3schools.com/appml/ “ >234</m:Trans>
</soap:Header>
...
...
</soap:Envelope>
SOAP Body 元素
必需的 SOAP Body 元素可包含打算传送到消息最终端点的实际 SOAP 消息。Body元素中既可以包含SOAP定义的命名空间中的元素,如Fault,也可以是用户的应用程序自定义的元素。以下是一个用户定义的请求:
Java代码 收藏代码
<? xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<soap:Body>
<m:GetPrice xmlns:m="http://www.jsoso.net/prices">
<m:Item>Apples</m:Item>
</m:GetPrice>
</soap:Body>
</soap:Envelope>
上面的例子请求苹果的价格。请注意,上面的 m:GetPrice 和 Item 元素是应用程序专用的元素。它们并不是 SOAP 标准的一部分。而对应的 SOAP 响应应该类似这样:
Java代码 收藏代码
<?xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<soap:Body>
<m:GetPriceResponse xmlns:m="http://www.jsoso.net/prices">
<m:Price>1.90</m:Price>
</m:GetPriceResponse>
</soap:Body>
</soap:Envelope>
SOAP Fault 元素
Fault 元素表示 SOAP的错误消息。它必须是 Body 元素的子元素,且在一条 SOAP 消息中,Fault 元素只能出现一次。Fault 元素拥有下列子元素:
常用的SOAP Fault Codes
HTTP协议中的SOAP 实例
下面的例子中,一个 GetStockPrice 请求被发送到了服务器。此请求有一个 StockName 参数,而在响应中则会返回一个 Price 参数。此功能的命名空间被定义在此地址中: "http://www.jsoso.net/stock"
SOAP 请求:(注意HTTP的Head属性)
Java代码 收藏代码
POST /InStock HTTP/1.1
Host: www.jsoso.net
Content-Type: application/soap+xml; charset=utf-8
Content-Length: XXX
<? xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<soap:Body xmlns:m="http://www.jsoso.net/stock">
<m:GetStockPrice>
<m:StockName>IBM</m:StockName>
</m:GetStockPrice>
</soap:Body>
</soap:Envelope>
SOAP 响应:(注意HTTP的Head属性)
Java代码 收藏代码
HTTP/1.1 200 OK
Content-Type: application/soap+xml; charset=utf-8
Content-Length: XXX
<? xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<soap:Body xmlns:m="http://www.jsoso.net/stock">
<m:GetStockPriceResponse>
<m:Price>34.5</m:Price>
</m:GetStockPriceResponse>
</soap:Body>
</soap:Envelope>
HTTP协议中的SOAP RPC工作流程
WSDL简介
介绍过了SOAP,让我们关注Web Service中另外一个重要的组成WSDL。
WSDL的主要文档元素
WSDL文档可以分为两部分。顶部分由抽象定义组成,而底部分则由具体描述组成。抽象部分以独立于平台和语言的方式定义SOAP消息,它们并不包含任何随机器或语言而变的元素。这就定义了一系列服务,截然不同的应用都可以实现。具体部分,如数据的序列化则归入底部分,因为它包含具体的定义。在上述的文档元素中,<types>、<message>、<portType>属于抽象定义层,<binding>、<service>属于具体定义层。所有的抽象可以是单独存在于别的文件中,也可以从主文档中导入。
WSDL文档的结构实例解析
下面我们将通过一个实际的WSDL文档例子来详细说明各标签的作用及关系。
Java代码 收藏代码
<?xml version="1.0" encoding="UTF-8"?>
<definitions
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.jsoso.com/wstest"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.xmlsoap.org/wsdl/"
targetNamespace="http://www.jsoso.com/wstest"
name="Example">
<types>
<xsd:schema>
<xsd:import
namespace="http://www.jsoso.com/wstest"
schemaLocation="http://localhost:8080/hello?xsd=1"></xsd:import>
</xsd:schema>
</types>
<message name="toSayHello">
<part name="userName" type="xsd:string"></part>
</message>
<message name="toSayHelloResponse">
<part name="returnWord" type="xsd:string"></part>
</message>
<message name="sayHello">
<part name="person" type="tns:person"></part>
<part name="arg1" type="xsd:string"></part>
</message>
<message name="sayHelloResponse">
<part name="personList" type="tns:personArray"></part>
</message>
<message name="HelloException">
<part name="fault" element="tns:HelloException"></part>
</message>
<portType name="Example">
<operation name="toSayHello" parameterOrder="userName">
<input message="tns:toSayHello"></input>
<output message="tns:toSayHelloResponse"></output>
</operation>
<operation name="sayHello" parameterOrder="person arg1">
<input message="tns:sayHello"></input>
<output message="tns:sayHelloResponse"></output>
<fault message="tns:HelloException" name="HelloException"></fault>
</operation>
</portType>
<binding name="ExamplePortBinding" type="tns:Example">
<soap:binding
transport="http://schemas.xmlsoap.org/soap/http"
style="rpc"></soap:binding>
<operation name="toSayHello">
<soap:operation soapAction="sayHello"></soap:operation>
<input>
<soap:body use="literal"
namespace="http://www.jsoso.com/wstest"></soap:body>
</input>
<output>
<soap:body use="literal"
namespace="http://www.jsoso.com/wstest"></soap:body>
</output>
</operation>
<operation name="sayHello">
<soap:operation soapAction="sayHello"></soap:operation>
<input>
<soap:body use="literal"
namespace="http://www.jsoso.com/wstest"></soap:body>
</input>
<output>
<soap:body use="literal"
namespace="http://www.jsoso.com/wstest"></soap:body>
</output>
<fault name="HelloException">
<soap:fault name="HelloException" use="literal"></soap:fault>
</fault>
</operation>
</binding>
<service name="Example">
<port name="ExamplePort" binding="tns:ExamplePortBinding">
<soap:address location="http://localhost:8080/hello"></soap:address>
</port>
</service>
</definitions>
由于上面的事例XML较长,我们将其逐段分解讲解
WSDL文档的根元素:<definitions>
Java代码 收藏代码
<definitions
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.jsoso.com/wstest"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.xmlsoap.org/wsdl/"
targetNamespace="http://www.jsoso.com/wstest"
name="Example">
……
……
</definitions>
<definitions>定义了文档中用到的各个xml元素的namespace缩写,也界定了本文档自己的targetNamespace="http://www.jsoso.com/wstest",这意味着其它的XML要引用当前XML中的元素时,要声明这个namespace。注意xmlns:tns="http://www.jsoso.com/wstest"这个声明,它标示了使用tns这个前缀指向自身的命名空间。
引用
WSDL文档数据类型定义元素:<types>
Java代码 收藏代码
<types>
<xsd:schema>
<xsd:import
namespace="http://www.jsoso.com/wstest"
schemaLocation="http://localhost:8080/hello?xsd=1"></xsd:import>
</xsd:schema>
</types>
<types>标签定义了当前的WSDL文档用到的数据类型。要说明的是,为了最大程度的平台中立性,WSDL 使用 XML Schema 语法来定义数据类型。这些数据类型用来定义web service方法的参数和返回指。对于通用的原生数据类型如:integer , boolean , char , float等,在W3C的标准文档http://www.w3.org/2001/XMLSchema中已经做了定义。这里我们要引入的schema定义schemaLocation="http://localhost:8080/hello?xsd=1"是我们自定义的Java对象类型。
WSDL文档消息体定义元素:< message >
Java代码 收藏代码
<message name="toSayHello">
<part name="userName" type="xsd:string"></part>
</message>
<message name="toSayHelloResponse">
<part name="returnWord" type="xsd:string"></part>
</message>
<message name="sayHello">
<part name="person" type="tns:person"></part>
<part name="arg1" type="xsd:string"></part>
</message>
<message name="sayHelloResponse">
<part name="personList" type="tns:personArray"></part>
</message>
<message name="HelloException">
<part name="fault" element="tns:HelloException"></part>
</message>
<message>元素定义了web service函数的参数。<message>元素中的每个<part>子元素都和某个参数相符。输入参数在<message>元素中定义,与输出参数相隔离,输出参数有自己的<message>元素。兼作输入、输出的参数在输入输出的<message>元素中有它们相应的<part>元素。输出<message>元素以"Response"结尾,对Java而言方法得返回值就对应一个输出的<message>。每个<part>元素都有名字和类型属性,就像函数的参数有参数名和参数类型。
在上面的文档中有两个输入参数、两个输出参数和一个错误参数(对应Java中的Exception)。
输入参数<message>的name属性分别命名为toSayHello,sayHello。
toSayHello对应输入参数userName,参数类型为xsd:string,在Java语言中就是String;
sayHello对应两个输入参数person和arg1,类型为tns:person和xsd:string。这里tns:person类型就是引用了< types >标签中的类型定义。
输出参数<message>的name属性分别命名为toSayHelloResponse和sayHelloResponse。
这个名称和输入参数的<message>标签name属性对应,在其后面加上Response尾缀。
toSayHelloResponse对应的返回值是returnWord,参数类型为xsd:string;
sayHelloResponse对应的返回值是personList,参数类型为tns:personArray(自定义类型);
错误参数<message>的name属性为HelloException。
它的<part>子标签element而不是type来定义类型。
以上的message标签的name属性通常使用web service函数方法名作为参照,错误参数标签则使用异常类名为参照。标签中的参数名称,即part子元素的name属性是可自定义的(下一章节详细说明)。message标签的参数类型将引用types标签的定义。
WSDL文档函数体定义元素:< portType >
Java代码 收藏代码
<portType name="Example">
<operation name="toSayHello" parameterOrder="userName">
<input message="tns:toSayHello"></input>
<output message="tns:toSayHelloResponse"></output>
</operation>
<operation name="sayHello" parameterOrder="person arg1">
<input message="tns:sayHello"></input>
<output message="tns:sayHelloResponse"></output>
<fault message="tns:HelloException" name="HelloException"></fault>
</operation>
</portType>
<portType> 元素是最重要的 WSDL 元素。它可描述一个 web service、可被执行的操作,以及相关的消息。portType的name属性对应Java中的一个服务类的类名。<portType> 元素使用其子元素< operation>描述一个web service的服务方法。
在<operation>元素中,name属性表示服务方法名,parameterOrder属性表示方法的参数顺序,使用空格符分割多个参数,如:“parameterOrder="person arg1”。<operation>元素的子标签<input>表示输入参数说明,它引用<message>标签中的输入参数。<output>表示输出参数说明,它引用<message>标签中的输出参数。<fault>标签在Java方法中的特别用来表示异常(其它语言有对应的错误处理机制),它引用<message>标签中的错误参数。
WSDL绑定实现定义元素:< binding >
Java代码 收藏代码
<binding name="ExamplePortBinding" type="tns:Example">
<soap:binding
transport="http://schemas.xmlsoap.org/soap/http"
style="rpc"></soap:binding>
<operation name="toSayHello">
<soap:operation soapAction="sayHello"></soap:operation>
<input>
<soap:body use="literal"
namespace="http://www.jsoso.com/wstest"></soap:body>
</input>
<output>
<soap:body use="literal"
namespace="http://www.jsoso.com/wstest"></soap:body>
</output>
</operation>
<operation name="sayHello">
<soap:operation soapAction="sayHello"></soap:operation>
<input>
<soap:body use="literal"
namespace="http://www.jsoso.com/wstest"></soap:body>
</input>
<output>
<soap:body use="literal"
namespace="http://www.jsoso.com/wstest"></soap:body>
</output>
<fault name="HelloException">
<soap:fault name="HelloException" use="literal"></soap:fault>
</fault>
</operation>
</binding>
<binding>标签是完整描述协议、序列化和编码的地方,<types>,<message>和<portType>标签处理抽象的数据内容,而<binding>标签是处理数据传输的物理实现。
<binding>标签把前三部分的抽象定义具体化。
首先<binding>标签使用<soap:binding>的transport和style属性定义了Web Service的通讯协议HTTP和SOAP的请求风格RPC。其次<operation>子标签将portType中定义的operation同SOAP的请求绑定,定义了操作名称soapAction,输出输入参数和异常的编码方式及命名空间。
WSDL服务地址绑定元素:< service >
Java代码 收藏代码
<service name="Example">
<port name="ExamplePort" binding="tns:ExamplePortBinding">
<soap:address location="http://localhost:8080/hello"></soap:address>
</port>
</service>
service是一套<port>元素。在一一对应形式下,每个<port>元素都和一个location关联。如果同一个<binding>有多个<port>元素与之关联,可以使用额外的URL地址作为替换。
一个WSDL文档中可以有多个<service>元素,而且多个<service>元素十分有用,其中之一就是可以根据目标URL来组织端口。在一个WSDL文档中,<service>的name属性用来区分不同的service。在同一个service中,不同端口,使用端口的"name"属性区分。
这一章节,我们简单的描述了WSDL对SOAP协议的支持,以及在Web Service中的作用。在接下来的章节中,我们将学习如何使用Java6.0的Annotation标签来定义和生成对应的WSDL。
JavaSE6.0下的Web Service
从JavaSE6.0开始,Java引入了对Web Service的原生支持。我们只需要简单的使用Java的Annotation标签即可将标准的Java方法发布成Web Service。(PS:Java Annotation资料请参考 JDK5.0 Annotation学习笔记(一) )
但不是所有的Java类都可以发布成Web Service。Java类若要成为一个实现了Web Service的bean,它需要遵循下边这些原则:
这个类必须是public类
这些类不能是final的或者abstract
这个类必须有一个公共的默认构造函数
这个类绝对不能有finalize()方法
下面我们将通过一个具体的Java Web Service代码例子,配合上述的WSDL文件,讲述如何编写JavaSE6.0的原生Web Service应用。
完整的Java Web Service类代码
Java代码 收藏代码
package org.jsoso.jws.server;
import java.util.ArrayList;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.WebParam.Mode;
import javax.jws.soap.SOAPBinding;
/
* 提供WebService服务的类
*/
@WebService(name="Example", targetNamespace="http://www.jsoso.com/wstest", serviceName="Example")
@SOAPBinding(style=SOAPBinding.Style.RPC)
public class Example {
private ArrayList<Person> persons = new ArrayList<Person>();;
/**
*
* 返回一个字符串
* @param userName
* @return
*/
@WebMethod(operationName="toSayHello",action="sayHello",exclude=false)
@WebResult(name="returnWord")//自定义该方法返回值在WSDL中相关的描述
public String sayHello(@WebParam(name="userName")String userName) {
return "Hello:" + userName;
}
/**
* web services 方法的返回值与参数的类型不能为接口
* @param person
* @return
* @throws HelloException
*/
@WebMethod(operationName="sayHello", action="sayHello")
@WebResult(partName="personList")
public Person[] sayHello(@WebParam(partName="person", mode=Mode.IN)Person person,
String userName) throws HelloException {
if (person == null || person.getName() == null) {
throw new HelloException("说hello出错,对像为空。。");
}
System.out.println(person.getName() + " 对 " + userName + " 说:Hello,我今年" + person.getAge() + "岁");
persons.add(person);
return persons.toArray(new Person[0]);
}
}
Annotation 1@WebService(name="Example", targetNamespace="http://www.jsoso.com/wstest", serviceName="Example")
@WebService标签主要将类暴露为WebService,其中targetNamespace属性定义了自己的命名空间,serviceName则定义了< definitions >标签和<service>标签的name属性。
Annotation 2:@SOAPBinding(style=SOAPBinding.Style.RPC)
@SOAPBinding标签定义了WSDL文档中SOAP的消息协议,其中style属性对应SOAP的文档类型,可选的有RPC和DOCUMENT
Annotation 3:@WebMethod(operationName="toSayHello",action="sayHello",exclude=false)
@WebMethod定义Web Service运作的方法,
属性action 对应操作的活动 ,如<soap:operation soapAction="sayHello" />
属性operationName匹配的wsdl:operation 的名称,如<operation name="toSayHello" parameterOrder="userName">
属性exclude 用于阻止将某一继承方法公开为web服务,默认为false
Annotation 4:@WebResult(name="returnWord")
@ WebResult定义方法返回值得名称,如<part name="returnWord" type="xsd:string" />
Annotation 5:@WebParam(partName="person", mode=Mode.IN
@WebParam定义方法的参数名称,如<part name="person" type="tns:person" />,其中mode属性表示参数的流向,可选值有IN / OUT / INOUT
这里要着重说明的是,上述Web Service类的sayHello方法中,带有HelloException这个异常声明,造成该服务类不能直接发布成Web Service。需要使用wsgen工具为其生存异常Bean。关于wsgen工具的使用,请参考wsgen与wsimport命令说明
发布一个的Java Web Service
在完成了上述的Web Service Annotation注释后,我们使用wsgen工具为其进行服务资源文件的构造(这里主要是生成一个名为org.jsoso.jws.server.jaxws.HelloExceptionBean的异常bean类),最后使用以下的类发布Web 服务:
Java代码 收藏代码
package org.jsoso.jws.server;
import java.util.LinkedList;
import java.util.List;
import javax.xml.ws.Binding;
import javax.xml.ws.Endpoint;
import javax.xml.ws.handler.Handler;
/**
* @author zsy 启动web services服务
*/
public class StartServer {
/**
* @param args
*/
public static void main(String[] args) {
/*
* 生成Example 服务实例
*/
Example serverBean = new Example();
/*
* 发布Web Service到http://localhost:8080/hello地址
*/
Endpoint endpoint =
Endpoint.publish("http://localhost:8080/hello", serverBean);
Binding binding = endpoint.getBinding();
/*
* 设置一个SOAP协议处理栈
* 这里就简单得打印SOAP的消息文本
*/
List<Handler> handlerChain = new LinkedList<Handler>();
handlerChain.add(new TraceHandler());
binding.setHandlerChain(handlerChain);
System.out.println("服务已启动 http://localhost:8080/hello");
}
}
在控制台运行这个类,就可以使用URL :http://localhost:8080/hello?wsdl 浏览到上文所描述的WSDL的全文了。这说明您的第一个Web Service应用发布成功!
构建Web Service客户端
使用JavaSE6.0构建Web Service的客户端是一件相当简单的事。这里我们要使用到JDK中的另一个命令行工具wsimport。在控制台下输入以下命令:
引用
wsimport -d ./bin -s ./src -p org.jsoso.jws.client.ref http://localhost:8080/hello?wsdl
即可在包org.jsoso.jws.client.ref中生成客户端的存根及框架文件。其中我们要使用的类只有两个:服务类Example_Service和本地接口Example。编写如下客户端,即可调用Web Service服务:
Java代码 收藏代码
package org.jsoso.jws.client;
import org.jsoso.jws.client.ref.*;
public class RunClient {
/**
* @param args
*/
public static void main(String[] args) {
//初始化服务框架类
Example_Service service = new Example_Service();
//或者本地服务借口的实例
Example server = (Example) service.getExamplePort();
try {
//调用web service的toSayHello方法
System.out.println("输入toSayHello的返回值——" + server.toSayHello("阿土"));
Person person = new Person();
person.setName("阿土");
person.setAge(25);
//调用web service的sayHello方法
server.sayHello(person, "机器人");
person = new Person();
person.setName("aten");
person.setAge(30);
//调用web service的sayHello方法
PersonArray list = server.sayHello(person, "机器人");
//输出返回值
System.out.println("\n以下输入sayHello的返回值——");
for (Person p : list.getItem()) {
System.out.println(p.getName() + ":" + p.getAge());
}
} catch (HelloException_Exception e) {
e.printStackTrace();
}
}
}
届此,本次Web Service的学习暂告一个段落。Java Web Service是一个相当庞大的知识体系,其中涉及的相关技术较多,这里无法一一道来,我们将会在今后的开发和使用中,同大家做进一步深入的探讨和学习。
附录:wsgen与wsimport命令说明
wsgen
wsgen是在JDK的bin目录下的一个exe文件(Windows版),该命令的主要功能是用来生成合适的JAX-WS。它读取Web Service的终端类文件,同时生成所有用于发布Web Service所依赖的源代码文件和经过编译过的二进制类文件。这里要特别说明的是,通常在Web Service Bean中用到的异常类会另外生成一个描述Bean,如果Web Service Bean中的方法有申明抛出异常,这一步是必需的,否则服务器无法绑定该对像。此外,wsgen还能辅助生成WSDL和相关的xsd文件。wsgen从资源文件生成一个完整的操作列表并验证web service是否合法,可以完整发布。
命令参数说明:
-cp 定义classpath
-r 生成 bean的wsdl文件的存放目录
-s 生成发布Web Service的源代码文件的存放目录(如果方法有抛出异常,则会生成该异常的描述类源文件)
-d 生成发布Web Service的编译过的二进制类文件的存放目录(该异常的描述类的class文件)
命令范例:wsgen -cp ./bin -r ./wsdl -s ./src -d ./bin -wsdl org.jsoso.jws.server.Example
wsimport
wsimport也是在JDK的bin目录下的一个exe文件(Windows版),主要功能是根据服务端发布的wsdl文件生成客户端存根及框架,负责与Web Service 服务器通信,并在将其封装成实例,客户端可以直接使用,就像使用本地实例一样。对Java而言,wsimport帮助程序员生存调用web service所需要的客户端类文件.java和.class。要提醒指出的是,wsimport可以用于非Java的服务器端,如:服务器端也许是C#编写的web service,通过wsimport则生成Java的客户端实现。
命令参数说明:
-d 生成客户端执行类的class文件的存放目录
-s 生成客户端执行类的源文件的存放目录
-p 定义生成类的包名
Web Service概述
Web Service的定义
W3C组织对其的定义如下,它是一个软件系统,为了支持跨网络的机器间相互操作交互而设计。Web Service服务通常被定义为一组模块化的API,它们可以通过网络进行调用,来执行远程系统的请求服务。
这里我们从一个程序员的视角来观察web service。在传统的程序编码中,存在这各种的函数方法调用。通常,我们知道一个程序模块M中的方法A,向其发出调用请求,并传入A方法需要的参数P,方法A执行完毕后,返回处理结果R。这种函数或方法调用通常发生在同一台机器上的同一程序语言环境下。现在的我们需要一种能够在不同计算机间的不同语言编写的应用程序系统中,通过网络通讯实现函数和方法调用的能力,而Web service正是应这种需求而诞生的。
最普遍的一种说法就是,Web Service = SOAP + HTTP + WSDL。其中,SOAP Simple Object Access Protocol)协议是web service的主体,它通过HTTP或者SMTP等应用层协议进行通讯,自身使用XML文件来描述程序的函数方法和参数信息,从而完成不同主机的异构系统间的计算服务处理。这里的WSDL(Web Services Description Language)web 服务描述语言也是一个XML文档,它通过HTTP向公众发布,公告客户端程序关于某个具体的 Web service服务的URL信息、方法的命名,参数,返回值等。
下面,我们先来熟悉一下SOAP协议,看看它是如何描述程序中的函数方法、参数及结果对象的。
SOAP协议简介
什么是SOAP
SOAP 指简单对象访问协议,它是一种基于XML的消息通讯格式,用于网络上,不同平台,不同语言的应用程序间的通讯。可自定义,易于扩展。一条 SOAP 消息就是一个普通的 XML 文档,包含下列元素:
• Envelope 元素,标识XML 文档一条 SOAP 消息
• Header 元素,包含头部信息的XML标签
• Body 元素,包含所有的调用和响应的主体信息的标签
• Fault 元素,错误信息标签。
以上的元素都在 SOAP的命名空间http://www.w3.org/2001/12/soap-envelope中声明;
SOAP的语法规则
• SOAP 消息必须用 XML 来编码
• SOAP 消息必须使用 SOAP Envelope 命名空间
• SOAP 消息必须使用 SOAP Encoding 命名空间
• SOAP 消息不能包含 DTD 引用
• SOAP 消息不能包含 XML 处理指令
SOAP 消息的基本结构
Java代码 收藏代码
<? xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<soap:Header>
...
...
</soap:Header>
<soap:Body>
...
...
<soap:Fault>
...
...
</soap:Fault>
</soap:Body>
</soap:Envelope>
SOAP Envelope 元素
Envelope 元素是 SOAP 消息的根元素。它指明 XML 文档是一个SOAP 消息。它的属性 xmlns:soap的值必须是http://www.w3.org/2001/12/soap-envelope。
encodingStyle 属性,语法:soap:encodingStyle="URI"
encodingStyle 属性用于定义文档中使用的数据类型。此属性可出现在任何 SOAP 元素中,并会被应用到元素的内容及元素的所有子元素上。
Java代码 收藏代码
<? xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
...
Message information goes here
...
</soap:Envelope>
SOAP Header 元素
actor 属性,语法soap:actor="URI"
通过沿着消息路径经过不同的端点,SOAP 消息可从某个发送者传播到某个接收者。并非 SOAP 消息的所有部分均打算传送到 SOAP 消息的最终端点,不过,另一个方面,也许打算传送给消息路径上的一个或多个端点。SOAP 的 actor 属性可被用于将 Header 元素寻址到一个特定的端点。
mustUnderstand 属性 ,语法soap:mustUnderstand="0|1"
SOAP 的 mustUnderstand 属性可用于标识标题项对于要对其进行处理的接收者来说是强制的还是可选的。假如您向 Header 元素的某个子元素添加了 "mustUnderstand="1",则要求处理此头部的接收者必须认可此元素。
Java代码 收藏代码
<? xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<soap:Header>
<m:Trans
xmlns:m="http://www.jsoso.net/transaction/"
soap:mustUnderstand="1"
soap:actor="http://www.w3schools.com/appml/ “ >234</m:Trans>
</soap:Header>
...
...
</soap:Envelope>
SOAP Body 元素
必需的 SOAP Body 元素可包含打算传送到消息最终端点的实际 SOAP 消息。Body元素中既可以包含SOAP定义的命名空间中的元素,如Fault,也可以是用户的应用程序自定义的元素。以下是一个用户定义的请求:
Java代码 收藏代码
<? xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<soap:Body>
<m:GetPrice xmlns:m="http://www.jsoso.net/prices">
<m:Item>Apples</m:Item>
</m:GetPrice>
</soap:Body>
</soap:Envelope>
上面的例子请求苹果的价格。请注意,上面的 m:GetPrice 和 Item 元素是应用程序专用的元素。它们并不是 SOAP 标准的一部分。而对应的 SOAP 响应应该类似这样:
Java代码 收藏代码
<?xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<soap:Body>
<m:GetPriceResponse xmlns:m="http://www.jsoso.net/prices">
<m:Price>1.90</m:Price>
</m:GetPriceResponse>
</soap:Body>
</soap:Envelope>
SOAP Fault 元素
Fault 元素表示 SOAP的错误消息。它必须是 Body 元素的子元素,且在一条 SOAP 消息中,Fault 元素只能出现一次。Fault 元素拥有下列子元素:
常用的SOAP Fault Codes
HTTP协议中的SOAP 实例
下面的例子中,一个 GetStockPrice 请求被发送到了服务器。此请求有一个 StockName 参数,而在响应中则会返回一个 Price 参数。此功能的命名空间被定义在此地址中: "http://www.jsoso.net/stock"
SOAP 请求:(注意HTTP的Head属性)
Java代码 收藏代码
POST /InStock HTTP/1.1
Host: www.jsoso.net
Content-Type: application/soap+xml; charset=utf-8
Content-Length: XXX
<? xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<soap:Body xmlns:m="http://www.jsoso.net/stock">
<m:GetStockPrice>
<m:StockName>IBM</m:StockName>
</m:GetStockPrice>
</soap:Body>
</soap:Envelope>
SOAP 响应:(注意HTTP的Head属性)
Java代码 收藏代码
HTTP/1.1 200 OK
Content-Type: application/soap+xml; charset=utf-8
Content-Length: XXX
<? xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<soap:Body xmlns:m="http://www.jsoso.net/stock">
<m:GetStockPriceResponse>
<m:Price>34.5</m:Price>
</m:GetStockPriceResponse>
</soap:Body>
</soap:Envelope>
HTTP协议中的SOAP RPC工作流程
WSDL简介
介绍过了SOAP,让我们关注Web Service中另外一个重要的组成WSDL。
WSDL的主要文档元素
WSDL文档可以分为两部分。顶部分由抽象定义组成,而底部分则由具体描述组成。抽象部分以独立于平台和语言的方式定义SOAP消息,它们并不包含任何随机器或语言而变的元素。这就定义了一系列服务,截然不同的应用都可以实现。具体部分,如数据的序列化则归入底部分,因为它包含具体的定义。在上述的文档元素中,<types>、<message>、<portType>属于抽象定义层,<binding>、<service>属于具体定义层。所有的抽象可以是单独存在于别的文件中,也可以从主文档中导入。
WSDL文档的结构实例解析
下面我们将通过一个实际的WSDL文档例子来详细说明各标签的作用及关系。
Java代码 收藏代码
<?xml version="1.0" encoding="UTF-8"?>
<definitions
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.jsoso.com/wstest"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.xmlsoap.org/wsdl/"
targetNamespace="http://www.jsoso.com/wstest"
name="Example">
<types>
<xsd:schema>
<xsd:import
namespace="http://www.jsoso.com/wstest"
schemaLocation="http://localhost:8080/hello?xsd=1"></xsd:import>
</xsd:schema>
</types>
<message name="toSayHello">
<part name="userName" type="xsd:string"></part>
</message>
<message name="toSayHelloResponse">
<part name="returnWord" type="xsd:string"></part>
</message>
<message name="sayHello">
<part name="person" type="tns:person"></part>
<part name="arg1" type="xsd:string"></part>
</message>
<message name="sayHelloResponse">
<part name="personList" type="tns:personArray"></part>
</message>
<message name="HelloException">
<part name="fault" element="tns:HelloException"></part>
</message>
<portType name="Example">
<operation name="toSayHello" parameterOrder="userName">
<input message="tns:toSayHello"></input>
<output message="tns:toSayHelloResponse"></output>
</operation>
<operation name="sayHello" parameterOrder="person arg1">
<input message="tns:sayHello"></input>
<output message="tns:sayHelloResponse"></output>
<fault message="tns:HelloException" name="HelloException"></fault>
</operation>
</portType>
<binding name="ExamplePortBinding" type="tns:Example">
<soap:binding
transport="http://schemas.xmlsoap.org/soap/http"
style="rpc"></soap:binding>
<operation name="toSayHello">
<soap:operation soapAction="sayHello"></soap:operation>
<input>
<soap:body use="literal"
namespace="http://www.jsoso.com/wstest"></soap:body>
</input>
<output>
<soap:body use="literal"
namespace="http://www.jsoso.com/wstest"></soap:body>
</output>
</operation>
<operation name="sayHello">
<soap:operation soapAction="sayHello"></soap:operation>
<input>
<soap:body use="literal"
namespace="http://www.jsoso.com/wstest"></soap:body>
</input>
<output>
<soap:body use="literal"
namespace="http://www.jsoso.com/wstest"></soap:body>
</output>
<fault name="HelloException">
<soap:fault name="HelloException" use="literal"></soap:fault>
</fault>
</operation>
</binding>
<service name="Example">
<port name="ExamplePort" binding="tns:ExamplePortBinding">
<soap:address location="http://localhost:8080/hello"></soap:address>
</port>
</service>
</definitions>
由于上面的事例XML较长,我们将其逐段分解讲解
WSDL文档的根元素:<definitions>
Java代码 收藏代码
<definitions
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.jsoso.com/wstest"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.xmlsoap.org/wsdl/"
targetNamespace="http://www.jsoso.com/wstest"
name="Example">
……
……
</definitions>
<definitions>定义了文档中用到的各个xml元素的namespace缩写,也界定了本文档自己的targetNamespace="http://www.jsoso.com/wstest",这意味着其它的XML要引用当前XML中的元素时,要声明这个namespace。注意xmlns:tns="http://www.jsoso.com/wstest"这个声明,它标示了使用tns这个前缀指向自身的命名空间。
引用
WSDL文档数据类型定义元素:<types>
Java代码 收藏代码
<types>
<xsd:schema>
<xsd:import
namespace="http://www.jsoso.com/wstest"
schemaLocation="http://localhost:8080/hello?xsd=1"></xsd:import>
</xsd:schema>
</types>
<types>标签定义了当前的WSDL文档用到的数据类型。要说明的是,为了最大程度的平台中立性,WSDL 使用 XML Schema 语法来定义数据类型。这些数据类型用来定义web service方法的参数和返回指。对于通用的原生数据类型如:integer , boolean , char , float等,在W3C的标准文档http://www.w3.org/2001/XMLSchema中已经做了定义。这里我们要引入的schema定义schemaLocation="http://localhost:8080/hello?xsd=1"是我们自定义的Java对象类型。
WSDL文档消息体定义元素:< message >
Java代码 收藏代码
<message name="toSayHello">
<part name="userName" type="xsd:string"></part>
</message>
<message name="toSayHelloResponse">
<part name="returnWord" type="xsd:string"></part>
</message>
<message name="sayHello">
<part name="person" type="tns:person"></part>
<part name="arg1" type="xsd:string"></part>
</message>
<message name="sayHelloResponse">
<part name="personList" type="tns:personArray"></part>
</message>
<message name="HelloException">
<part name="fault" element="tns:HelloException"></part>
</message>
<message>元素定义了web service函数的参数。<message>元素中的每个<part>子元素都和某个参数相符。输入参数在<message>元素中定义,与输出参数相隔离,输出参数有自己的<message>元素。兼作输入、输出的参数在输入输出的<message>元素中有它们相应的<part>元素。输出<message>元素以"Response"结尾,对Java而言方法得返回值就对应一个输出的<message>。每个<part>元素都有名字和类型属性,就像函数的参数有参数名和参数类型。
在上面的文档中有两个输入参数、两个输出参数和一个错误参数(对应Java中的Exception)。
输入参数<message>的name属性分别命名为toSayHello,sayHello。
toSayHello对应输入参数userName,参数类型为xsd:string,在Java语言中就是String;
sayHello对应两个输入参数person和arg1,类型为tns:person和xsd:string。这里tns:person类型就是引用了< types >标签中的类型定义。
输出参数<message>的name属性分别命名为toSayHelloResponse和sayHelloResponse。
这个名称和输入参数的<message>标签name属性对应,在其后面加上Response尾缀。
toSayHelloResponse对应的返回值是returnWord,参数类型为xsd:string;
sayHelloResponse对应的返回值是personList,参数类型为tns:personArray(自定义类型);
错误参数<message>的name属性为HelloException。
它的<part>子标签element而不是type来定义类型。
以上的message标签的name属性通常使用web service函数方法名作为参照,错误参数标签则使用异常类名为参照。标签中的参数名称,即part子元素的name属性是可自定义的(下一章节详细说明)。message标签的参数类型将引用types标签的定义。
WSDL文档函数体定义元素:< portType >
Java代码 收藏代码
<portType name="Example">
<operation name="toSayHello" parameterOrder="userName">
<input message="tns:toSayHello"></input>
<output message="tns:toSayHelloResponse"></output>
</operation>
<operation name="sayHello" parameterOrder="person arg1">
<input message="tns:sayHello"></input>
<output message="tns:sayHelloResponse"></output>
<fault message="tns:HelloException" name="HelloException"></fault>
</operation>
</portType>
<portType> 元素是最重要的 WSDL 元素。它可描述一个 web service、可被执行的操作,以及相关的消息。portType的name属性对应Java中的一个服务类的类名。<portType> 元素使用其子元素< operation>描述一个web service的服务方法。
在<operation>元素中,name属性表示服务方法名,parameterOrder属性表示方法的参数顺序,使用空格符分割多个参数,如:“parameterOrder="person arg1”。<operation>元素的子标签<input>表示输入参数说明,它引用<message>标签中的输入参数。<output>表示输出参数说明,它引用<message>标签中的输出参数。<fault>标签在Java方法中的特别用来表示异常(其它语言有对应的错误处理机制),它引用<message>标签中的错误参数。
WSDL绑定实现定义元素:< binding >
Java代码 收藏代码
<binding name="ExamplePortBinding" type="tns:Example">
<soap:binding
transport="http://schemas.xmlsoap.org/soap/http"
style="rpc"></soap:binding>
<operation name="toSayHello">
<soap:operation soapAction="sayHello"></soap:operation>
<input>
<soap:body use="literal"
namespace="http://www.jsoso.com/wstest"></soap:body>
</input>
<output>
<soap:body use="literal"
namespace="http://www.jsoso.com/wstest"></soap:body>
</output>
</operation>
<operation name="sayHello">
<soap:operation soapAction="sayHello"></soap:operation>
<input>
<soap:body use="literal"
namespace="http://www.jsoso.com/wstest"></soap:body>
</input>
<output>
<soap:body use="literal"
namespace="http://www.jsoso.com/wstest"></soap:body>
</output>
<fault name="HelloException">
<soap:fault name="HelloException" use="literal"></soap:fault>
</fault>
</operation>
</binding>
<binding>标签是完整描述协议、序列化和编码的地方,<types>,<message>和<portType>标签处理抽象的数据内容,而<binding>标签是处理数据传输的物理实现。
<binding>标签把前三部分的抽象定义具体化。
首先<binding>标签使用<soap:binding>的transport和style属性定义了Web Service的通讯协议HTTP和SOAP的请求风格RPC。其次<operation>子标签将portType中定义的operation同SOAP的请求绑定,定义了操作名称soapAction,输出输入参数和异常的编码方式及命名空间。
WSDL服务地址绑定元素:< service >
Java代码 收藏代码
<service name="Example">
<port name="ExamplePort" binding="tns:ExamplePortBinding">
<soap:address location="http://localhost:8080/hello"></soap:address>
</port>
</service>
service是一套<port>元素。在一一对应形式下,每个<port>元素都和一个location关联。如果同一个<binding>有多个<port>元素与之关联,可以使用额外的URL地址作为替换。
一个WSDL文档中可以有多个<service>元素,而且多个<service>元素十分有用,其中之一就是可以根据目标URL来组织端口。在一个WSDL文档中,<service>的name属性用来区分不同的service。在同一个service中,不同端口,使用端口的"name"属性区分。
这一章节,我们简单的描述了WSDL对SOAP协议的支持,以及在Web Service中的作用。在接下来的章节中,我们将学习如何使用Java6.0的Annotation标签来定义和生成对应的WSDL。
JavaSE6.0下的Web Service
从JavaSE6.0开始,Java引入了对Web Service的原生支持。我们只需要简单的使用Java的Annotation标签即可将标准的Java方法发布成Web Service。(PS:Java Annotation资料请参考 JDK5.0 Annotation学习笔记(一) )
但不是所有的Java类都可以发布成Web Service。Java类若要成为一个实现了Web Service的bean,它需要遵循下边这些原则:
这个类必须是public类
这些类不能是final的或者abstract
这个类必须有一个公共的默认构造函数
这个类绝对不能有finalize()方法
下面我们将通过一个具体的Java Web Service代码例子,配合上述的WSDL文件,讲述如何编写JavaSE6.0的原生Web Service应用。
完整的Java Web Service类代码
Java代码 收藏代码
package org.jsoso.jws.server;
import java.util.ArrayList;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.WebParam.Mode;
import javax.jws.soap.SOAPBinding;
/
* 提供WebService服务的类
*/
@WebService(name="Example", targetNamespace="http://www.jsoso.com/wstest", serviceName="Example")
@SOAPBinding(style=SOAPBinding.Style.RPC)
public class Example {
private ArrayList<Person> persons = new ArrayList<Person>();;
/**
*
* 返回一个字符串
* @param userName
* @return
*/
@WebMethod(operationName="toSayHello",action="sayHello",exclude=false)
@WebResult(name="returnWord")//自定义该方法返回值在WSDL中相关的描述
public String sayHello(@WebParam(name="userName")String userName) {
return "Hello:" + userName;
}
/**
* web services 方法的返回值与参数的类型不能为接口
* @param person
* @return
* @throws HelloException
*/
@WebMethod(operationName="sayHello", action="sayHello")
@WebResult(partName="personList")
public Person[] sayHello(@WebParam(partName="person", mode=Mode.IN)Person person,
String userName) throws HelloException {
if (person == null || person.getName() == null) {
throw new HelloException("说hello出错,对像为空。。");
}
System.out.println(person.getName() + " 对 " + userName + " 说:Hello,我今年" + person.getAge() + "岁");
persons.add(person);
return persons.toArray(new Person[0]);
}
}
Annotation 1@WebService(name="Example", targetNamespace="http://www.jsoso.com/wstest", serviceName="Example")
@WebService标签主要将类暴露为WebService,其中targetNamespace属性定义了自己的命名空间,serviceName则定义了< definitions >标签和<service>标签的name属性。
Annotation 2:@SOAPBinding(style=SOAPBinding.Style.RPC)
@SOAPBinding标签定义了WSDL文档中SOAP的消息协议,其中style属性对应SOAP的文档类型,可选的有RPC和DOCUMENT
Annotation 3:@WebMethod(operationName="toSayHello",action="sayHello",exclude=false)
@WebMethod定义Web Service运作的方法,
属性action 对应操作的活动 ,如<soap:operation soapAction="sayHello" />
属性operationName匹配的wsdl:operation 的名称,如<operation name="toSayHello" parameterOrder="userName">
属性exclude 用于阻止将某一继承方法公开为web服务,默认为false
Annotation 4:@WebResult(name="returnWord")
@ WebResult定义方法返回值得名称,如<part name="returnWord" type="xsd:string" />
Annotation 5:@WebParam(partName="person", mode=Mode.IN
@WebParam定义方法的参数名称,如<part name="person" type="tns:person" />,其中mode属性表示参数的流向,可选值有IN / OUT / INOUT
这里要着重说明的是,上述Web Service类的sayHello方法中,带有HelloException这个异常声明,造成该服务类不能直接发布成Web Service。需要使用wsgen工具为其生存异常Bean。关于wsgen工具的使用,请参考wsgen与wsimport命令说明
发布一个的Java Web Service
在完成了上述的Web Service Annotation注释后,我们使用wsgen工具为其进行服务资源文件的构造(这里主要是生成一个名为org.jsoso.jws.server.jaxws.HelloExceptionBean的异常bean类),最后使用以下的类发布Web 服务:
Java代码 收藏代码
package org.jsoso.jws.server;
import java.util.LinkedList;
import java.util.List;
import javax.xml.ws.Binding;
import javax.xml.ws.Endpoint;
import javax.xml.ws.handler.Handler;
/**
* @author zsy 启动web services服务
*/
public class StartServer {
/**
* @param args
*/
public static void main(String[] args) {
/*
* 生成Example 服务实例
*/
Example serverBean = new Example();
/*
* 发布Web Service到http://localhost:8080/hello地址
*/
Endpoint endpoint =
Endpoint.publish("http://localhost:8080/hello", serverBean);
Binding binding = endpoint.getBinding();
/*
* 设置一个SOAP协议处理栈
* 这里就简单得打印SOAP的消息文本
*/
List<Handler> handlerChain = new LinkedList<Handler>();
handlerChain.add(new TraceHandler());
binding.setHandlerChain(handlerChain);
System.out.println("服务已启动 http://localhost:8080/hello");
}
}
在控制台运行这个类,就可以使用URL :http://localhost:8080/hello?wsdl 浏览到上文所描述的WSDL的全文了。这说明您的第一个Web Service应用发布成功!
构建Web Service客户端
使用JavaSE6.0构建Web Service的客户端是一件相当简单的事。这里我们要使用到JDK中的另一个命令行工具wsimport。在控制台下输入以下命令:
引用
wsimport -d ./bin -s ./src -p org.jsoso.jws.client.ref http://localhost:8080/hello?wsdl
即可在包org.jsoso.jws.client.ref中生成客户端的存根及框架文件。其中我们要使用的类只有两个:服务类Example_Service和本地接口Example。编写如下客户端,即可调用Web Service服务:
Java代码 收藏代码
package org.jsoso.jws.client;
import org.jsoso.jws.client.ref.*;
public class RunClient {
/**
* @param args
*/
public static void main(String[] args) {
//初始化服务框架类
Example_Service service = new Example_Service();
//或者本地服务借口的实例
Example server = (Example) service.getExamplePort();
try {
//调用web service的toSayHello方法
System.out.println("输入toSayHello的返回值——" + server.toSayHello("阿土"));
Person person = new Person();
person.setName("阿土");
person.setAge(25);
//调用web service的sayHello方法
server.sayHello(person, "机器人");
person = new Person();
person.setName("aten");
person.setAge(30);
//调用web service的sayHello方法
PersonArray list = server.sayHello(person, "机器人");
//输出返回值
System.out.println("\n以下输入sayHello的返回值——");
for (Person p : list.getItem()) {
System.out.println(p.getName() + ":" + p.getAge());
}
} catch (HelloException_Exception e) {
e.printStackTrace();
}
}
}
届此,本次Web Service的学习暂告一个段落。Java Web Service是一个相当庞大的知识体系,其中涉及的相关技术较多,这里无法一一道来,我们将会在今后的开发和使用中,同大家做进一步深入的探讨和学习。
附录:wsgen与wsimport命令说明
wsgen
wsgen是在JDK的bin目录下的一个exe文件(Windows版),该命令的主要功能是用来生成合适的JAX-WS。它读取Web Service的终端类文件,同时生成所有用于发布Web Service所依赖的源代码文件和经过编译过的二进制类文件。这里要特别说明的是,通常在Web Service Bean中用到的异常类会另外生成一个描述Bean,如果Web Service Bean中的方法有申明抛出异常,这一步是必需的,否则服务器无法绑定该对像。此外,wsgen还能辅助生成WSDL和相关的xsd文件。wsgen从资源文件生成一个完整的操作列表并验证web service是否合法,可以完整发布。
命令参数说明:
-cp 定义classpath
-r 生成 bean的wsdl文件的存放目录
-s 生成发布Web Service的源代码文件的存放目录(如果方法有抛出异常,则会生成该异常的描述类源文件)
-d 生成发布Web Service的编译过的二进制类文件的存放目录(该异常的描述类的class文件)
命令范例:wsgen -cp ./bin -r ./wsdl -s ./src -d ./bin -wsdl org.jsoso.jws.server.Example
wsimport
wsimport也是在JDK的bin目录下的一个exe文件(Windows版),主要功能是根据服务端发布的wsdl文件生成客户端存根及框架,负责与Web Service 服务器通信,并在将其封装成实例,客户端可以直接使用,就像使用本地实例一样。对Java而言,wsimport帮助程序员生存调用web service所需要的客户端类文件.java和.class。要提醒指出的是,wsimport可以用于非Java的服务器端,如:服务器端也许是C#编写的web service,通过wsimport则生成Java的客户端实现。
命令参数说明:
-d 生成客户端执行类的class文件的存放目录
-s 生成客户端执行类的源文件的存放目录
-p 定义生成类的包名
发表评论
-
CXF整合spring入门helloworld
2014-01-02 10:31 1381下面的例子是摘抄的CXF官网的例子,然后自己动手测 ... -
CXF关于wsdl2java 生成 service class 构造器报错的解决办法
2013-03-11 17:29 11I'm marking this as "n ... -
CXF spring 整合
2013-03-06 18:40 900http://www.cnblogs.com/shenlia ... -
CXF 添加内容到 soap header 中
2013-03-06 16:26 4175http://huiseyiyu.iteye.com/blo ... -
webservice cxf 入门视频网站
2013-03-03 17:24 1292http://www.iteye.com/topic/30 ...
相关推荐
C# Web Service是一种基于.NET Framework的开发技术,用于创建分布式应用程序,使得不同系统间能够通过互联网进行通信。这种服务提供了一种标准化的方式,允许应用程序通过HTTP协议交换数据,因此,即使它们是由不同...
在《实战Delphi6/Kylix2/SOAP/Web Service程序设计篇》这本书中,作者李维精心编撰了一套系统而全面的教程,针对的是Delphi6和Kylix2这两个经典的Visual Basic derivative (VBD) 编程环境,尤其是针对SOAP(Simple ...
ASP.NET Web Service是一种基于.NET Framework的简单方法,用于构建可跨平台、跨语言通信的Web应用程序。这个例子是为初学者设计的,旨在演示如何创建和使用Web Service,以及如何在ASP.NET环境中调用这些服务。 ...
《T100 Web Service 接口开发v1.5版》 在现代信息技术领域,Web Service接口开发扮演着至关重要的角色,它使得不同系统之间的数据交换和功能调用变得简单而高效。本文将深入探讨T100 Web Service接口开发的最新版本...
标题"D6 SOAP_WEB SERVICE"指的是使用Delphi编程语言开发基于SOAP(简单对象访问协议)的Web服务。在本文中,我们将深入探讨这个主题,了解如何使用Delphi构建Web服务以及SOAP在其中的作用。 首先,让我们了解一下...
### Service Now Web Service知识点 #### 一、简介与概述 **Service Now Web Service**是一种集成解决方案,它允许不同应用程序之间通过网络进行通信。Service Now 支持多种类型的 Web 服务,包括作为提供者...
web service在第一次启动时出现启动缓慢的问题,通常是指在运行或访问web service时遇到的启动延迟现象。这种问题可能会在不同的web service应用中出现,尤其是在首次连接或部署新服务时更为常见。web service是一种...
本示例代码将帮助你理解和实现一个完整的Web Service程序。 首先,我们来看"xfire-client"部分。XFire是早先的一个Java Web Service框架,它简化了客户端和服务端的开发。在Java中,创建Web Service客户端通常涉及...
### Web Service应用实例详解 #### 一、IIS安装与配置 在开发Web Service之前,首先需要确保服务器上已正确安装并配置了Internet Information Services (IIS)。无论是Windows Server 2003还是Windows XP,IIS都是...
《实战Delphi6.Kylix2.SOAP.Web Service程序设计篇》是由知名技术专家李维编著的一本专业书籍,主要面向的是希望深入理解和应用Delphi6、Kylix2、SOAP以及Web Service技术的开发者。这本书详细介绍了如何利用这些...
Web Service Proxy Wizard 是一个工具,它为Visual Studio 6.0的开发者提供了一种方法,可以将Web服务封装成一个代理组件(.dll),这个组件可以在设计时通过早期绑定(Early Binding)像其他COM组件一样使用。...
Web Service编程是现代软件开发中的一个重要领域,尤其是在分布式系统和跨平台通信中。C#作为.NET框架的主要编程语言,提供了强大的工具和库来创建和消费Web Service。本篇将深入探讨C#环境下开发Web Service的相关...
本篇内容将深入探讨如何利用PB11来开发Web Service应用,这对于初学者来说是一份宝贵的资源。 一、Web Service基础 Web Service是一种基于开放标准的、平台无关的通信协议,它允许不同系统之间的数据交换。在PB11中...
VMware vSphere Web Service SDK开发指南是一份指导开发者如何使用VMware vSphere SDK进行开发的文档。VMware vSphere是VMware公司推出的业界领先虚拟化解决方案,它通过提供高级抽象层来管理和控制计算资源,为用户...
**Yahoo Web Service 2.11** Yahoo Web Service 2.11 是一个重要的API接口,它允许开发者利用Yahoo的在线资源和服务进行程序开发。这个版本可能是对之前版本的升级,可能包含了性能优化、新功能的添加以及已知问题...
### T100 Web Service 开发、调试及整合重启检查说明 #### 文件概述 本文件主要针对T100 Web Service的开发、调试以及在遇到问题时如何进行整合重启检查进行了详细说明。适用于T100项目的工程师和服务人员,帮助...
《实战Delphi6.Kylix2.SOAP.Web Service程序设计篇》是由知名技术专家李维撰写的一本专业书籍,主要涵盖了使用Delphi6和Kylix2进行SOAP(简单对象访问协议)以及Web Service开发的核心技术和实践应用。这本书是...