Webservice 基础 (其中大部分信息参考传智播客)

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生成本地调用代码:

说明书看不懂怎么办?别急JDK能看懂:

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获知,请使用反编译工具。

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" οnclick="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 οnclick="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中分析出类的关系:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值