异构平台之间的交互
XML (DTDàSchema—>Stax(XStream)、SAX、Dom4J、PULL) JAXB
XStream和Jackson完成Json和java的转化
SOAP
Jax-ws(java api xml webservice)
CXF Rest Axis Metro
服务端:
SEI:Service Endpoint Interface
SIB:Service Implemention Bean
就是指接口和实现类
@WebService()
public interface IMyService {
@WebResult(name="addResult")
publicint add(@WebParam(name="a")int a,@WebParam(name="b")int b);
@WebResult(name="minusResult")
publicint minus(@WebParam(name="a")int a,@WebParam(name="b")intb);
@WebResult(name="loginUser")
publicUser login(@WebParam(name="username")Stringusername,@WebParam(name="password")String password);
}
@WebService(endpointInterface="org.zttc.service.IMyService")
public class MyServiceImpl implements IMyService {
@Override
publicint add(int a, int b) {
System.out.println(a+"+"+b+"="+(a+b));
returna+b;
}
@Override
publicint minus(int a, int b) {
System.out.println(a+"-"+b+"="+(a-b));
returna-b;
}
@Override
publicUser login(String username, String password) {
System.out.println(username+"is logining");
Useruser = new User();
user.setId(1);
user.setUsername(username);
user.setPassword(password);
returnuser;
}
}
public class MyServer {
publicstatic void main(String[] args) {
Stringaddress = "http://localhost:8888/ns";
Endpoint.publish(address,new MyServiceImpl());
}
}
如果没有使用annotation会报异常
出现WebService runtime modeler error:Wrapper class XXX is not found. Have you run APT to generate them异常解决办法:
1> 先用apt命令将主程序进行编译,然后生成一些java文件(比较麻烦,不建议使用)
2> 升级JDK到版本jdk1.6u17或以后
3>需要在public class XXX类上方加入@SOAPBinding(style = SOAPBinding.Style.RPC);
客户端:
public static void main(String[] args) {
try{
//创建访问wsdl服务地址的url
URLurl = new URL("http://localhost:8888/ns?wsdl");
//通过Qname指明服务的具体信息
QNamesname = new QName("http://service.zttc.org/","MyServiceImplService");
//创建服务
Serviceservice = Service.create(url,sname);
//实现接口
IMyServicems = service.getPort(IMyService.class);System.out.println(ms.add(12,33));
//以上服务有问题,依然依赖于IMyServie接口
}catch (MalformedURLException e) {
e.printStackTrace();
}
}
这种情况下可以使用wsimport访问webservice的地址得到接口的实现
客户端:在JDK的bin文件夹中,有一个wsimport.exe,这个工具依据wsdl文件生成相应的类文件,然后用这些类文件,就可以像调用 本地的类一样调用WebService提供的方。该工具可以用于非Java的服务器,如:用C#编写的WebService,通过wsimport则生成 Java的客户端实现。
在命令提示符中使用如下命令:wsimport -keep -p com.demo.clienthttp://localhost:8080/Demo/services/MyService?wsdl
命令参数说明:
-d:生成客户端执行类的class文件的存放目录
-s:生成客户端执行类的源文件的存放目录
-p:定义生成类的包名
代码优先:使用接口。。等方式的代码生成wsdl的xml
契约优先:先规定服务,定义契约,也就是标准,再根据契约编写代码 SOA(Service-Oriented Architecture)
服务的类型:
基于实体的服务:像学生奖惩信息的添加
基于功能的服务:天气预报
基于流程(业务)的服务:招生系统—财务系统--…..
编写Schema的三种方式:
1. Russia Roll(俄罗斯玩偶)
<?xmlversion="1.0" encoding="UTF-8"?>
<schemaxmlns="http://www.w3.org/2001/XMLSchema"targetNamespace="http://www.example.org/02"
xmlns:tns="http://www.example.org/02"elementFormDefault="qualified">
<element name="books">
<complexType>
<!-- maxOccurs表示最大出现次数-->
<sequencemaxOccurs="unbounded">
<elementname="book">
<complexType>
<sequenceminOccurs="1" maxOccurs="unbounded">
<elementname="title" type="string" />
<elementname="content" type="string" />
<choice>
<elementname="author" type="string" />
<elementname="authors">
<complexType>
<all><!--每个元素只能出现一次 -->
<elementname="author" type="string"/>
</all>
</complexType>
</element>
</choice>
</sequence>
<attributename="id" type="int" use="required"/>
</complexType>
</element>
</sequence>
</complexType>
</element>
</schema>
优点:结构清晰;缺点:类型不能重用
根据它写的xml文件
<?xmlversion="1.0" encoding="UTF-8"?>
<book:booksxmlns:book="http://www.example.org/02"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="02.xsd">
<book:book id="1">
<book:title>Java inaction</book:title>
<book:content>Java isgood</book:content>
<book:author>Bruce</book:author>
</book:book>
<book:book id="2">
<book:title>SOA inaction</book:title>
<book:content>soa isdifficult</book:content>
<book:authors>
<book:author>Jike</book:author>
</book:authors>
</book:book>
</book:books>
2. Salami Slice(腊肉切片)
<?xml version="1.0"encoding="UTF-8"?>
<schemaxmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/03"
xmlns:tns="http://www.example.org/03"
elementFormDefault="qualified">
<elementname="book" type="tns:bookType"></element>
<elementname="id" type="int"/>
<elementname="title" type="string"/>
<elementname="content" type="string"/>
<complexTypename="bookType">
<sequence>
<elementref="tns:id"/>
<elementref="tns:title"/>
<elementref="tns:content"/>
</sequence>
</complexType>
</schema>
优点:类型最大程度重用;缺点:结构不清晰,根节点都不好确定
<?xml version="1.0"encoding="UTF-8"?>
<titlexmlns="http://www.example.org/03"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.example.org/03">
12asdasdasd
</title>
3. Venetian Blind(百叶窗)
<?xml version="1.0"encoding="UTF-8"?>
<schemaxmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/04"
xmlns:tns="http://www.example.org/04"
elementFormDefault="qualified">
<elementname="person" type="tns:personType"/>
<complexTypename="personType">
<sequence>
<elementname="name" type="string"/>
<elementname="age" type="tns:ageType"/>
<elementname="email" type="tns:emailType"/>
</sequence>
<attributename="sex" type="tns:sexType"/>
</complexType>
<simpleTypename="emailType">
<restrictionbase="string">
<patternvalue="(\w+\.*)*\w+@\w+\.[A-Za-z]{2,6}"/>
<minLengthvalue="6"/>
<maxLengthvalue="255"/>
</restriction>
</simpleType>
<simpleTypename="ageType">
<restrictionbase="int">
<minInclusivevalue="1"/>
<maxExclusivevalue="150"/>
</restriction>
</simpleType>
<simpleTypename="sexType">
<restrictionbase="string">
<enumerationvalue="男"/>
<enumerationvalue="女"/>
</restriction>
</simpleType>
</schema>
根据以上写就的xml
<?xml version="1.0"encoding="UTF-8"?>
<personxmlns="http://www.example.org/04"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.example.org/04"sex="男">
<name>搜索</name>
<age>149</age>
<email>[email protected]</email>
</person>
最好的使用Schema的方式【一个Schema表示一个类,做到分离、模块化】
Student.xsd
<?xml version="1.0"encoding="UTF-8"?>
<xsd:schemaxmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/classroom"
xmlns:tns="http://www.example.org/classroom"
elementFormDefault="qualified">
<xsd:elementname="student" type="tns:studentType"/>
<xsd:complexTypename="studentType">
<xsd:sequence>
<xsd:elementname="name" type="xsd:string"/>
<xsd:elementname="sex" type="tns:sexType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:simpleTypename="sexType">
<xsd:restrictionbase="xsd:string">
<xsd:enumerationvalue="男"/>
<xsd:enumerationvalue="女"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
classroom.xsd
<?xml version="1.0"encoding="UTF-8"?>
<xsd:schemaxmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/classroom"
xmlns:tns="http://www.example.org/classroom"
elementFormDefault="qualified">
<xsd:includeschemaLocation="student.xsd"/>
<xsd:elementname="classroom" type="tns:classroomType"/>
<xsd:complexTypename="classroomType">
<xsd:sequence>
<xsd:elementname="grade" type="tns:gradeType"/>
<xsd:elementname="name" type="xsd:string"/>
<!-- <xsd:element name="stus">
<xsd:complexType>
<xsd:sequenceminOccurs="1" maxOccurs="unbounded">
<xsd:elementname="student" type="tns:studentType"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
-->
<xsd:sequenceminOccurs="1" maxOccurs="unbounded">
<xsd:elementname="student" type="tns:studentType"/>
</xsd:sequence>
</xsd:sequence>
</xsd:complexType>
<xsd:simpleTypename="gradeType">
<xsd:restrictionbase="xsd:int">
<xsd:minInclusivevalue="2000"/>
<xsd:maxInclusivevalue="3000"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
使用xjc生成Java类
SOAP【更底层的一种访问webservice方式,比用wsimport得到的接口更底层】
SAAJ(SOAP ATTACHMENT API 4 JAVA)
SOAP消息的创建
//1、创建消息工厂
MessageFactoryfactory = MessageFactory.newInstance();
//2、根据消息工厂创建SoapMessage
SOAPMessagemessage = factory.createMessage();
//3、创建SOAPPart
SOAPPartpart = message.getSOAPPart();
//4、获取SOAPENvelope
SOAPEnvelopeenvelope = part.getEnvelope();
//5、可以通过SoapEnvelope有效的获取相应的Body和Header等信息
SOAPBodybody = envelope.getBody();
//6、根据Qname创建相应的节点(QName就是一个带有命名空间的)
QNameqname = new QName("http://java.zttc.edu.cn/webservice",
"add","ns");//<ns:addxmlns="http://java.zttc.edu.cn/webservice"/>
//如果使用以下方式进行设置,会见<>转换为<和>
//body.addBodyElement(qname).setValue("<a>1</a><b>2</b>");
SOAPBodyElementele = body.addBodyElement(qname);
ele.addChildElement("a").setValue("22");
ele.addChildElement("b").setValue("33");
//打印消息信息
message.writeTo(System.out);
SOAP消息的传递【基于soap消息方式】
//1、创建服务(Service)
URLurl = new URL(wsdlUrl);
QNamesname = new QName(ns,"MyServiceImplService");
Serviceservice = Service.create(url,sname);
//2、创建Dispatch
Dispatch<SOAPMessage>dispatch = service.createDispatch(newQName(ns,"MyServiceImplPort"),SOAPMessage.class,Service.Mode.MESSAGE);
//3、创建SOAPMessage
SOAPMessage msg = MessageFactory.newInstance().createMessage();
SOAPEnvelopeenvelope = msg.getSOAPPart().getEnvelope();
SOAPBody body =envelope.getBody();
//4、创建QName来指定消息中传递数据
QName ename =new QName(ns,"add","nn");//<nn:addxmlns="xx"/>
SOAPBodyElementele = body.addBodyElement(ename);
ele.addChildElement("a").setValue("22");
ele.addChildElement("b").setValue("33");
msg.writeTo(System.out);
System.out.println("\ninvoking.....");
//5、通过Dispatch传递消息,会返回响应消息
SOAPMessageresponse = dispatch.invoke(msg);
response.writeTo(System.out);
System.out.println();
//将响应的消息转换为dom对象
Document doc =response.getSOAPPart().getEnvelope().getBody().extractContentAsDocument();
Stringstr = doc.getElementsByTagName("addResult").item(0).getTextContent();
System.out.println(str);
传递复杂数据【基于payload方式】
//1、创建服务(Service)
URLurl = new URL(wsdlUrl);
QNamesname = new QName(ns,"MyServiceImplService");
Serviceservice = Service.create(url,sname);
//2、创建Dispatch(通过源数据的方式传递)
Dispatch<Source>dispatch = service.createDispatch(new QName(ns,"MyServiceImplPort"),
Source.class,Service.Mode.PAYLOAD);
//3、根据用户对象创建相应的xml
Useruser = new User(3,"zs","张三","11111");
JAXBContextctx = JAXBContext.newInstance(User.class);
Marshallermar = ctx.createMarshaller();
mar.setProperty(Marshaller.JAXB_FRAGMENT,true);
StringWriterwriter= new StringWriter();
mar.marshal(user,writer);
//4、封装相应的part addUser
Stringpayload = "<nn:addUserxmlns:nn=\""+ns+"\">"+writer.toString()+"</nn:addUser>";
System.out.println(payload);
StreamSourcers = new StreamSource(new StringReader(payload));
//5、通过dispatch传递payload
Sourceresponse = (Source)dispatch.invoke(rs);
//6、将Source转化为DOM进行操作,使用Transform对象转换
Transformertran = TransformerFactory.newInstance().newTransformer();
DOMResultresult = new DOMResult();
tran.transform(response,result);
//7、处理相应信息(通过xpath处理)
XPathxpath = XPathFactory.newInstance().newXPath();
NodeList nl =(NodeList)xpath.evaluate("//user", result.getNode(),XPathConstants.NODESET);
Userru = (User)ctx.createUnmarshaller().unmarshal(nl.item(0));
System.out.println(ru.getNickname());
@Test
publicvoid test04() {
try{
//1、创建服务(Service)
URLurl = new URL(wsdlUrl);
QNamesname = new QName(ns,"MyServiceImplService");
Serviceservice = Service.create(url,sname);
//2、创建Dispatch
Dispatch<SOAPMessage>dispatch = service.createDispatch(new QName(ns,"MyServiceImplPort"),
SOAPMessage.class,Service.Mode.MESSAGE);
//3、创建SOAPMessage
SOAPMessagemsg = MessageFactory.newInstance().createMessage();
SOAPEnvelopeenvelope = msg.getSOAPPart().getEnvelope();
SOAPBodybody = envelope.getBody();
//3.2、处理header信息
SOAPHeaderheader = envelope.getHeader();
if(header==null)header = envelope.addHeader();
QNamehname = new QName(ns,"authInfo","nn");
header.addHeaderElement(hname).setValue("aabbccdd");
//4、创建QName来指定消息中传递数据
QNameename = new QName(ns,"list","nn");//<nn:addxmlns="xx"/>
body.addBodyElement(ename);
msg.writeTo(System.out);
System.out.println("\ninvoking.....");
//5、通过Dispatch传递消息,会返回响应消息
SOAPMessageresponse = dispatch.invoke(msg);
response.writeTo(System.out);
System.out.println();
//将响应的消息转换为dom对象
Documentdoc = response.getSOAPBody().extractContentAsDocument();
NodeListnl = doc.getElementsByTagName("user");
JAXBContextctx = JAXBContext.newInstance(User.class);
for(inti=0;i<nl.getLength();i++) {
Noden = nl.item(i);
Useru = (User)ctx.createUnmarshaller().unmarshal(n);
System.out.println(u.getNickname());
}
}catch (SOAPException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}catch (JAXBException e) {
e.printStackTrace();
}
}
@Test
publicvoid test05() {
try{
//1、创建服务(Service)
URLurl = new URL(wsdlUrl);
QNamesname = new QName(ns,"MyServiceImplService");
Serviceservice = Service.create(url,sname);
//2、创建Dispatch
Dispatch<SOAPMessage>dispatch = service.createDispatch(new QName(ns,"MyServiceImplPort"),
SOAPMessage.class,Service.Mode.MESSAGE);
//3、创建SOAPMessage
SOAPMessagemsg = MessageFactory.newInstance().createMessage();
SOAPEnvelopeenvelope = msg.getSOAPPart().getEnvelope();
SOAPBodybody = envelope.getBody();
//4、创建QName来指定消息中传递数据
QNameename = new QName(ns,"login","nn");//<nn:addxmlns="xx"/>
SOAPBodyElementele = body.addBodyElement(ename);
ele.addChildElement("username").setValue("ss");
ele.addChildElement("password").setValue("dd");
msg.writeTo(System.out);
System.out.println("\ninvoking.....");
//5、通过Dispatch传递消息,会返回响应消息
SOAPMessageresponse = dispatch.invoke(msg);
response.writeTo(System.out);
System.out.println();
}catch(SOAPFaultException e){
System.out.println(e.getMessage());
}catch (SOAPException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
}
封装SoapException处理Webservice异常
Webservice客户端使用一个WebMethod时,如果WebMethod内部出现异常,不管异常是系统级异常或者自定义的异常,均会被包装为SoapException类型的异常,返回给客户端。 客户端再使用这种SoapException时,无法直接从异常类的属性中提取直接的业务异常信息。
网上看到有同学是做了一个SoapException的Helper类,利用正则表达式的方式,从SoapException的属性做文法分析,从中提取业务异常信息。可是感觉这种方法不是很.Net,而且是不保险的一种做法,如果是自定义异常之类的,在做文法分析时可能会有隐患。而且不能更好的体现错误号。
仔细研究了SoapException之后,发现它有个detail属性,可以利用这个Xml文档类型的节点实现较好的异常信息封包。
步骤如下:
一、(服务端)建立 SoapException 的封包方法
/// <summary>
/// 异常类型
/// </summary>
public enum FaultCode
{
Client = 0,
Server = 1
}
/// <summary>
/// 封装异常为SoapException
/// </summary>
/// <param name="uri">引发异常的方法uri</param>
/// <param name="errorMessage">错误信息</param>
/// <param name="errorNumber">错误号</param>
/// <param name="errorSource">错误源</param>
/// <param name="code">异常类型</param>
/// <returns>封装后的SoapException</returns>
public SoapException RaiseException(
string uri,
string errorMessage,
string errorNumber,
string errorSource,
FaultCode code
)
{
//初始化限定名
XmlQualifiedName faultCodeLocation = null;
//异常类型代码转换
switch (code)
{
case FaultCode.Client:
faultCodeLocation = SoapException.ClientFaultCode;
break;
case FaultCode.Server:
faultCodeLocation = SoapException.ServerFaultCode;
break;
}
//构建异常信息结构体
string strXmlOut = @"<detail>"
+ "<Error>"
+ "<ErrorNumber>" + errorNumber + "</ErrorNumber>"
+ "<ErrorMessage>" + errorMessage + "</ErrorMessage>"
+ "<ErrorSource>" + errorSource + "</ErrorSource>"
+ "</Error>"
+ "</detail>";
//装载为Xml文档
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(strXmlOut);
//实例化SoapException
SoapException soapEx = new SoapException(errorMessage, faultCodeLocation, uri, xmlDoc.DocumentElement);
//返回SoapException
return soapEx;
}
二、(服务端)WebMethod的异常处理中调用此方法。例如:
/// <summary>
/// 根据ID读取人员信息
/// </summary>
/// <returns>人员信息类</returns>
[WebMethod(Description = "根据ID读取人员信息")]
public PersonInfo WSReadPersonByID(int ID)
{
try
{
PersonMethod personMethod = new PersonMethod();
return personMethod.ReadPersonByID(ID);
}
catch (System.Exception ex)
{
throw RaiseException(
"WSReadPersonByID",
ex.Message,
"1000",
ex.Source,
FaultCode.Server
);
}
}
三、(客户端)建立SoapException的信息解析类
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Xml;
using System.Web.Services.Protocols;
/// <summary>
/// SoapException 信息解析类
/// </summary>
public class SoapExceptionInfo
{
/// <summary>
/// 错误号
/// </summary>
public string ErrorNumber = string.Empty;
/// <summary>
/// 错误信息
/// </summary>
public string ErrorMessage = string.Empty;
/// <summary>
/// 错误源
/// </summary>
public string ErrorSource = string.Empty;
/// <summary>
/// SoapExceptionInfo构造方法
/// </summary>
public SoapExceptionInfo()
{
}
/// <summary>
/// SoapExceptionInfo构造方法
/// </summary>
/// <param name="soapEx">SoapException</param>
public SoapExceptionInfo(SoapException soapEx)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(soapEx.Detail.OuterXml);
XmlNode categoryNode = doc.DocumentElement.SelectSingleNode("Error");
this.ErrorNumber = categoryNode.SelectSingleNode("ErrorNumber").InnerText;
this.ErrorMessage = categoryNode.SelectSingleNode("ErrorMessage").InnerText;
this.ErrorSource = categoryNode.SelectSingleNode("ErrorSource").InnerText;
}
}
四、(客户端)使用WebMethod时,使用 SoapException的信息解析类方法
public PersonInfo ReadByID(int id)
{
try
{
WSDemoService ws = new WSDemoService();
ws.Credentials = System.Net.CredentialCache.DefaultCredentials;
return ws.WSReadPersonByID(id);
}
catch (SoapException soapEx)
{
SoapExceptionInfo soapExInfo = new SoapExceptionInfo(soapEx);
throw new System.Exception(soapExInfo.ErrorMessage);
}
catch (Exception ex)
{
throw ex;
}
}
handler的处理
处理顺序:不管我们怎么定义,处理顺序都是
先写信----信封-----打开信封(验证权限等)----处理内容
客户端
1、创建一个类实现SOAPHandler<SOAPMessageContext>
public class HeaderHandler implementsSOAPHandler<SOAPMessageContext> {
@Override
publicboolean handleMessage(SOAPMessageContext context) {
try{
Stringns = "http://service.soap.org/";
Booleanout = (Boolean)context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if(out){
SOAPMessagemessage = context.getMessage();
//1、判断message中是否存在header
SOAPEnvelopeenve = message.getSOAPPart().getEnvelope();
SOAPBodybody = enve.getBody();
Nodenode = body.getChildNodes().item(0);
Stringpn = node.getLocalName();
if("list".equals(pn)||"addUser".equals(pn)){
SOAPHeaderheader = enve.getHeader();
if(header==null)header = enve.addHeader();
QNameqname = new QName(ns, "licenseInfo","ns");
header.addHeaderElement(qname).setValue("123123");
message.writeTo(System.out);
}
}
}catch (SOAPException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
returntrue;
}
@Override
publicboolean handleFault(SOAPMessageContext context) {
System.out.println("error");
returnfalse;
}
@Override
publicvoid close(MessageContext context) {
}
@Override
publicSet<QName> getHeaders() {
returnnull;
}
}
2、增加过滤链配置文件【类路径下handler-chain.xml】
<?xml version="1.0"encoding="UTF-8" standalone="yes"?>
<javaee:handler-chains
xmlns:javaee="http://java.sun.com/xml/ns/javaee"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<javaee:handler-chain>
<javaee:handler>
<javaee:handler-class>org.soap.service.handler.HeaderHandler</javaee:handler-class>
</javaee:handler>
</javaee:handler-chain>
</javaee:handler-chains>
3、在wsimport生成的service类中增加annotation
客户端测试是否添加了header信息
利用eclipse自带的TCPMon
服务端
第一种方式和客户端差不多
public class LicenseHandler implementsSOAPHandler<SOAPMessageContext> {
@Override
publicboolean handleMessage(SOAPMessageContext context) {
try{
Booleanout = (Boolean)context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if(!out){
SOAPMessagemessage = context.getMessage();
SOAPEnvelopeenve = message.getSOAPPart().getEnvelope();
SOAPHeaderheader = enve.getHeader();
SOAPBodybody = enve.getBody();
Nodebn = body.getChildNodes().item(0);
Stringpartname = bn.getLocalName();
if("list".equals(partname)||"addUser".equals(partname)){
if(header==null){
//添加一个错误信息
System.out.println("ttt");
SOAPFaultfault = body.addFault();
fault.setFaultString("头部信息不能为空!");
thrownew SOAPFaultException(fault);
}
Iterator<SOAPHeaderElement>iterator = header.extractAllHeaderElements();
if(!iterator.hasNext()){
//添加一个错误信息
System.out.println("ttt");
SOAPFaultfault = body.addFault();
fault.setFaultString("头部信息不正确!");
thrownew SOAPFaultException(fault);
}
while(iterator.hasNext()){
SOAPHeaderElementele = iterator.next();
System.out.println(ele.getTextContent());
}
}
}
}catch (SOAPException e) {
e.printStackTrace();
}
returntrue;
}
@Override
publicboolean handleFault(SOAPMessageContext context) {
returnfalse;
}
@Override
publicvoid close(MessageContext context) {
}
@Override
publicSet<QName> getHeaders() {
returnnull;
}
}
RPC对于基本类型不做封装,像User这种复杂类型才做封装
Doc方式将这两个参数封装成add这个parameter,就可以添加一些限制
RPC不封装简单类型 ,不能做限制
契约优先的编写流程
在classpath下面创建META-INF/wsdl
一、基本概念
编写WSDL有三种方式:基于document的Wrapper方式,基于document的Bare方式,基于RPC方式。本例介绍Wraper方式,也是默认方式和推荐方式。Wrapper有包起来的意思,将所有对象通过element封装。
RPC的方式也挺好的,因为它更直观,但是它的类型我们不好方便地定义、限制和校验。
二、编写步骤
①服务端
1、编写WSDL
<?xml version="1.0" encoding="UTF-8"standalone="no"?>
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.example.org/hello/"xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
name="HelloService"
targetNamespace="http://www.example.org/hello/">
<wsdl:types>
<xsd:schematargetNamespace="http://www.example.org/hello/">
<xsd:element name="add"type="tns:add"></xsd:element>
<xsd:element name="addResponse"type="tns:addResponse"></xsd:element>
<xsd:element name="licenceInfo"type="tns:licenceInfo"></xsd:element>
<xsd:complexTypename="add">
<xsd:sequence>
<xsd:element name="a"type="xsd:int"></xsd:element>
<xsd:element name="b"type="xsd:int"></xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexTypename="addResponse">
<xsd:sequence>
<xsd:element name="addResponse"type="xsd:int"></xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="licenceInfo">
<xsd:sequence>
<xsd:element name="licenceInfo"type="xsd:string"></xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
</wsdl:types>
<wsdl:message name="add">
<wsdl:part name="add"element="tns:add"></wsdl:part>
</wsdl:message>
<wsdl:message name="addResponse">
<wsdl:part name="addResponse"element="tns:addResponse"></wsdl:part>
</wsdl:message>
<wsdl:message name="licenceInfo">
<wsdl:part name="licenceInfo"element="tns:licenceInfo"></wsdl:part>
</wsdl:message>
<wsdl:portType name="IHelloService">
<wsdl:operation name="add">
<wsdl:input message="tns:add"></wsdl:input>
<wsdl:output message="tns:addResponse"></wsdl:output>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="HelloServiceSOAP"type="tns:IHelloService">
<soap:binding style="document"transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="add">
<wsdl:input>
<soap:body use="literal" />
<soap:headeruse="literal"part="licenceInfo"message="tns:licenceInfo"></soap:header>
//这里就可以任意添加头信息
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="HelloService">
<wsdl:port binding="tns:HelloServiceSOAP"name="HelloServicePort">
<soap:address location="http://localhost:8080/hello" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
2、通过wsimport生成java文件,将生成的java类文件复制到项目中一般在src下新建MATE-INF/WSDL两层文件夹,将文件放进去。
3、删除生成的java文件,只保留生成的接口的.java文件,删除该文件中不需要的代码。注意不要拷贝.class文件进去,因为将来如果要在tomcat里面部署,多余的.class文件会让程序报错。
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.ws.RequestWrapper;
import javax.xml.ws.ResponseWrapper;
/**
* This class was generated by the JAX-WS RI.
* JAX-WS RI 2.1.1 in JDK 6
* Generated source version: 2.1
*
*/
@WebService(name = "Hello", targetNamespace ="http://www.example.org/hello/")
public interface IHelloService{
@WebMethod
@WebResult(name = "addResponse", targetNamespace ="")
@RequestWrapper(localName = "add", targetNamespace ="http://www.example.org/hello/", className ="org.example.hello.Add")
@ResponseWrapper(localName = "addResponse",targetNamespace = "http://www.example.org/hello/", className ="org.example.hello.AddResponse")
public int add(
@WebParam(name = "a", targetNamespace ="")
int a,
@WebParam(name = "b", targetNamespace = "")
int b ,
@WebParam(name="licenceInfo" ,header=true) String licenceInfo);
}
4、编写HelloServiceImpl类
@WebService(endpointInterface ="org.example.hello.Hello",
serviceName = "HelloService" , wsdlLocation ="META-INF/wsdl/hello.wsdl" ,
targetNamespace ="http://www.example.org/hello/", portName="HelloServicePort")
public class HelloServiceImpl implements IHelloService {
public int add(int a, int b, String licenceInfo) {
System.out.println(a+b);
System.out.println("licenceInfo:" + licenceInfo );
return a + b;
}
}
5、发布service
import javax.xml.ws.Endpoint;
import org.example.hello.HelloServiceImpl;
public class ServiceTest {
public static void main(String[] args) {
Endpoint.publish("http://localhost:8080/mywebservice",new HelloServiceImpl());
}
}
其实服务端完全没有必要用接口,使用它的唯一原因就是使用其annotation,避免自己手动添加
②编写客户端
将wsimort生成的java类添加到客户端。
1、普通方式访问(无法传递头信息,当然可以通过另外编写Handler添加头信息)
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import org.example.hello.Hello;
public class Client01 {
public static void main(String[] args) throws Exception{
URL url = newURL("http://localhost:8080/mywebservice?wsdl");
String namespace = "http://www.example.org/hello/";
QName sname = new QName(namespace, "HelloService");
Service service = Service.create(url, sname);
IHelloService hello = service.getPort(IHelloService.class);
int result = hello.add(1, 100);
System.out.println(result);
// 或直接调用生成的方法(这是另一个例子,可以仿照写)
// MyServiceImplService mis =new MyServiceImplService();
// IMyService ms = mis.getMyServiceImplPort();
// System.out.println(ms.add(29, 3));
}
}
2、拼装SOAPMessage方式访问 (有头信息)
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPBodyElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
public class Client02 {
/**
* 带Header的请求
*/
public static void main(String[] args) throws Exception{
URL url = new URL("http://localhost:8080/mywebservice?wsdl");
String namespace = "http://www.example.org/hello/";
QName sname = new QName(namespace , "HelloService");
Service service = Service.create(url, sname);
QName protName = new QName(namespace, "HelloServicePort");
Dispatch<SOAPMessage> dispatch =service.createDispatch(protName,SOAPMessage.class, Service.Mode.MESSAGE);
SOAPMessage msg = MessageFactory.newInstance().createMessage() ;
SOAPEnvelope env = msg.getSOAPPart().getEnvelope() ;
SOAPBody body = env.getBody() ;
SOAPHeader header = env.getHeader() ;
if(header == null) header = env.addHeader() ;
// 一定要加ns前缀
QName addName = new QName(namespace , "add" , "myprefix");
// 添加Body信息
SOAPBodyElement bodyEle = body.addBodyElement(addName);
bodyEle.addChildElement("a").setValue("1");
bodyEle.addChildElement("b").setValue("2");
// 添加头信息
QName headerName = new QName(namespace , "licenceInfo");
// 设置头信息的值
header.addHeaderElement(headerName).setTextContent("admin");
// 发送前将soap消息打印出来
msg.writeTo(System.out);
System.out.println("----------------relult---------------");
SOAPMessage resultMsg = dispatch.invoke(msg);
// 将返回的soap消息打印出来
resultMsg.writeTo(System.out) ;
}
}
原帖地址:http://blog.csdn.net/is_zhoufeng/article/details/8365723
做一个小实例(用户管理)
首先写WSDL(,Schema)
在类路径下新建文件夹META-INF/wsdl
<?xmlversion="1.0" encoding="UTF-8"standalone="no"?>
<wsdl:definitions
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://service.zttc.edu.cn"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
name="UserService"
targetNamespace="http://service.zttc.edu.cn">
<!-- wrappered推荐使用的方式,全部封装 -->
<wsdl:types>
<xsd:schematargetNamespace="http://service.zttc.edu.cn">
如果太多可以通过另外的文件(schema)引入
<!-- <xsd:importnamespace="http://service.zttc.edu.cn"schemaLocation="user.xsd"></xsd:import> -->
<!-- <xsd:includeschemaLocation="user.xsd"></xsd:include> -->
<xsd:elementname="add" type="tns:add"></xsd:element>
<xsd:elementname="addResponse"type="tns:addResponse"></xsd:element>
<xsd:elementname="delete" type="tns:delete"></xsd:element>
<xsd:elementname="deleteResponse"type="tns:deleteResponse"></xsd:element>
<xsd:elementname="list" type="tns:list"></xsd:element>
<xsd:elementname="listResponse"type="tns:listResponse"></xsd:element>
<xsd:elementname="login" type="tns:login"></xsd:element>
<xsd:elementname="loginResponse"type="tns:loginResponse"></xsd:element>
<xsd:element name="UserException"type="tns:UserException"></xsd:element>
<xsd:complexTypename="UserException">
<xsd:sequence>
<xsd:elementname="message" type="xsd:string"></xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexTypename="add">
<xsd:sequence>
<xsd:elementname="user" type="tns:user"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexTypename="addResponse">
<xsd:sequence/>
</xsd:complexType>
<xsd:complexTypename="delete">
<xsd:sequence>
<xsd:elementname="username" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexTypename="deleteResponse">
<xsd:sequence/>
</xsd:complexType>
<xsd:complexTypename="list">
<xsd:sequence/>
</xsd:complexType>
<xsd:complexTypename="listResponse">
<xsd:sequenceminOccurs="1" maxOccurs="unbounded">
<xsd:elementname="user" type="tns:user"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexTypename="login">
<xsd:sequence>
<xsd:elementname="username" type="xsd:string"/>
<xsd:elementname="password" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexTypename="loginResponse">
<xsd:sequence>
<xsd:elementname="user" type="tns:user"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexTypename="user">
<xsd:sequence>
<xsd:elementname="username" type="xsd:string"/>
<xsd:elementname="password" type="xsd:string"/>
<xsd:elementname="nickname" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
</wsdl:types>
<wsdl:message name="UserException">
<wsdl:partname="fault"element="tns:UserException"></wsdl:part>
</wsdl:message>
<wsdl:message name="add">
<wsdl:part element="tns:add"name="parameters"/>
</wsdl:message>
<wsdl:messagename="addResponse">
<wsdl:partelement="tns:addResponse" name="parameters"/>
</wsdl:message>
<wsdl:message name="delete">
<wsdl:partelement="tns:delete" name="parameters"/>
</wsdl:message>
<wsdl:message name="deleteResponse">
<wsdl:partelement="tns:deleteResponse" name="parameters"/>
</wsdl:message>
<wsdl:message name="list">
<wsdl:part element="tns:list"name="parameters"/>
</wsdl:message>
<wsdl:messagename="listResponse">
<wsdl:partelement="tns:listResponse" name="parameters"/>
</wsdl:message>
<wsdl:message name="login">
<wsdl:part element="tns:login"name="parameters"/>
</wsdl:message>
<wsdl:messagename="loginResponse">
<wsdl:partelement="tns:loginResponse" name="parameters"/>
</wsdl:message>
<wsdl:portType name="IUserService">
<wsdl:operation name="add">
<wsdl:inputmessage="tns:add"/>
<wsdl:outputmessage="tns:addResponse"/>
<wsdl:fault name="UserException" message="tns:UserException"></wsdl:fault>
</wsdl:operation>
<wsdl:operationname="delete">
<wsdl:inputmessage="tns:delete"/>
<wsdl:outputmessage="tns:deleteResponse"/>
</wsdl:operation>
<wsdl:operationname="list">
<wsdl:inputmessage="tns:list"/>
<wsdl:outputmessage="tns:listResponse"/>
</wsdl:operation>
<wsdl:operationname="login">
<wsdl:inputmessage="tns:login"/>
<wsdl:outputmessage="tns:loginResponse"/>
<wsdl:fault name="UserException"message="tns:UserException"></wsdl:fault>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="userServiceSOAP"type="tns:IUserService">
<soap:binding style="document"transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="add">
<wsdl:input>
<soap:bodyuse="literal"/>
</wsdl:input>
<wsdl:output>
<soap:bodyuse="literal"/>
</wsdl:output>
<wsdl:fault name="UserException">
<soap:fault name="UserException"use="literal"/>
</wsdl:fault>
</wsdl:operation>
<wsdl:operationname="delete">
<wsdl:input>
<soap:bodyuse="literal"/>
</wsdl:input>
<wsdl:output>
<soap:bodyuse="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operationname="list">
<wsdl:input>
<soap:bodyuse="literal"/>
</wsdl:input>
<wsdl:output>
<soap:bodyuse="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operationname="login">
<wsdl:input>
<soap:bodyuse="literal"/>
</wsdl:input>
<wsdl:output>
<soap:bodyuse="literal"/>
</wsdl:output>
<wsdl:fault name="UserException">
<soap:fault name="UserException"use="literal"/>
</wsdl:fault>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="UserService">
<wsdl:port binding="tns:userServiceSOAP"name="UserServicePort">
<soap:address location="http://localhost:9898/us/"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
<?xmlversion="1.0" encoding="UTF-8"standalone="no"?>
<wsdl:definitions
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://service.zttc.edu.cn"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
name="UserService"
targetNamespace="http://service.zttc.edu.cn">
<!--RPC的方式,全部不封装,使用type -->
<wsdl:types>
<xsd:schematargetNamespace="http://service.zttc.edu.cn">
<!--<xsd:import namespace="http://service.zttc.edu.cn"schemaLocation="user.xsd"></xsd:import> -->
<!--<xsd:include schemaLocation="user.xsd"></xsd:include>-->
<xsd:complexTypename="user">
<xsd:sequence>
<xsd:elementname="username" type="xsd:string"/>
<xsd:elementname="password" type="xsd:string"/>
<xsd:elementname="nickname" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexTypename="listUser">
<xsd:sequencemaxOccurs="unbounded" minOccurs="1">
<xsd:element name="user"type="tns:user"></xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
</wsdl:types>
<wsdl:message name="add">
<wsdl:part name="user" type="tns:user"/>
</wsdl:message>
<wsdl:message name="addResponse"/>
<wsdl:message name="delete">
<wsdl:part type="xsd:string"name="username"/>
</wsdl:message>
<wsdl:messagename="deleteResponse"/>
<wsdl:message name="list">
</wsdl:message>
<wsdl:messagename="listResponse">
<wsdl:part name="user"type="tns:listUser">
</wsdl:part>
</wsdl:message>
<wsdl:message name="login">
<wsdl:part type="xsd:string"name="username"/>
<wsdl:part type="xsd:string"name="password"/>
</wsdl:message>
<wsdl:message name="loginResponse">
<wsdl:part name="user"type="tns:user"/>
</wsdl:message>
<wsdl:portTypename="IUserService">
<wsdl:operation name="add">
<wsdl:inputmessage="tns:add"/>
<wsdl:outputmessage="tns:addResponse"/>
</wsdl:operation>
<wsdl:operationname="delete">
<wsdl:inputmessage="tns:delete"/>
<wsdl:outputmessage="tns:deleteResponse"/>
</wsdl:operation>
<wsdl:operationname="list">
<wsdl:inputmessage="tns:list"/>
<wsdl:outputmessage="tns:listResponse"/>
</wsdl:operation>
<wsdl:operation name="login"parameterOrder="username password">
<wsdl:inputmessage="tns:login"/>
<wsdl:outputmessage="tns:loginResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:bindingname="userServiceSOAP" type="tns:IUserService">
<soap:binding style="rpc"transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="add">
<wsdl:input>
<soap:body use="literal"namespace="http://service.zttc.edu.cn"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"namespace="http://service.zttc.edu.cn"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operationname="delete">
<wsdl:input>
<soap:body use="literal"namespace="http://service.zttc.edu.cn"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"namespace="http://service.zttc.edu.cn"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operationname="list">
<wsdl:input>
<soap:body use="literal"namespace="http://service.zttc.edu.cn"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"namespace="http://service.zttc.edu.cn"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operationname="login">
<wsdl:input>
<soap:body use="literal"namespace="http://service.zttc.edu.cn"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"namespace="http://service.zttc.edu.cn"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:servicename="UserService">
<wsdl:portbinding="tns:userServiceSOAP" name="UserServicePort">
<soap:addresslocation="http://localhost:9898/us/"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
<?xmlversion="1.0" encoding="UTF-8"standalone="no"?>
<wsdl:definitions
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://service.zttc.edu.cn"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
name="UserService"
targetNamespace="http://service.zttc.edu.cn">
<!--
Document-》bare不进行封装的类型
-->
<wsdl:types>
<xsd:schematargetNamespace="http://service.zttc.edu.cn">
<!--<xsd:import namespace="http://service.zttc.edu.cn"schemaLocation="user.xsd"></xsd:import> -->
<!--<xsd:include schemaLocation="user.xsd"></xsd:include>-->
<xsd:elementname="user" type="tns:user"></xsd:element>
<xsd:elementname="username" type="xsd:string"></xsd:element>
<xsd:elementname="loginResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:elementname="user" type="tns:user"></xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:elementname="login">
<xsd:complexType>
<xsd:sequence>
<xsd:elementname="username" type="xsd:string"></xsd:element>
<xsd:elementname="password" type="xsd:string"></xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:elementname="listResponse">
<xsd:complexType>
<xsd:sequenceminOccurs="1" maxOccurs="unbounded">
<xsd:elementname="user" type="tns:user"></xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexTypename="user">
<xsd:sequence>
<xsd:elementname="username" type="xsd:string"/>
<xsd:elementname="password" type="xsd:string"/>
<xsd:elementname="nickname" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
</wsdl:types>
<wsdl:message name="add">
<wsdl:part element="tns:user" name="user"/>
</wsdl:message>
<wsdl:messagename="addResponse"/>
<wsdl:message name="delete">
<wsdl:partelement="tns:username" name="username"/>
</wsdl:message>
<wsdl:messagename="deleteResponse"/>
<wsdl:message name="list"/>
<wsdl:messagename="listResponse">
<wsdl:partelement="tns:listResponse" name="parameters"/>
</wsdl:message>
<wsdl:message name="login">
<wsdl:part element="tns:login"name="parameters"/>
</wsdl:message>
<wsdl:messagename="loginResponse">
<wsdl:partelement="tns:loginResponse" name="parameters"/>
</wsdl:message>
<wsdl:portTypename="IUserService">
<wsdl:operation name="add">
<wsdl:inputmessage="tns:add"/>
<wsdl:outputmessage="tns:addResponse"/>
</wsdl:operation>
<wsdl:operationname="delete">
<wsdl:inputmessage="tns:delete"/>
<wsdl:outputmessage="tns:deleteResponse"/>
</wsdl:operation>
<wsdl:operationname="list">
<wsdl:inputmessage="tns:list"/>
<wsdl:outputmessage="tns:listResponse"/>
</wsdl:operation>
<wsdl:operationname="login">
<wsdl:inputmessage="tns:login"/>
<wsdl:outputmessage="tns:loginResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:bindingname="userServiceSOAP" type="tns:IUserService">
<soap:binding style="document"transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="add">
<wsdl:input>
<soap:bodyuse="literal"/>
</wsdl:input>
<wsdl:output>
<soap:bodyuse="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operationname="delete">
<wsdl:input>
<soap:bodyuse="literal"/>
</wsdl:input>
<wsdl:output>
<soap:bodyuse="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operationname="list">
<wsdl:input>
<soap:bodyuse="literal"/>
</wsdl:input>
<wsdl:output>
<soap:bodyuse="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operationname="login">
<wsdl:input>
<soap:bodyuse="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:servicename="UserService">
<wsdl:portbinding="tns:userServiceSOAP" name="UserServicePort">
<soap:addresslocation="http://localhost:9898/us/"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
然后通过wsimport导入源码,写实现类,在实现类上添加wsdlLocation
注意考入的时候不要考入class文件
@WebService(endpointInterface="cn.edu.zttc.service.IUserService",
wsdlLocation="WEB-INF/wsdl/user.wsdl",
serviceName="UserService",
portName="UserServicePort",
targetNamespace="http://service.zttc.edu.cn")
public class UserServiceImpl implements IUserService {
private UserDaouserDao = UserDao.newInstance();
@Override
public void add(Useruser) throws UserException {
userDao.add(user);
}
@Override
public voiddelete(String username) {
userDao.delete(username);
}
@Override
publicList<User> list() {
returnuserDao.list();
}
@Override
public Userlogin(String username, String password) throws UserException {
returnuserDao.login(username, password);
}
}
public class UserDao {
private static finalMap<String,User> users = new HashMap<String,User>();
private static UserDaodao = null;
private UserDao() {
users.put("admin",newUser("admin","123","超级管理员"));
}
public static UserDaonewInstance() {
if(dao==null)dao =new UserDao();
return dao;
}
public void add(Useruser) throws UserException {
if(users.containsKey(user.getUsername()))thrownew UserException("用户已经存在了");
users.put(user.getUsername(),user);
}
public voiddelete(String username) {
users.remove(username);
}
publicList<User> list() {
Set<String>keys = users.keySet();
List<User>list = new ArrayList<User>();
for(Stringkey:keys) {
list.add(users.get(key));
}
return list;
}
public Userlogin(String username,String password) throws UserException {
if(!users.containsKey(username))thrownew UserException("用户不存在");
User u =users.get(username);
if(!password.equals(u.getPassword()))thrownew UserException("用户密码不正确!");
return u;
}
}
public class UserException extends Exception {//不能是RuntimeException
public UserException(){
super();
}
publicUserException(String message, Throwable cause) {
super(message,cause);
}
publicUserException(String message) {
super(message);
}
publicUserException(Throwable cause) {
super(cause);
}
}
Web Service概述
Web Service的定义
W3C组织对其的定义如下,它是一个软件系统,为了支持跨网络的机器间相互操作交互而设计。Web Service服务通常被定义为一组模块化的API,它们可以通过网络进行调用,来执行远程系统的请求服务。
这里我们从一个程序员的视角来观察web service。在传统的程序编码中,存在这各种的函数方法调用。通常,我们知道一个程序模块M中的方法A,向其发出调用请求,并传入A方法需要的参数P,方法A执行完毕后,返回处理结果R。这种函数或方法调用通常发生在同一台机器上的同一程序语言环境下。现在的我们需要一种能够在不同计算机间的不同语言编写的应用程序系统中,通过网络通讯实现函数和方法调用的能力,而Web service正是应这种需求而诞生的。
最普遍的一种说法就是,Web Service = SOAP 【SOAP协议,通过XML描述】+ HTTP【网络传输】 + WSDL【公布服务】。【通过HTTP按照SOAP协议传输XML,XML按照WSDL写】其中,SOAPSimple 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 引用【schema】
SOAP 消息不能包含 XML 处理指令
SOAP 消息的基本结构
XML/HTML代码
<? 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 元素中,并会被应用到元素的内容及元素的所有子元素上。
XML/HTML代码
<? 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",则要求处理此头部的接收者必须认可此元素。
XML/HTML代码
<? 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,也可以是用户的应用程序自定义的元素。以下是一个用户定义的请求:
XML/HTML代码
<? 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 响应应该类似这样:
SOAP Fault 元素
Fault 元素表示 SOAP的错误消息。它必须是 Body 元素的子元素,且在一条 SOAP 消息中,Fault 元素只能出现一次。Fault 元素拥有下列子元素:
常用的SOAP Fault Codes
HTTP协议中的SOAP 实例
下面的例子中,一个 GetStockPrice 请求被发送到了服务器。此请求有一个 StockName 参数,而在响应中则会返回一个 Price 参数。此功能的命名空间被定义在此地址中: "http://www.jsoso.net/stock"
SOAP 请求:(注意HTTP的Head属性)
XML/HTML代码
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属性)
XML/HTML代码
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文档例子来详细说明各标签的作用及关系。
XML/HTML代码
<?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>
<messagename="toSayHello">
【{returnWord}String toSayHello(String {username})】
<part name="userName"type="xsd:string"></part>
</message>
<messagename="toSayHelloResponse">
<part name="returnWord"type="xsd:string"></part>
</message>
<message name="sayHello">
【{personList } personArray sayHello(Person {person},String {arg1})throws HelloException】
<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>
<messagename="HelloException">
<part name="fault"element="tns:HelloException"></part>
</message>
<portType name="Example">
<operation name="toSayHello" parameterOrder="userName">
<input message="tns:toSayHello"></input>
<outputmessage="tns:toSayHelloResponse"></output>
</operation>
<operation name="sayHello" parameterOrder="personarg1">
<input message="tns:sayHello"></input>
<outputmessage="tns:sayHelloResponse"></output>
<faultmessage="tns:HelloException"name="HelloException"></fault>
</operation>
</portType>
<bindingname="ExamplePortBinding" type="tns:Example">
<soap:binding
transport="http://schemas.xmlsoap.org/soap/http"
style="rpc"></soap:binding>
<operation name="toSayHello">
<soap:operationsoapAction="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>
<faultname="HelloException">
<soap:faultname="HelloException"use="literal"></soap:fault>
</fault>
</operation>
</binding>
<service name="Example">
<port name="ExamplePort"binding="tns:ExamplePortBinding">
<soap:addresslocation="http://localhost:8080/hello"></soap:address>
</port>
</service>
</definitions>
由于上面的事例XML较长,我们将其逐段分解讲解
WSDL文档的根元素:<definitions>
XML/HTML代码
<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这个前缀指向自身的命名空间。【以tns作为前缀访问】
引用
WSDL文档数据类型定义元素:<types>
XML/HTML代码
<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语法来定义数据类型。这些数据类型用来定义webservice方法的参数和返回值。对于通用的原生数据类型如:integer , boolean , char , float等,在W3C的标准文档http://www.w3.org/2001/XMLSchema中已经做了定义。这里我们要引入的schema定义schemaLocation="http://localhost:8080/hello?xsd=1"是我们自定义的Java对象类型。 【w3c标准的数据类型和自己定义的值对象类型】
WSDL文档消息体定义元素:< message >【每一个操作都是一个消息,包括Fault】
XML/HTML代码
<messagename="toSayHello">
<part name="userName"type="xsd:string"></part>
</message>
<messagename="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>
<messagename="sayHelloResponse">
<part name="personList"type="tns:personArray"></part>
</message>
<messagename="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 >
XML/HTML代码
<portTypename="Example">
<operation name="toSayHello"parameterOrder="userName">
<input message="tns:toSayHello"></input>
<outputmessage="tns:toSayHelloResponse"></output>
</operation>
<operation name="sayHello" parameterOrder="personarg1">
<input message="tns:sayHello"></input>
<outputmessage="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 >
XML/HTML代码
<bindingname="ExamplePortBinding" type="tns:Example">
<soap:binding
transport="http://schemas.xmlsoap.org/soap/http"
style="rpc"></soap:binding>
<operation name="toSayHello">
<soap:operationsoapAction="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:operationsoapAction="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 >
XML/HTML代码
<servicename="Example">
<port name="ExamplePort"binding="tns:ExamplePortBinding">
<soap:addresslocation="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。
但不是所有的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服务的类 其实应该有一个接口的,接口中定义了许多的annotation,在实现的时候就不需要了
*/
@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")StringuserName) {
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
【RPC不封装、Document完全封装、Document Bare方式部分封装】
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的全文了。这说明您的第一个WebService应用发布成功!
构建Web Service客户端
使用JavaSE6.0构建Web Service的客户端是一件相当简单的事。这里我们要使用到JDK中的另一个命令行工具wsimport。在控制台下输入以下命令:
引用【生成客户端需要的类】
wsimport -d ./bin -s ./src -p org.jsoso.jws.client.refhttp://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 -wsdlorg.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 定义生成类的包名
命令范例:wsimport -d ./bin -s ./src -p org.jsoso.jws.client.refhttp://localhost:8080/hello?wsdl