加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

webservice基础

发布时间:2020-12-16 22:22:00 所属栏目:安全 来源:网络整理
导读:根据传智播客视频学习 ?---〉增加了自己开发中遇到的问题 1 :WebService基础笔记 ? 请改为本机IP练习 无论你的服务端是什么语言书写的,只要接收SOAP协议的XML数据,并返回SOAP协议的XML数据,就可以被任何语言调用。 ? 1.1?????常用名词介绍: l? 名词1:X

根据传智播客视频学习 ?---〉增加了自己开发中遇到的问题

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:

注意:1jdk的版本和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、给类添加注解

?

?

?


//1、添加注解

@WebService

public class OneService {

2、声明实例方法

?

?

??? //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中分析出类的关系:

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读