您的位置:首页 > 其它

webservice基础

2016-03-13 21:33 323 查看
根据传智播客视频学习 ---〉增加了自己开发中遇到的问题

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、给类添加注解

//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_HOME\bin目录下.

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_24\bin;%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, 0, 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",url,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, HttpServletResponse response)

throws ServletException, 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, HttpServletResponse response)

throws ServletException, IOException {

String result = "";

//中文new String(b,0,len,"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中分析出类的关系:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: