1 :WebService基础笔记 ? ?使用本机IP练习
无论你的服务端是什么语言书写的,只要接收SOAP协议的XML数据,并返回SOAP协议的XML数据,就可以被任何语言调用。
?
1.1?????常用名词介绍:
l? 名词1:XML.Extensible Markup Language -扩展性标记语言
???? XML,用于传输格式化的数据,是Web服务的基础。
???? namespace-命名空间。
???? xmlns=“http://itcast.cn” 使用默认命名空间。
???? xmlns:itcast=“http://itcast.cn”使用指定名称的命名空间。
???? ?
l? 名词2:WSDL –WebService Description Language – Web服务描述语言。
???? 通过XML形式说明服务在什么地方-地址。
???? 通过XML形式说明服务提供什么样的方法 – 如何调用。
???? ?
l? 名词3:SOAP-SimpleObject Access Protocol(简单对象访问协议)
???? SOAP作为一个基于XML语言的协议用于有网上传输数据。
???? SOAP = 在HTTP的基础上+XML数据。
???? SOAP是基于HTTP的。
???? SOAP的组成如下:
???? Envelope – 必须的部分。以XML的根元素出现。
???? Headers – 可选的。
???? Body – 必须的。在body部分,包含要执行的服务器的方法。和发送到服务器的数据。
?
?
1.2?????WSDL介绍
?
?
? <?xml version="1.0" encoding="UTF8" ?> <definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" ???????? xmlns:tns="http://ws.itcast.cn/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" ???????? xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://ws.itcast.cn/" ???????? name="HelloServiceService"> ???????? <types> ?????????????????? <xsd:schema> ??????????????????????????? <xsd:import namespace="http://ws.itcast.cn/" ???????????????????????????????????? schemaLocation="http://localhost:9999/hello?xsd=1" /> ?????????????????? </xsd:schema> ???????? </types> ???????? <message name="sayHi"> ?????????????????? <part name="parameters" element="tns:sayHi" /> ???????? </message> ???????? <message name="sayHiResponse"> ?????????????????? <part name="parameters" element="tns:sayHiResponse" /> ???????? </message> ???????? <portType name="HelloService"> ?????????????????? <operation name="sayHi"> ??????????????????????????? <input message="tns:sayHi" /> ??????????????????????????? <output message="tns:sayHiResponse" /> ?????????????????? </operation> ???????? </portType> ???????? <binding name="HelloServicePortBinding" type="tns:HelloService"> ?????????????????? <soap:binding transport="http://schemas.xmlsoap.org/soap/http" ??????????????????????????? style="document" /> ?????????????????? <operation name="sayHi"> ??????????????????????????? <soap:operation soapAction="" /> ??????????????????????????? <input> ???????????????????????????????????? <soap:body use="literal" /> ??????????????????????????? </input> ??????????????????????????? <output> ???????????????????????????????????? <soap:body use="literal" /> ??????????????????????????? </output> ?????????????????? </operation> ???????? </binding> ???????? <service name="HelloServiceService"> ?????????????????? <port name="HelloServicePort" binding="tns:HelloServicePortBinding"> ??????????????????????????? <soap:address location="http://localhost:9999/hello" /> ?????????????????? </port> ???????? </service> </definitions> ? ? |
?
1.3????SOAP协议的范本:
1.3.1??请求示例:
?
POST /WebServices/MobileCodeWS.asmx HTTP/1.1 Host: webservice.webxml.com.cn Content-Type: text/xml; charset=utf-8 Content-Length: length SOAPAction: "http://WebXml.com.cn/getMobileCodeInfo" <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ???????? ?????????? xmlns:xsd="http://www.w3.org/2001/XMLSchema" ??????????????????????????? ?? xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <getMobileCodeInfo xmlns="http://WebXml.com.cn/"> <mobileCode>string</mobileCode> <userID>string</userID> </getMobileCodeInfo> </soap:Body> </soap:Envelope> ? |
?
?
1.3.2?SOAP协议:-响应示例:
响应的信息,同发送信息一样,先必须是HTTP协议,然后再遵循SOAP协议
HTTP/1.1 200 OK Content-Type: text/xml; charset=utf-8 Content-Length: length <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ?????????????????? ?????? xmlns:xsd="http://www.w3.org/2001/XMLSchema" ??????????????????????????? ?? xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <getMobileCodeInfoResponse xmlns="http://WebXml.com.cn/"> <getMobileCodeInfoResult>string</getMobileCodeInfoResult> </getMobileCodeInfoResponse> </soap:Body> </soap:Envelope> ? |
?
?
1.4?????java项目中发布第一个WebService服务
?
在JDK1.6中JAX-WS规范定义了如何发布一个webService服务。
1: JAX-WS是指Java Api for XML –WebService.
用Jdk1.6.0_21以后的版本发布一个WebService服务.与Web服务相关的类,都位于javax.jws.*包中。主要类有:
@WebService - 它是一个注解,用在类上指定将此类发布成一个ws.Endpoint – 此类为端点服务类,它的方法publish用于将一个已经添加了@WebService注解对象绑定到一个地址的端口上。
?
1.4.1?本人实践——>发布服务使用wsimport:
注意:1:jdk的版本和IDE默认版本一致;
????? 2:客服端说服务端同包;
命令参数说明:
-d:生成客户端执行类的class文件的存放目录
-s:生成客户端执行类的源文件的存放目录
-p:定义生成类的包名
?
1.4.1.11:写代码 启动服务?
(服务端代码http://192.168.72.1:9000/Hello)
package cn.itcast.ws; ? import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; import javax.xml.ws.Endpoint; ? /** ?* WebService ?* 将 Java 类标记为实现 Web Service,或者将 Java 接口标记为定义 Web Service 接口 ?*/ @WebService public class HelloService { ???????? /*???? @WebMethod(operationName="abc") ???????? @WebResult(name="myReturn")(*/ ???????? public String sayHello(String name){ ?????????????????? System.out.println("sayHello()..."); ?????????????????? return? "hello " + name; ???????? } ???????? // exclude-->true:表示该方法不发布 ???????? @WebMethod(exclude=true) ???????? public String sayHello2(String name){ ?????????????????? return "hello " + name; ???????? } ? ???????? public static void main(String[] args) { ?????????????????? /** ?????????????????? ?* 参数1:服务的发布地址 ?????????????????? ?* 参数2:服务的实现者 ?????????????????? ?*/ ?????????????????? //本机IP"192.168.72.1" ?????????????????? Endpoint.publish("http://192.168.72.1:9000/Hello",new HelloService()); ?????????????????? System.out.println("Server ready..."); ???????? } ? } |
?
1.4.1.2Dos中调用wsimport-s 生成java文件
?
2:win+R--->cmd---->d:回车;---〉输入:wsimport -s . http://192.168.72.1:9000/Hello?wsdl
?
d盘文件如下
?
问题:直接复制不是英文状态下输入的命令;
?
?
?
1.4.1.3客服端写代码
?
package cn.itcast.ws; /** ?* ?在wsimport客服端调用Webservice服务 ?*/ publicclass App { ? ?? publicstaticvoid main(String[] args) { ????? HelloServiceService hss = new HelloServiceService(); ????? HelloService hs = hss.getHelloServicePort(); ????? String ret = hs.sayHello("zhangsan"); ????? System.out.println(ret); ?? } } |
?
===end
?
1.4.2?如何发布一个web服务:
l? 1、在类上添加@WebService注解。
???? 这是jdk1.6提供的一个注解。它位于:javax.jws.*包中。
l? 2、通过EndPoint(端点服务)发布一个webService。
???? Endpoint也是jdk提供的一个专门用于发布服务的类,它的publish方法接收两个参数,一个是本地的服务地址,二是提供服务的类。它位于javax.xml.ws.*包中。
???? static?Endpoint.publish(String?address,Object?implementor)
??????????在给定地址处针对指定的实现者对象创建并发布端点。
???? stop方法用于停止服务。
???? EndPoint发布完成服务以后,将会独立的线程运行。所以,publish之后的代码,可以正常执行。
l? 其他注意事项:
???? 给类添加上@WebService注解后,类中所有的非静态方法都将会对外公布。
???? 不支持静态方法,final方法。-
???? 如果希望某个方法(非static,非final)不对外公开,可以在方法上添加@WebMethod(exclude=true),阻止对外公开。
???? 如果一个类上,被添加了@WebService注解,则必须此类至少有一个可以公开的方法,否则将会启动失败。
?
//1、添加注解
@WebService
public class OneService {
??? //2、至少包含一个可以对外公开的服务
publicString sayHello(String name){
???????? System.err.println("invoke"+name);
???????? return"Hello "+name;
3、使用端点服务,将对象
绑定到一个地址和端口。
同时必须要在端口后面
给服务取一个名称
?
|
? |
??? }
publicstatic void main(String[] args) {
???????? //3、第一个参数称为Binding即绑定地址,
???????? //第二个参数是实现者,即谁提供服务
???????? Endpoint.publish("http://localhost:9999/one",new OneService());
??? }
}
?
package com.itcast; import javax.jws.WebService; import javax.xml.ws.Endpoint; /** ?* 第一个WebService服务应用 ?*/ //通过注解,标明此类发布为一个WebService @WebService publicclass HelloWorld { public String sayHello(){ return"Hello World"; } //在main方法中,使用javax.xml.ws.Endpoint端点发布一个应用 publicstaticvoid main(String[] args) { Endpoint.publish("http://127.0.0.1:9999/helloworld", new HelloWorld()); } } ? |
?
?
l? 在地址栏输入(注意后面的参数?wsdl)
???? http://127.0.0.1:9999/helloworld?wsdl
l? 目前不是访问webService,只是获取一个用于描述WebService的说明文件,即:wsdl文件.
wsdl- WebService Description Language,是以XML文件形式来描述WebService的”说明书”,有了说明书,我们才可以知道如何使用或是调用这个服务
?
1:在MyEclipse中新建立一个项目.在此项目中,将调用另一个项目中发布的WebService
2:步骤如下:
???????? 1:首先要根据http://127.0.0.1:9999/helloworld?wsdl获取WebService的使用说明书.
????????2:在Jdk的当前版本下,Jdk1.6.0_24,通过wsimport这个工具来生成远程调用的源代码.(建议生成扩展名为.java的文件)
????????3:在本项目中,通过调用生成代码的形式调用远程服务.成功返回”helloWorld”.
?
?
?
1.4.3?使用wsimport生成本地调用代码:
l? 说明书看不懂怎么办?别急JDK能看懂:
l? wsimport是jdk自带的,可以根据wsdl文档生成客户端调用代码的工具.当然,无论服务器端的WebService是用什么语言写的,都将在客户端生成Java代码.服务器端用什么写的并不重要.
l? wsimport.exe位于JAVA_HOMEbin目录下.
l? 常用参数为:
???? -d<目录>? - 将生成.class文件。默认参数。
???? -s<目录> - 将生成.java文件。
???? -p<生成的新包名> -将生成的类,放于指定的包下。
???? (wsdlurl) - http://server:port/service?wsdl,必须的参数。
示例:
C:/>wsimport –s . http://192.168.0.100/one?wsdl
注意:-s不能分开,-s后面有个小点,用于指定源代码生成的目录。点即当前目录。
如果使用了-s参数则会在目录下生成两份代码,一份为.class代码。一份为.java代码。
.class代码,可以经过打包以后使用。.java代码可以直接Copy到我们的项目中运行。
?
1:可以通过java –version检查你当前的版本号.如果版本太低可以安装高版本的jdk.
或直接将别人已安装好的jdk目录拷贝到你的机器如D:jdk1.6.0_24目录下.
因为以前的环境变量已经设置成以前老版本的jdk目录,即JAVA_HOME和PATH两个环境变量.
可以再重新设置一下环境变量为:JAVA_HOME=D:jdk1.6.0_24,path=%JAVA_HOME%bin,
重新设置了环境变量后,要重新打开一个doc(命令行)窗口.才生效.
如果不想修改原来已经配置好的环境变量,可以命令行窗口输入以下命令,使jdk1.6.0_24生效:
set path = D:jdk1.6.0_24bin;%PATH%(回车即可)
再通过java –version查看jdk的版本号是否已经发生变化.
2:转到一个相对干净的目录下,我在d盘上新建立一个目录名为:ws,并转到此目录下.
3:开启你的webService.
4:输入以下命令:
?wsimport –s . http://127.0.0.1:9999/helloworld?wsdl
参数说明:-s是指编译出源代码文件,后面的.(点)指將代碼放到當前目錄下.
最后面的http….是指获取wsdl说明书的地址.
5:此时,将生成.java文件和.class文件.(都包含原始包名).将代码Copy到你的项目中.(只拷贝java文件)
6:在新的项目中,新一个类,(可位于任意包下),对上面生成的代码进行调用,见下一页ppt.
7:wsimport其他参数说明,我们经常使用的参数为-d,-s,-p
-d<目录>将会生成.class文件.
示例:wsimport –d . http://127.0.0.1:9999/helloworld?wsdl
-s<目录>将会生成.java文件.
示例:wsimport –s . http://127.0.0.1:9999/helloworld?wsdl
-p<包名>将生成的文件(.java或是.class修改成指定的包名)
示例:wsimport -s . -p com.beijing.itcasthttp://127.0.0.1:9999/helloworld?wsdl
对于-p参数,注意包名的修改,它将所生成类,全部置于通过-p指定的包下.(演示)
需要说明的是,当仅使用-p参数时,它也将同时使用-d即编译成.class文件. –d参数写或不写,它都在那里,不离不弃.
?
1.4.4?生成以后代码如下图所示:
?
?
RunMain.java的源代码如下: package com.leaf; import com.itcast.HelloWorld; import com.itcast.HelloWorldService; /** ?* 通过调用生成的类,来调用远程代码 ?*/ publicclass RunMain { publicstaticvoid main(String[] args) { //从HelloWorldSerice的getHelloWorldPort方法中返回调用接口 HelloWorld helloWorld = new HelloWorldService().getHelloWorldPort(); String str = helloWorld.sayHello();???? //执行调用 System.err.println(str);//返回HelloWorld字符串 } } ? |
?
?
?
?
通过wsimport生成本地代码,调用网络上的web服务,比如手机号码归属地服务
?
?
?
1.5????WebService通过HTTP协议完成远程调用: (深入分析) –RPC?
1.5.1?介绍
l? WebService只采用HTTP POST方式传输数据,不使用GET方式;? -- 握手,WSDL-get,
???? 普通http post的contentType为
???? application/x-www-form-urlencoded
???? WebService的contentType为-即在Http的基础上发SOAP协议
???? text/xml 这是基于soap1.1协议。
???? application/soap+xml 这是基于soap1.2协议。
l? WebService从数据传输格式上作了限定。WebService所使用的数据均是基于XML格式的。目前标准的WebService在数据格式上主要采用SOAP协议。SOAP协议实际上就是一种基于XML编码规范的文本协议。
l? SOAP – Simple Object Access protocol 简单对像访问协议。是运行在HTTP协议基础之上的协议。其实就是在HTTP协议是传输XML文件,就变成了SOAP协议。
l? SOAP1.1和SOAP1.2的namespace不一样。可以通过查看类
???? javax.xml.ws.soap.SOAPBinding来查看里面的常量
???? 默认情况下,Jdk1.6只支持soap1.1
???? 即:@BindingType(value=javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_BINDING)
?
1.5.2?WebService和Web服务器的区别
l? WebService和Web服务器有什么区别呢?我们可以把WebService看作是Web服务器上应用;反过来说,Web服务器是WebService运行时所必需的容器。这就是它们的区别和联系。
l? 使用JDK1.6发布的简单Web服务,其内部其实是使用Socket实现。可以查看:SUN公司未对外公布的API类com.sun.xml.internal.ws.transport.http.server.ServerMgr获知,请使用反编译工具。
l? WebService的特点
???? WebService通过HTTP POST方式接受客户的请求
???? WebService与客户端之间一般使用SOAP协议传输XML数据.
???? 它本身就是为了跨平台或跨语言而设计的。
?
?
1.6?????--〉客户端调用WebService的方式<--
1.6.1?本人实践
Eclipse创建一个WebService浏览器服务:
?
?
?
?
?
l? 通过wsimport生成客户端代码
l? 通过客户端编程的方式调用
l? 通过ajax调用js+XML?
l? 通过URLConnection调用
错误:thread "main"java.io.IOException: Server returned HTTP response code: 500 for URL:http://localhost:20000/hello
at s
?
?
URL url = new URL("http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("POST"); conn.setDoInput(true); conn.setDoOutput(true); conn.setRequestProperty("Content-Type","text/xml;charset=UTF-8"); OutputStream out = conn.getOutputStream(); String soap = "<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">" + "<soap:Body><getMobileCodeInfo xmlns="http://WebXml.com.cn/"><mobileCode>13436823445</mobileCode><userID></userID>" + "</getMobileCodeInfo></soap:Body></soap:Envelope>"; out.write(soap.getBytes()); int code = conn.getResponseCode(); if (code == 200) { InputStream is = conn.getInputStream(); byte[] b = newbyte[1024]; int len = 0; StringBuffer sb = new StringBuffer(); while ((len = is.read(b)) != -1) { String s = new String(b,len,"UTF-8"); sb.append(s); } System.out.println(sb); } conn.disconnect(); ? |
?
?
1.6.2?使用原生的ajax调用web服务:
l? 由于使用ajax – js调用web服务完成不同于使用java代码调用。所以,必须要对SOAP文件非常的了解。
l? 一般使用ajax调用,应该是在已经获知了以下信息以后才去调用:
???? 获知请求(request)的soap文本。
???? 获知响应(response)的soap文本。
?
?
1.6.3?Ajax调用获取所有用户:
?
<html> ???????? <body> ?????????????????? <button id="btn" onclick="getUsers();">获取所有用户</button> ???????? </body> ???????? <script language="javascript"> ???????? ???? var xhr = null;?? ?????????????????? function getUsers(){ ??????????????????????????? var url = "http://localhost:9999/user";//声明完整的url ??????????????????????????? //以下声明soap文本 ??????????????????????????? var soap = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" '+ ??????????????????????????? ?????????? 'xmlns:q0="http://ws2.itcast.cn/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" '+ ?????????????????????????????????????????????? ?? 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'+ ???????????????????????????????????? ?????? '<soapenv:Body><q0:users/></soapenv:Body></soapenv:Envelope>'; ??????????????????????????? xhr.open("POST",url,true); ??????????????????????????? xhr.onreadystatechange=back;//以下设置请求头 ??????????????????????????? xhr.setRequestHeader("Content-Type","text/xml;charset=UTF-8"); ??????????????????????????? xhr.send(soap);//发送xml请求 ?????????????????? } ?????????????????? function back(){ ??????????????????????????? if(xhr.readyState==4){ ???????????????????????????????????? if(xhr.status==200){ ?????????????????????????????????????????????? var xml = xhr.responseXML;//获取返回的xml文本并解析 ?????????????????????????????????????????????? var returns = xml.getElementsByTagName("return"); ?????????????????????????????????????????????? for(var i=0;i<returns.length;i++){ ??????????????????????????????????????????????????????? //var nm = returns[i].firstChild.text;//两种方式都可以 ??????????????????????????????????????????????????????? var nm = returns[i].getElementsByTagName("name")[0].text; ??????????????????????????????????????????????????????? alert(nm); ?????????????????????????????????????????????? } ???????????????????????????????????? } ??????????????????????????? } ?????????????????? } ?????????????????? //创建xhr对象,在IE上 ?????????????????? function init(){ ???????? ?????????????????? xhr = new ActiveXObject("Microsoft.XMLHTTP"); ?????????????????? } ?????????????????? init(); ???????? </script> </html> ? |
?
1.6.4?客户端通过编程的方式访问服务:
?
l? 使用javax.xml.ws.Service类用于访问web服务。
l? 关键类Service
???? 方法create – 用户创建Service对像,提供wsdlurl和服务名。
???? getPort-用于通过指定namespace,portName和接口的范型。
???? 在客户端需要一个与服务器接口完全相同的类。(仍然使用工具生成。但只需要一个接口。并需要简单修改。如果返回的是复杂数据类型如POJO,还需要将POJO一并放到项目中)-不要试图通过-p来修改包名,会出错的。
l? 关键类QName – 被称为完全限定名即:QualifiedName的缩写。
???? QName 的值包含名称空间URI、本地部分和前缀。
1、以下是调用代码(以下代码仅供参考) package com.itcast; import java.net.URL; import javax.xml.namespace.QName; import javax.xml.ws.Service; import com.leaf.mynamespace.MyName; publicclass ClientTest { publicstaticvoid main(String[] args) throws Exception { //create的第一个参数为一个URL对像,接收wsdl的地址信息 //QName的参数:1: Service service = Service.create(new URL("http://localhost:6666/helloworld?wsdl"), new QName("http://leaf.com/mynamespace","myService")); System.err.println(service); //以下获取接口名 MyName o = service.getPort(? new javax.xml.namespace.QName("http://leaf.com/mynamespace","myPort"), ?????? MyName.class); System.err.println(o.mySayHiOperationName("中国北京")); } } |
?
?
1.6.5?客户端编程-用的不是很多
?
package cn;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import cn.wj.One;
public class Test {
???????? publicstatic void main(String[] args) throws Exception {
?????????????????? //声明wsdl地址
?????????????????? URLu = new URL("http://localhost:9999/one?wsdl");
?????????????????? //获取命名空间
?????????????????? Stringns = "http://wj.cn";
?????????????????? //第二个参数是一个完全限定名,WjService是服务名
?????????????????? Serviceservice = Service.create(u,new QName(ns,"WjService"));
?????????????????? //通过service的getPort方法返回指定的接口
?????????????????? Oneone = service.getPort(new QName(ns,"one"),One.class);
?????????????????? //调用sayHello方法
?????????????????? Stringss = one.sayHello("DDDD");
?????????????????? System.err.println(ss);
???????? }
}
?
1.7????WebService监听工具:
?
l? 之前我们使用过HttpWatch获取的HTTP的调用过程,并获得了HTTP的请求头及其他请求的详细信息。
l? 既然WebServie也是通过HTTP进行通信的,能不使用HTTPWatch来获取它的请求过程呢?
l? 我们的代码不仅仅是向服务器发送的HTTP协议,更具体的说应该叫SOAP协议,它是WebService进行通信的基础。
l? 为了获取SOAP数据发送和接收的格式。我们有必要使用一个工具来深入的了解WebService.
l? 为了监控拦截请求头和响应头的具体数据,我们使用TCP/IP Monitor来拦截请求和响应的完整过程。
?
?
1:简单的说,SOAP就是在HTTP的基础上传输XML数据,以实现远程调用。 ??? 因为HTTP和XML格式的数据已经被广泛的应用。而SOAP又架构在这两种技术之上,所以WebService为什么会流行也就不难理解了。 2:老生常谈,无论你的服务端是什么语言书写的,只要接收SOAP协议的XML数据,并返回SOAP协议的XML数据,就可以被任何语言调用。 3、以下是通过纯ajax向服务器发送XML数据并解析的代码: <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> </head> <body> <p>通过Ajax向服务器发送XML数据</p> <button onclick="test1();">Ajax</button> </body> <script type="text/javascript"> ?????????????????? var http; ?????????????????? function test1(){ ??????????????????????????? if(window.XMLHttpRequest){ ???????????????????????????????????? http = new XMLHttpRequest(); ??????????????????????????? }else{ ???????????????????????????????????? http = new ActiveXObject("Microsoft.XMLHttp"); ??????????????????????????? } ??????????????????????????? var url = "One"; ??????????????????????????? http.open("POST",true); ??????????????????????????? http.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); ??????????????????????????? http.onreadystatechange=function(){ ???????????????????????????????????? if(http.readyState==4){ ?????????????????????????????????????????????? if(http.status==200){ ??????????????????????????????????????????????????????? //返回JSON ??????????????????????????????????????????????????????? var json = http.responseText; ??????????????????????????????????????????????????????? var person= eval("("+json+")"); ??????????????????????????????????????????????????????? alert("人员名单:"+person.name); ?????????????????????????????????????????????? } ???????????????????????????????????? } ??????????????????????????? }; ??????????????????????????? http.send("<?xml version='1.0' encoding='utf-8'?>" + ??????????????????????????? "<user><name>王健</name><name>张三</name></user>"); ?????????????????? } </script> </html> --- 服务器使用jaxp进行解析 package cn.itcast; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; /** ?* 接收XML数据使用jaxp进行解析 ?* @author 王健 ?*/ public class One extends HttpServlet { ???????? public void doGet(HttpServletRequest request,HttpServletResponse response) ??????????????????????????? throws ServletException,IOException { ?????????????????? doPost(request,response); ???????? } ???????? public void doPost(HttpServletRequest request,IOException { ?????????????????? //获取输入流,如果在输出,请在组成String时使用UTF-8 ?????????????????? InputStream in = request.getInputStream(); ?????????????????? String names = ""; ?????????????????? // 使用JAXP解析 ?????????????????? try { ??????????????????????????? DocumentBuilderFactory factory = DocumentBuilderFactory ?????????????????????????????????????????????? .newInstance(); ??????????????????????????? DocumentBuilder builder = factory.newDocumentBuilder(); ??????????????????????????? Document dom = builder.parse(in); ??????????????????????????? NodeList nl = dom.getElementsByTagName("name"); ??????????????????????????? for(int i=0;i<nl.getLength();i++){ ???????????????????????????????????? Element el = (Element)nl.item(i); ???????????????????????????????????? String name = el.getTextContent(); ???????????????????????????????????? System.err.println(">>:"+name); ???????????????????????????????????? names +=name; ??????????????????????????? } ?????????????????? } catch (Exception e) { ??????????????????????????? throw new RuntimeException(e.getMessage(),e); ?????????????????? } ?????????????????? response.setContentType("text/xml;charset=UTF-8"); ?????????????????? PrintWriter out = response.getWriter(); ?????????????????? out.print("{"name":""+names+""}"); ???????? } } -----以下通过jQuery+Dom4j实现发XML数据-------- ???????? <script type="text/javascript" src="js/jquery-1.6.2.js"></script> ???????? <script type="text/javascript"> ?????????????????? $(function(){ ??????????????????????????? $("#jq").click(function(){ ???????????????????????????????????? var xml = "<?xml version='1.0' encoding='UTF-8'?>" + ???????????????????????????????????? "<user><name>王健A</name><name>张三</name></user>"; ???????????????????????????????????? alert(xml); ???????????????????????????????????? $.ajax({ ?????????????????????????????????????????????? url:'Two', ?????????????????????????????????????????????? type:'post', ?????????????????????????????????????????????? dataType:'json',//设置返回的数据类型 ?????????????????????????????????????????????? data:xml,//直接发xml数据 ?????????????????????????????????????????????? contentType:'application/x-www-form-urlencoded', ?????????????????????????????????????????????? success:function(data){ ??????????????????????????????????????????????????????? alert("返回的信息是:"+data.name); ?????????????????????????????????????????????? }, ?????????????????????????????????????????????? complete:function(http,textStatus){ ??????????????????????????????????????????????????????? alert("over..."+textStatus); ?????????????????????????????????????????????? } ???????????????????????????????????? }); ??????????????????????????? }); ?????????????????? }); ???????? </script> ---------------------------- package cn.itcast; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.Iterator; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; /** ?* JQuery+Dom4j ?* @author 王健 ?*/ public class Two extends HttpServlet { ???????? public void doPost(HttpServletRequest request,IOException { ?????????????????? String result = ""; ?????????????????? //中文new String(b,"UTF-8") ?????????????????? InputStream in = request.getInputStream(); ?????????????????? //以下用dom4j解析 ?????????????????? SAXReader sax = new SAXReader(); ?????????????????? try { ??????????????????????????? Document dom = sax.read(in); ??????????????????????????? Element root = dom.getRootElement(); ??????????????????????????? Iterator<Element> it = root.elementIterator(); ??????????????????????????? while(it.hasNext()){ ???????????????????????????????????? String nm = it.next().getStringValue(); ???????????????????????????????????? System.err.println(nm); ???????????????????????????????????? result+=nm; ??????????????????????????? } ?????????????????? } catch (Exception e) { ??????????????????????????? throw new RuntimeException(e.getMessage(),e); ?????????????????? } ?????????????????? response.setContentType("text/html;charset=UTF-8"); ?????????????????? PrintWriter out = response.getWriter(); ?????????????????? //返回json数据 ?????????????????? out.print("{"name":""+result+""}"); ???????? } } ? |
?
?
?
1.8????WS Explorer工具的使用:- web服务浏览器
??? 使用此工具可以获取请求协议的格式和响应协议的格式。
???????? 在MyEclipse的调用WebService并查看发出和收到的数据格式!
?
?
1、将wsdl文件,保存成本地一样可以通过此工具访问远程服务。为file:///D:/abc.xml
输入正确的WSDL地址后,点确定,将显示所的对外暴露的方法:
?
?
?
输入正确的WSDL地址后,点确定,将显示所的对外暴露的方法:
?
在MyEclipse中调用WebService可以快速验证你的服务器端程序,从而省去了自己书写客户端。 1:这是发出的消息格式: <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:q0="http://itcast.com/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <soapenv:Body> - <q0:sayHi> ?<arg0>zhangsan同学</arg0> ?</q0:sayHi> ?</soapenv:Body> ?</soapenv:Envelope> 2:以下是接收到的XML格式 <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> - <S:Body> - <ns2:sayHiResponse xmlns:ns2="http://itcast.com/"> ?<return>你好:zhangsan同学,当前时间是:2011-05-07 10:15:20</return> ?</ns2:sayHiResponse> ?</S:Body> ?</S:Envelope> 3:上面的1和2就是SOAP(Simple Object Access Protocol)简单对像访问协议的格式。 ? |
?
通过HTTP发出和接收到的XML数据:
使用WebServiceExplorer只可以看到SOAP的XML数据,并看不到HTTP协议的头。
既然是用HTTP发XML数据,就一定会有HTTP头,为了获取HTTP头,我们使用TCP/IP Monitor.
?
|
? |
?
1:我们已经说过了,WebService是通过向服务器发出XML格式的数据实现远程调用,然后服务器也返回XML数据给客户端,那么这个XML是什么格式的呢?
下面我将使用MyEclipse中的WebService Explorer工具向我们的WebService发起请求,并查看它的XML数据格式。
2:通过HttpWatchprofession Edition只可以看到获取wsdl文档的具体信息。
???? 且必须安装HttpWatchprofession Edition版本的才可以,如果是Basic版本的,将不会看到Stream(数据流)信息。
?
请求的数据:
?
使用TCP/IP Monitor-拦截HTTP请求头和响应头及Body部分:
?
?
?
1.9????SOAP请求过程分析:
l? 第一步:使用get方式获取wsdl文件,称为握手。
???? 对于JDK1.6生成的ws服务,由于内部有一两个配置文件,所以会发出两次get请求。
???? 其他的一般为一次。
l? 第二步:用户发出请求将使用post方式。
l? 第三步:服务器响应成功。
?
?
获取wsdl文件-握手的请求与响应:
?
以下是拦截到的请求/响应信息:
?
?
?
?
发出去的XML文本:
?
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"xmlns:q0="http://server.itcast.cn/"xmlns:xsd="http://www.w3.org/2001/XMLSchema"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>??? //SOAP协议必须拥有body元素
<q0:sayHello>??? //SOAP协议必须通过第一个节点指明需要调用的方法
<arg0>aaa</arg0>
</q0:sayHello>
</soapenv:Body>
</soapenv:Envelope>
?
?
拦截到的返回信息:
?
<?xml version="1.0" ?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:sayHiResponsexmlns:ns2="http://ws.itcast.cn/">
<return>HelloWorld</return>
</ns2:sayHiResponse>
</S:Body>
</S:Envelope>
?
?
深入分析说明书WSDL:
?
l? wsdl – WebService Description Language(WS描述语言)
l? 它主要定义了三个方面的问题:
???? What?即服务是什么?
???? (portType,types,message)
???? How?如何调用服务?
???? 通过binding元素说明调用服务的方式:soap,soap12,post,get.
???? Where?在哪儿调用服务?
???? Service元素,soap:address.
?
?
?
都是由系统发布时自动生成的,那么如何才可以修改这个文档呢?
|
? |
?
?
修改wsdl文件的内容:
?
l? WSDL文件的内容,一般由服务默认生成,但为了更好的向开发人员提供使用说明书,一般应做一些简单的修改。至少不应该暴露我们的包结构。而targetNamespace默认情况下为倒置的包名,这已经暴露了我们的包结构。
l? 通过在类文件上添加以下注解,可以修改wsdl生成的各元素,而不是直接去修改wsdl文件,直接去修改wsdl文件是无效的。
l? WebService的注解包括:
???? @WebService-定义服务?? --类上
???? @WebMethod-定义方法?? - 方法
???? @WebResult-定义返回值– 返回值
???? @WebParam-定义参数– 参数
???? ?
l? 1、另有:SOAPBinding-指定WebService到SOAP协议的影射关系?
l? 使用不同版本的Jdk对发布ws的影响.
l? 1.5不支持.
l? 1.6.0_20前版本必须使用完整注解.
l? 1.6.0_21以后可以只使用@WebService对类进行注解.
l? 2、关于namespace约定名的说明,@WebService(targetNameSpace=…..)
l? targetNamespace
l? 定义导出的服务接口的名域(namespace),默认是倒置的服务接口Java包名。如demo.cxf.UserService的名域将会是http://cxf.demo/
?
?
注解的作用
l? 通过WebService的注解,可以更加形像的描述Web服务。从而生成WSDL文档。
l? 当修改了WebService注解之后,同时会影响客户端生成的代码。
l? 调用的方法名和参数名也发生了变化。
l? 即使是没有修改源代码,只修改了注解,客户端的代码也必须要重新生成(注意是生成而不是下载)。否则调用将会失败。
l? 生成本地调用代码,依然使用wsimport工具。
?
?
1:WebService的注解都位于javax.jws包下。 ???? 主要包含以下几个注解(直接查看JDK文档,关于它里面的配置属性也直接看JDK6的文档。) ???? 我们只讨论以下加个注解: ???? WebMethod ???? WebParam ???? WebResult ???? WebService 2:以下是加了注解的示例: package com.itcast; import java.text.SimpleDateFormat; import java.util.Date; import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; import javax.jws.WebParam.Mode; import javax.xml.ws.Endpoint; /** ?* 一个加了很多注解的代码 ?*/ @WebService(name="myName",//对应portType name="myName" portName="myPort",? //对应服务中的port name="myPort" serviceName="myService",//对应service name="myService" targetNamespace="http://leaf.com/mynamespace")//可以随意书写类似于java中的package publicclass HelloWorld{ privatestatic SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @WebMethod(action="myAction",//定义一个soapAction="myAction"用于找到这个方法以执行 ?? operationName="myOperationName")//定义可以调用的方法,会生成相应类的具体方法,operation name=".." public @WebResult(name="mySayHelloResult")String//定义返回值的名称 sayHello(){ return"HelloWorld"; } @WebMethod(action="mySayHiAction",operationName="mySayHiOperationName") public @WebResult(name="mySayHiResult")String sayHi(@WebParam(name="myParaName", //将参数放到头信息中,用于保护参数,默认在body中 ????????????????????????????????????????????????????? header=true, ? mode=Mode.IN) String name){ String str = "你好:"+name+",当前时间是:"+sdf.format(new Date()); return str; } publicstaticvoid main(String[] args) { Endpoint.publish("http://127.0.0.1:6666/helloworld",new HelloWorld()); } } 3:将上面的程序对外发布以后,我们通过MyEclipse的WebService Explorer来访问 你会发现和以前不一样的提示信息,但其实,仍然还是调用的那同一个方法。 4:请同学们在去观察SOAP请求和返回文档的修改。在MyEclipse WebService Explorer的返回信息窗口中点Soure即可以看到。观察变化加以分析。 5:再次使用wsimport –s . http://127.0.0.1:6666/helloworld?wsdl生成java代码然后调用,看看还是哪些类名吗? 以下是调用代码(可以用面目全非来形容,但完成的还是同样的工作。) package com.leaf.mynamespace; publicclass Main { publicstaticvoid main(String[] args) { //通过分析wsdl可知从myService中调用getMyPort返回myName MyName myName = new MyService().getMyPort(); //通过myName的mySayHiOperationName来调用sayHi方法 String str = myName.mySayHiOperationName("王健"); System.err.println(str); } } ? |
?
?
@WebService注解:
l? @WebService注解,作用在具体类上。而不是接口。
l? 一个类只有添加了此注解才可以通过Endpoint发布为一个web服务。
l? 一个添加了此注解的类,必须要至少包含一个实例方法。静态方法和final方法不能
l? 被发布为服务方法。
l? WebService注解包含以下参数:
?
?
@WebMethod
?
@WebResult用于定制返回值到WSDL的映射:
?
?
@WebParam用于定义WSDL中的参数映射:
?
?
?
package cn.leaf.two; import java.util.Date; import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; import javax.xml.ws.Endpoint; /** ?* 发布第一个web服务 ?*/ @WebService (serviceName="WjService"//修改Service的名称,即:new WjService(); ?,name="One"//定义Port名称,即端口-new WjService().getOnePort();返回接口即One ?,targetNamespace="http://wj.cn"//定义命名空间,默认为倒置的包名 ?,portName="one"//定义获取的方法,此值可以覆盖name的定义,即port name="getOne" ) public class OneService{ ???????? @WebMethod(operationName="sayHello"//修改方法名 ?????????????????? ????? ) ???????? public ???????? ?? @WebResult(name="ReturnMsg") ?????????????????? String sayHi( ???????????????????????????????????? @WebParam(name="yourName") ???????????????????????????????????? String name){ ?????????????????? return name+",你好,现在时间是:"+new Date(); ???????? } ???????? public static void main(String[] args) throws Exception { ?????????????????? //发布服务 ?????????????????? Endpoint ed= Endpoint.publish("http://127.0.0.1:9999/one", ?????????????????????????????????????????????? new OneService()); ?????????????????? System.err.println("服务发布成功"); ???????? } } ? |
?
从wsdl中分析出类的关系: