jaxws-webservice编程

前言:

随着近几年来,SOA,EAI等架构体系的日渐成熟,Webservice愈来愈炽手可热,尤为是在企业作异质平台整合时成为了首选的技术。java

Java的Webservice技术更是层出不穷,比较流行的有:node

Axis2,Spring WS以及Jaxws。web

本人在平常工做和以往工程中,在使用了上述这些Webservice后进行了总结,比较,最终以为jaxws是目前最标准,须要额外第三方插件最少,配置最少最灵活的webservice。编程

JAXWS适合几乎全部Webservice客户端的调用,所以很多巨头型的厂商如:IBM,Weblogic等,在他们的产品上都使用了以JAXWS为标准的Webservice接口。tomcat

本教程分红五天,为初级教程。安全

经过本教程,可使一个没有Webservice概念或者没有写过Webservice的JAVA Resource快速上手入门,并能知足通常中小型项目中Webservice的应用。服务器

对于Webservice Security,在(初级)教程中并不提供,会在高级教程中详细描述。session

不过真正利用Webservice Security特性即XML加密技术的工程并很少,少之又少,大多仍是以http: //xxx/xxxService?userId=&password=这样的形式来进行“假安全”通信的。数据结构

必经咱们的大部分项目是运行在Intranet里的,并且有很好的监控和布防。架构

下面开始咱们的教程。

第一天

 

目标:

1. 理解jaxws

2. 写jaxws以前的准备工做

3. 一切始于HelloWorld

4. 理解同步,异步

1、理解jaxws

1.1JAX-WS概述

JAX-WS2.0 的全称为 Java API for XML-Based Webservices (JAX-WS) 2.0。JAX-WS 2.0 是对 JAX-RPC 1.0 规范的扩展,是 JAX-RPC 1.1 的后续版本, JAX-RPC 2.0 标准发布不久后便被从新命名为 JAX-WS 2.0。 JAX-WS 2.0 是面向 Java 5 的开发 Web services 的最新编程标准,它提供了新的编程模型和对以往的 JAX-RPC 方式的 Web services 进行了加强。 JAX-WS2.0 (JSR 224)是Sun新的web services协议栈,是一个彻底基于标准的实现。在binding层,使用的是the Java Architecture for XMLBinding (JAXB, JSR 222),在parsing层,使用的是the Streaming API for XML (StAX, JSR 173),同时它还彻底支持schema规范。

1.2JAX-WS 2.1特性

支持SOAP 1.1(默认)、1.2

支持XML/HTTP Binding

支持WS-Addressing

支持document/literal样式

支持WS-I Basic Profile 1.1

支持消息传输优化机制(Message Transmission Optimization Mechanism,MTOM)

2、写jaxws以前的准备工做

2.1JDKjavaversion "1.6.0_x"。

2.2JAX-WS RI 2.1.1 in JDK 6

2.2.1 JAX-WS RI 2.1.1安装注解


JAX-WS RI组件下载后为一个”.jar”文件,它并不能直接在工程中使用,它是一个以JAVA Swing为界面的JAXWS的安装程序包。

咱们须要打开一个命令行窗口,并输入:

 


输入完这条命令后,你会获得一个安装界面以下:


下一步,下一步完成安装后你会获得这样的一个目录:


这个目录里有咱们写JAXWS所需的全部lib包以及JAXWS自带的教程。

3、一切始于HelloWorld

3.1创建Webservice的Server端工程


能够看到咱们这个目录除传统的src,WebContent目录外还有几个目录,它们分别是:

?    build
?    wsdl
?    wssrc

咱们来书写咱们的第一个Webservice吧,它的名字叫Hello(Come on, 老套了,又来了)。

package ctsjavacoe.ws.fromjava;

 

import javax.jws.WebMethod;

import javax.jws.WebService;

 

@WebService

public class Hello {

    @WebMethod

    public String say(String name) {

       return ("Hello: "+name);

    }

}

注意:

@WebService

注释在了Class之上,这告诉了JAXWS,此类为Webservice。

@WebMethod

注释在了public方法上,这告诉了JAXWS,此方法为soap方法,该方法有两个参数,一个input的String,一个output的String。

业务逻辑很简单,客户端调用传入一个Name,服务端返回给客户端一个”Hello: “+name的字串。

如今咱们经过Java文件来生成Webservice相关布署文件以及调用接口。

3.2经过Java类编译Webservice

JAX-WS 2.0 有两种开发过程:自顶向下和自底向上。自顶向下方式指经过一个 WSDL 文件来建立Web Service,自底向上是从 Java 类出发建立 Web Service。两种开发过程最终造成的文件包括:

1.SEI。一个SEI对应WSDL中WebService的一个port,在Java中是一个Java接口。

2.SEI实现类。

3.WSDL和XSD文件。

结合公司内项目的特色,咱们更多的是碰到如下两种状况:

1.  Onsite要咱们作一个Webservice或者是客户要求咱们提供Webservice接口;

2.  Onsite已经有一个Webservice了,如今要咱们作客户端集成。

 

所以,咱们选用Server端经过Java Class生成webservice,而客户端经过wsdl生成Java调用类的作法

 

JAXWS为咱们提供了两个工具:

ü  wsgen

主要用于Server端经过Java类编译成Webservice及相关的wsdl文件

ü  wsimport

主要用于Client端(调用端)经过wsdl编译出调用Server端的Java文件

咱们就来生成一下上面的这个Hello,打开一个command窗口,键入以下命令:


-wsdl参数表明生成webservice

- s参数表明生成的.java文件置于何处

-d 参数表明生成的编译class文件置于何处(这个能够忽略,咱们利用eclipse编译)

-r 参数表明生成的.wsdl文件与.xsd文件生成在何处

-cp参数表明classpath,即Hello.class的所在,为何咱们的-cp后是这么长一个路径呢?请看Eclipse里工程编译输出目录的路径就知道了:


3.2.1 生成的src文件

好,咱们如今回到eclipse工程里,刷新一下工程:


看 到在wssrc目录下已经生成了咱们所需的java文件了,请手工cut(对,是cut)这些文件到咱们工程的”src”目录,若是不cut,下次继续使 用该目录生成webservice类时,wsgen有时会生成不了,但也不报错,不知道为何,查了一下,多是一个bug,因该会在后续的 jdk1.6.30up里改进。

3.2.2 生成的wsdl及xsd文件


这里咱们有两个文件,一个是wsdl文件,这个就是咱们的webservice的entry,一个是xsd文件,这个是什么?

这个就是咱们java的方法里的参数的对应,或者换句话说,它就是xml格式的java bean,在webservice的世界里,xsd是做为数据结构描述用的。

如今咱们的webservice的服务端有了。

3.2.3 布署webservice

布署前的准备:

在工程的WEB-INF目录下创建“sun-jaxws.xml”文件,内容以下:

<?xml version="1.0" encoding="UTF-8"?>

<endpoints xmlns='http://java.sun.com/xml/ns/jax-ws/ri/runtime'

    version='2.0'>

    <endpoint name='Hello' implementation='ctsjavacoe.ws.fromjava.Hello'

        url-pattern='/HelloService' />

</endpoints>

将ctsjavacoe.ws.fromjava.Hello声明为Web Service。

 

 

 

 

 

 

若是是从WSDL生成的Web Service,则写法为,

<?xml version="1.0" encoding="UTF-8"?>

<endpoints version="2.0" xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime">

<endpoint implementation="ctsjavacoe.ws.fromjava.HelloSEI"

name="Hello" url-pattern="/HelloService" />

</endpoints>

 

修改WEB-INF目录下的web.xml文件,增长以下内容:

<servlet>

        <servlet-name>Hello</servlet-name>

        <servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>

        <load-on-startup>2</load-on-startup>

</servlet>

<servlet-mapping>

        <servlet-name>Hello</servlet-name>

        <url-pattern>/HelloService</url-pattern>

</servlet-mapping>

为每个WebService声明一个com.sun.xml.ws.transport.http.servlet.WSServlet。

 

开始布署:

1.  在tomcat的webapps目录下创建一个目录叫“D:\tomcat2\webapps\JaxWSSample”

2.  把eclipse工程JaxWSSample下WebContent目录下全部的东西copy至该目录下

3.  重启tomcat

在ie中输入:

http://localhost:9090/JaxWSSample/HelloService?wsdl

能够看到咱们的webservice已经生成了。


3.3经过Server端的WSDL生成供JAVA调用的客户端

3.3.1 同步与异步

同步调用,很好理解,即一来一回,Client端request到Server端,Sever端马上回一个response。

异步调用,就是客户端调用一次服务端后,服务端处理事务并非即时返回的,好比说传一个600MB文件给服务端,服务端在处理接收和解析文件时,客户端不会立刻获得一个响应,它会等待一段时间,等服务器处理完后,再通知客户端“我处理完了”。

3.3.2 利用wsimport产生客户端

咱们新建一个eclipse的工程,只须要是JAVA工程就好了,不须要web工程的,由于咱们这边只用代码作调用:



把Server端的wsdl及xsd都手工copy到客户端工程的wsdl目录下。

打开一个cmd窗口敲入以下的命令:

wsimport -keep -d bin -s src wsdl/HelloService.wsdl


以上是产生同步客户端的命令。

若是要产生异步客户端命令,须要在工程根目录下建一个binding.xml的文件,内容以下:

<?xml version="1.0" encoding="UTF-8"?>

<bindings xmlns:xsd="http://www.w3.org/2001/XMLSchema"

    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" wsdlLocation="wsdl/HelloService.wsdl"

    xmlns="http://java.sun.com/xml/ns/jaxws">

    <bindings node="wsdl:definitions">

        <enableAsyncMapping>true</enableAsyncMapping>

    </bindings>

</bindings> 

而后产生客户端代码的wsimport命令也会不同:

wsimport -keep –b binding.xml  -d bin -s src wsdl/HelloService.wsdl

 


 

咱们来看异步调用的代码(同步代码比异步调用简单,留给你们本身作练习)

wsimport命令会在eclipse工程的src目录中生成你在调用时所用的java src文件。


Hello.java与HelloService.java是wsimport给咱们生成的供客户端调用的java文件。

咱们把HelloService文件打开,能够看到两行:

file:/D:/workspace/JaxWSClient/wsdl/HelloService.wsdl

把它们改为:

http://localhost:9090/JaxWSSample/HelloService?wsdl

有两行,尤为是Url url=这一行,千万不要漏改了。

咱们建立一个调用类,叫:HelloAsyncPollingClient.java文件,内容以下:

package ctsjavacoe.ws.fromjava;

 

import javax.xml.ws.Response;

 

public class HelloAsyncPollingClient {

 

    /**

     * @param  args

     */

    public static void main(String[] args) throws Exception {

        HelloService service = new HelloService();

        Hello port = service.getHelloPort();

        Response<SayResponse> sayAsync = port.sayAsync("Mk");

        while (!sayAsync.isDone()) {

            System.out.println("is not down");

        }

        try {

            SayResponse callNameResponse = sayAsync.get();

            String message = callNameResponse.getReturn();

            System.out.println(message);

        } catch (Exception ex) {

        }

    }

 

}

运行,获得结果以下:


3.3.3 细说同步与异步

在旧的基于JAX-RPC的webservice编程model中,是不支持异步的service 调用的,在最新的Jax-ws webservice 编程model中,加入了对webservice的异步调用的支持。

首 先我来说一下它的原理,你们不要觉得在异步的调用下,从client到server 之间的soap message 流也是异步的,其实不是,Soap/Http 协议在同步跟异步的调用下是同样的,都是客户端的service在运行时打开一个connectin,发送请求,而后接收返回,这些都在同一个 connection中。这种方式对咱们有什么影响呢?从客户端程序的角度来说,没有影响,客户端的编程模型是由WSDL中的messages跟port types 来定义的,只要这些东西没有改变,request 跟response是否是在同一个Tcp/ip 的session 中来发送对与咱们来讲没由影响,而后从架构跟资源的角度来说,对咱们的影响就大了,把链接层的资源跟应用层的程序运行状态绑定起来是由许多弊端的,假如在 异步调用时,程序运行出现了异常,将会致使链接层的资源被一直占用,这样会极大的影响咱们程序的,稳定性,可靠性,资源的使用跟性能。

 


3.3.4 异步的另外一种实现

上例中实现的是一种“polling方式的异步调用”,下面给出“callback”方式的异步调用客户端。

因为此callBack当请求发出去之后当前的这个connection就会关闭 ,为了达到测试的目的,加入了sleep,让客户端程序等待服务器端得返回。

callback类型的client要传入一个javax.xml.ws.AsyncHandler类型的匿名内部类,当soapMessage 到达时,Jax-ws会调handleResponse这个方法来处理response.

客户端测试代码以下:

package ctsjavacoe.ws.fromjava;

import javax.xml.ws.AsyncHandler;

import javax.xml.ws.Response;

public class HelloAsyncCallBackClient {

    public static void main(String[] args) throws Exception {

        HelloService service = new HelloService();

        Hello port = service.getHelloPort();

        port.sayAsync("Mk", new AsyncHandler<SayResponse>() {

            public void handleResponse(Response<SayResponse> res) {

                try {

                    SayResponse response = null;

                    response = res.get();

                    String message = response.getReturn();

                    System.out.println(message);

                } catch (Exception e) {

                    e.printStackTrace();

                }

            }

        });

        Thread.sleep(1000);

    }

}

相关文章
相关标签/搜索