点击打开链接:个人笔记 包括的内容有: wb的发布和客户端的调用 免费web服务常用连接:http://www.webxml.com.cn/zh_cn/web_services.aspx 客户端调用网上服务的例子 分析rpc/document_ware/document_ba
包括的内容有: wb的发布和客户端的调用 免费web服务常用连接:http://www.webxml.com.cn/zh_cn/web_services.aspx 客户端调用网上服务的例子 分析rpc/document_ware/document_bare的不同的参数交互方式。 webserivce的其他数据格式的传递与交互(date map Bean list String)。 wb的异常处理 1.: webservice中的名词介绍:
1.1:与WebServices 相关的 J2EE 技术称为 JWS(Java WebServices), 其中含有 JAX-WS、JAX-RS、JAXB、JAXR、SAAJ、 StAX等技术。
1.2:xml: 可扩展性标记语言。
1.3:XSD:是指XML结构定义 ( XML Schemas Definition ), XML Schema 是DTD的替代品。XML Schema语言也就是XSD。
XML Schema描述了XML文档的结构。一个XML Schema会定义:文档中出现的元素、文档中出现的属性、 子元素、子元素的数量、子元素的顺序、元素是否为空、元素和属性的数据类型、元素或属性的默认和固定值。
1.4:SOAP 即 Simple Object AccessProtocol 也就是简单对象访问协议。因为 SOAP基于XML和HTTP , 其通过XML 来实现消息描述,然后再通过 HTTP 实现消息传输。所以SOAP 是用于在应用程序之间进行通信的一种通信协议。
1.5:WSDL 即Web Services Description Language也就是 Web 服务描述语言。
是基于 XML的用于描述 Web 服务以及如何访问 Web 服务的语言。它里面定义了web服务所使用的方法、变量名、返回值、url 等。看WSDL这个文件时从下往上看。
1.6:JAXB(Java API for XML Binding)即XML元素跟Java对象之间的绑定。JAXP(Java API for XML Processing)包括了对 XML的解析、校验、查询、变换。JAXM(Java API for XML Messaging简称JAXM)是为Java平台上的应用程序定义的API,
用以通过XML(以及SOAP)发送和接收消息,支持同步消息和异步消息。SAAJ支持带附件的SOAP消息。SAAJ是JAXM下的一个 分支。 1.7:jax-rpc/jax-ws/jax-rs
支持 SOAP 的是JAX-RPC/JAX-WS方式,支持REST的是JAX-RS 2: webservice的实现方式: jax-ws/xfire/cxf/axis2等 3: 发布一个最简单的webservie以及客户端的调用方式: 3.1 首先得创建发布一个webservice,先创建一个Java工程,在com.webservice这个包下创建一个接口FirstService并且在接口类名 前加上@WebService这个注解(表明这是一个Web服务接口)和在接口中定义一些方法。再在这个包里创建一个First实现类,实现的接 口为前面创建的接口。并且要在First类的前面加上@WebService(endpointInterface = "com.webservice.FirstService")来说 明它实现的服务接口类是哪个。结构是:
Endpoint.publish(address, implementor);其中的address是webservice的访问地址,可以随意填写,第二个参数是new一个实 现对象。访问的时候address加上?WSDL。
3.2: 客户端调用服务端: 有三种方式(1.代理模式2.sope消息的方式3.客户端桩的模式)
都得先创建一个Java工程名叫WebServiceClient01. 3.2.1:代理模式 先将服务端的接口类拷到客户端中。
再写调用类:
3.2.2: 客户端桩的模式:通过WSDL地址,或者WSDL文件,生成客户端的调用类
一:使用MyEclipse工具来生成{内部调用jdk的命令}
二:通过jdk自带的命令来生成。
二:通过jdk自带的命令来生成
-d <directory> 指定放置生成的输出文件的位置
-keep 保留生成的文件
-p <pkg> 指定目标程序包 -verbose 有关编译器在执行什么操作的输出消息 先在e盘建一个名叫test_service的文件夹, 再在jdk的目录下用命令行来运行总的执行命令是: D:\jdk\bin>wsimport -d E:\test_service -p com.client -keep -verbose http://localhost:5050/first?wsdl
然后在到E:\test_service\com\client里把.class的都删了。再把com包整个拷到一个Java工程名叫WebServiceClient01里。
最后写调用类:
一:使用MyEclipse工具来生成
先在工程中建一个包名叫com.myeclipse,再在这个包上右键点击-->other-->Web Service Client点击后进行下一步下一 步。
注意:生成客户端的时候,服务端一定要处于发布状态,不然可能会生成失败。
最后写调用类:
3.3:发送原始的Soap消息:Http协议中,通过Soap协议来发送XML数据的消息格式。这种消息格式称为Soap消息。
3.4:还有其它两种
1:利用开源的工具(CXF,AXis2)也提供相应的调用方法。 2:Http协议中,通过Soap协议来发送XML数据的消息格式
利用开源Commont-httpClient来模拟HTTP请求,发送XML的消息格式。 4:注解:
@WebResult(name="returnWord") 接口的返回值 @WebParam(name="cityName")接口的参数
5:免费web服务常用连接: http://www.webxml.com.cn/zh_cn/web_services.aspx
6:例子:客户端调用网上的服务
因为是调用网上的,所以用wsdl地址生成客户端时会有错,所以一般情况下都是用wsdl文件。
步骤: 先建一个名叫wsdl的文件夹,再在这个文件夹里建一个带有.wsdl后缀的文件(chinese_to_english.wsdl)。
再把网上的那个wsdl地址里的内容复制到chinese_to_english.wsdl。
删除里面的中文描述和过时的标签。 最后像利用wsdl地址生成那样生成客户端文件。生成完后,wsdl文件夹就可以删了。 最后的最后就是写调用类啦! 7: 分析rpc/document_ware/document_bare的不同的参数交互方式。 rpc:@SOAPBinding(style = SOAPBinding.Style.RPC)即远程调用模式,rpc没有bare模式。
RPC模式下,方法中的参数与返回值,直接定义在message元素中。
<message name="add">
<part name="x" type="xsd:int"/>
<part name="y" type="xsd:int"/>
</message>
<message name="addResponse">
<part name="addResult" type="xsd:int"/>
</message>
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"/>
document_bare:@SOAPBinding(style = SOAPBinding.Style.DOCUMENT,
parameterStyle = SOAPBinding.ParameterStyle.BARE)
注意点:bare模式下,webservice的方法只能有一个参数。
Bare模式下,方法中的参数与返回值,直接在xsd文件中使用type来做声明。
<message name="divide">
//name为方法参数的名称 element为直接引用xsd中定义的元素。
<part name="x" element="tns:x"/>
</message>
<message name="divideResponse">
<part name="divideResult" element="tns:divideResult"/>
</message>
<xs:element name="divideResult" type="xs:int"/>
<xs:element name="x" type="xs:int"/>
document_warpper:封装格式。message方法中可以传递多个参数。
每一个参数都使用了封装类型。
<xs:element name="add" type="tns:add" /> //tns:add又引用下面定义的complexType类型。
<xs:element name="addResponse" type="tns:addResponse" />
<xs:element name="divide" type="tns:divide" />
<xs:element name="divideResponse" type="tns:divideResponse" />
<xs:complexType name="add">
<xs:sequence>
<xs:element name="x" type="xs:int" />
<xs:element name="y" type="xs:int" />
</xs:sequence> </xs:complexType> 8.webserivce的其他数据格式的传递与交互。 日期类型/Bean/List/Map接口如何处理: 日期类型:服务端是java中的日期类型。java.util.Date Soap消息中传递是XML中的日期类型。XMLGregorianCalendar XMLGregorianCalendar---->GregorianCalendar----->Date---->格式化成字符串。 Map:服务端是Map类型,但是WSDL定义的是List类型。 将Map做为WebSevice的数据传递时,不能再放入其他的复杂数据类型,如自定义的一些类型。 注意:一般情况下我们不会使用这些复杂的类型,而是使用String这种基本的类型。 8.1:日期类型:客户端测试代码:
package com.date; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.GregorianCalendar;
import javax.xml.datatype.XMLGregorianCalendar;
import com.sun.org.apache.xerces.internal.jaxp.datatype.XMLGregorianCalendarImpl;
public class TestMain { public static void main(String[] args) { TestMain testMain = new TestMain();
// testMain.get();
testMain.set(); }
private void get() { IDateService dateService = new DateImplService().getDateImplPort(); /** * XML元素中的日历对象 */ XMLGregorianCalendar xmlCalendar = dateService.getSysDate(); int year = xmlCalendar.getYear(); int month = xmlCalendar.getMonth(); System.out.println(year + "-" + month); /** * 转成java中的日历对象 */ GregorianCalendar calendar = xmlCalendar.toGregorianCalendar(); Date date = calendar.getTime(); DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("接收服务端返回的日期 = " + dateFormat.format(date));
}
private void set() { /** * java中的日历对象 */ Date date = new Date(2015-1900, 6, 7, 11, 12, 14); GregorianCalendar calendar = new GregorianCalendar(); calendar.setTime(date); /** * 转为XML中的日历对象 */ XMLGregorianCalendar xmlCalendar = new XMLGregorianCalendarImpl( calendar); IDateService dateService = new DateImplService().getDateImplPort(); dateService.setClient(xmlCalendar);
} } 服务端实现类的代码:
package com.webservice;
import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date;
import javax.jws.WebService;
@WebService(endpointInterface = "com.webservice.IDateService") public class DateImpl implements IDateService {
public Date getSysDate() { Date date = new Date(); return date; }
public void setClient(Date date) {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String strTime = dateFormat.format(date);
System.out.println("接收到客户端传递的Date数据 = " + strTime);
}
}
8.2: 将Map做为WebSevice的数据传递时 服务器端实现类的代码: package sss.webservice;
import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.Map.Entry;
import javax.jws.WebService; @WebService(endpointInterface = "sss.webservice.IMapService") public class MapImpl implements IMapService {
@Override public Map<String, Object> getMap() { Map<String, Object> map = new HashMap<String, Object>(); map.put("key1", "hahah"); map.put("key2", new Date()); return map; } @Override public void setMap(Map<String, Object> map) { if(map!=null){ Set<Entry<String, Object>> entries = map.entrySet(); for (Entry<String, Object> entry : entries) { String keyString = entry.getKey(); Object object = entry.getValue(); System.out.println("从客户端发送过来的数据:"+keyString+" "+object); } } }
}
客户端测试类的代码:
package sss.Map;
import java.util.Date; import java.util.List; import java.util.Map; import sss.Map.*; import sss.Map.GetMapResponse.GetMapResult; import sss.Map.GetMapResponse.GetMapResult.Entry;
public class TestMain { public static void main(String[] args) { TestMain testMain = new TestMain(); //testMain.get(); testMain.set(); }
private void get() { IMapService iMapService = new MapImplService().getMapImplPort(); GetMapResult gMapResult = iMapService.getMap(); List<sss.Map.GetMapResponse.GetMapResult.Entry> list = gMapResult.getEntry(); for (Entry entry : list) { String keyString = entry.getKey(); Object object = entry.getValue(); System.out.println("服务器端发来的数据:"+keyString + " "+object); } }
private void set() { IMapService iMapService = new MapImplService().getMapImplPort(); SetMap.Map map = new SetMap.Map(); List<sss.Map.SetMap.Map.Entry> list = map.getEntry(); //注意每一个entry都得另外新创建,不然list里就只有一个entry sss.Map.SetMap.Map.Entry entry = new sss.Map.SetMap.Map.Entry(); entry.setKey("key1"); entry.setValue("hahah"); list.add(entry); sss.Map.SetMap.Map.Entry entry1 = new sss.Map.SetMap.Map.Entry(); entry1.setKey("time"); entry1.setValue(new Date()); list.add(entry1); iMapService.setMap(map); } }
8.3: 将String做为WebSevice的数据传递时,可以把String封装成xml或json格式。 服务端代码: package com.webservice;
import javax.jws.WebService;
@WebService(endpointInterface = "com.webservice.IStrService") public class StrImpl implements IStrService { //服务端的接口实现类 public String getXMLStr() { StringBuffer xmlStr = new StringBuffer(); xmlStr.append("<root>"); xmlStr.append("<head>"); xmlStr.append(""); xmlStr.append("</head>"); xmlStr.append("<body>"); xmlStr.append("<userbean>"); xmlStr.append("<userid>1</userid><username>用户名</username>"); xmlStr.append("</userbean>"); xmlStr.append("</body>"); xmlStr.append("</root>"); return xmlStr.toString(); }
public void setStrList(String xmlStr) { }
}
客户端代码:
package com.str;
import java.io.StringReader;
import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; //客户端测试类 public class TestMain { public static void main(String[] args) { TestMain.get(); } private static void get() { IStrService strService = new StrImplService().getStrImplPort(); String xmlStr = strService.getXMLStr(); System.out.println("xmlStr = " + xmlStr); // 解析XML的字符串 Dom4j try { SAXReader reader = new SAXReader(); Document document = reader.read(new StringReader(xmlStr)); Element userBean = (Element) document .selectSingleNode("/root/body/userbean"); String userid = userBean.elementText("userid"); String username = userBean.elementText("username"); System.out.println(userid + "\t" +username); } catch (Exception e) { e.printStackTrace(); } } }
注意: 解析XML的字符串时可以用dom4j,要记得拷相应的jar包。 9.异常处理: wsdl中会把编译异常当作消息来处理,而运行时异常则不当作消息来处理。 正规情况下我们是抛编译异常,但我们一般都是抛运行时异常,也就是让我们交互不成功,双方都报错。 WebService中的自定义异常时,一般继承Exception,不继承RunTimeException 原因:继承Exception,WebService会将异常在wsdl中定义为一个message. 出现异常时,会将异常封装成为一个Soap消息传递给客户端。客户端就会获取到异常消息。 继承RunTimeException:服务端会抛异常,客户端接到的不是具体的异常。 是Soap中默认的异常。SoapFaultException 服务端代码: 服务端接口 package sss.webservice; import java.util.Date;
import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; //服务端接口 @WebService public interface IExceptionService { @WebResult(name = "addResult") public int add(@WebParam(name = "x")int x,@WebParam(name = "y")int y)throws Exception; @WebResult(name = "subResult") public int sub(@WebParam(name = "x")int x,@WebParam(name = "y")int y)throws RuntimeException; @WebResult(name = "divideResult") public int divide(@WebParam(name = "x")int x,@WebParam(name = "y")int y)throws DivideException; }
接口实现类
package sss.webservice;
import javax.jws.WebService; //服务端接口实现类 @WebService(endpointInterface = "sss.webservice.IExceptionService") public class ExceptionImpl implements IExceptionService {
@Override public int add(int x, int y) throws Exception { if(x == 0 || y == 0){ throw new Exception("Exception:add中的X或Y不能为0。。。"); } else return x+y; }
@Override public int sub(int x, int y) throws RuntimeException { if(x == 0 || y == 0){ throw new RuntimeException("RuntimeException:sub中的X或Y不能为0。。。"); } else return x+y;
}
@Override public int divide(int x, int y) throws DivideException { if(x == 0 || y == 0){ throw new DivideException("DivideException:divide中的X或Y不能为0。。。"); } else return x+y; }
}
客户端测试类:
package sss.Exception; //客户端测试类 public class TestMain { public static void main(String[] args) { TestMain testMain = new TestMain(); //testMain.add(); //testMain.sub(); testMain.didv(); }
private void add() { // 服务端没有异常 // 客户端:com.exception.Exception_Exception //这种抛编译异常的方式结果是客户端和服务端交互成功, //当服务端发生错误的时候,会把错误抛给客户端,所以导致最后服务端没有报错,而只有客户端报错。 //这种异常的使用只有常规的时候会使用,不然一般情况下是不会使用的。 IExceptionService iExceptionService = new ExceptionImplService().getExceptionImplPort(); try { iExceptionService.add(0, 10); } catch (Exception_Exception e) { System.out.println(e.getFaultInfo().getMessage()); e.printStackTrace(); }
}
private void sub() { // 服务端的异常:java.lang.RuntimeException // 客户端的异常:javax.xml.ws.soap.SOAPFaultException 交互不成功异常 //这种抛出运行异常的方式是使客户端和服务端交互不成功, //并且告诉双方你们出错的原因 //我们普遍都是使用这种方式。 IExceptionService iExceptionService = new ExceptionImplService().getExceptionImplPort(); iExceptionService.sub(0, 10); }
private void didv() { //和抛出编译异常的效果是一样的。 IExceptionService exceptionService = new ExceptionImplService() .getExceptionImplPort();
try { exceptionService.divide(1, 0); } catch (DivideException_Exception e) { System.out.println(e.getFaultInfo().getMessage()); e.printStackTrace(); }
} }