Java SE 六 新特性: Web 服务

Java SE 6 新特性: Web 服务
Java SE 6 新特性: Web 服务
2008-03-17 11:00

Web 服务

基 于 XML 的数据通常被作为 Web 服务之间互相调用的标准的数据传输文件格式。Java SE 6 SDK 中基于 XML 的解析技术,也提供了 Web 服务的 API 支持。和较早的 JDK 5 相比,新版本的 JDK Web 服务功能更改了名称 —— 从 JAX-RPC 变成 JAX-WS。JDK 5 只支持基于 remote-procedure-call 的 Web 服务,JDK 6 在此基础上,还支持基于 SOAP message 的 Web 服务实现。下面将给出一个例子,基于 SOAP message,实现一个简单的 Web 服务。

  1. 清单 9 给出了开发一个 Web services EndPoint 的代码。

    清单 9. 一个 Web service‘Hello’服务
    package hello;
    import javax.jws.WebService;
    import javax.jws.WebMethod;
    import javax.xml.ws.Endpoint;
    
    @WebService
    public class Hello {
        @WebMethod
        public String hello(String name) {
            return "Hello, " + name + "\n";
        }
     
        public static void main(String[] args) {
            // create and publish an endpoint
            Hello hello = new Hello();
            Endpoint endpoint = Endpoint.publish("http://localhost:8080/hello", hello); 
        }
    }
  2. 使用 apt 编译 Hello.java,产生辅助文件:

    apt -d sample example/Calculator.java

    运行完这条命令之后,example 目录下面多出了一个 jaxws 子目录如 图 6 所示。Apt 工具在该目录里生成了发布 Hello Web service 所必需的两个辅助文件。



    图 6. example 目录
    Java SE 六 新特性: Web 服务
  3. 发布 Hello Web service:

    java -cp sample hello.Hello

    将浏览器指向 http://localhost:8080/hello?wsdl 会产生如 图 7 所示页面。



    图 7. 发布的 Hello Web service
    Java SE 六 新特性: Web 服务

Java SE 6 SDK 内嵌了一个轻量级的 HTTP Server,方便开发者验证简单的 Web service 功能。通过以上三步,一个 Web service Endpoint 就部署完成,下面将开发一个调用 Hello 服务的客户端。

  1. 为 Web 服务的客户端产生存根文件:

    wsimport -p sample -keep http://localhost:8080/hello?wsdl

    这将会在 sample 目录下产生如 图 8 所示的文件。这一步实际是根据上面 URL 指向的 WSDL 文件,通过 JAXB 技术,生成了相应的 Java 对象。



    图 8. wsimport 产生的文件
    Java SE 六 新特性: Web 服务
  2. 开发,编译,运行 Web 服务客户程序。清单 10 给出了使用 Hello 服务的客户程序。



    清单 10. 使用 Hello 服务的客户程序
    package sample;
    class HelloApp {
        public static void main(String args[]) {
            HelloService service = new HelloService();
            Hello helloProxy = service.getHelloPort();
            String hello = helloProxy.hello("developer works");
            System.out.println(hello);
        }
    }

    图 9 是编译并运行该客户程序产生的结果:



    图 9. 调用 Hello 服务
    Java SE 六 新特性: Web 服务

可 以说在 Java SE 6 SDK 中,Web 服务的开发过程被大大简化了。原来开发中需要手工重复劳动产生的文件,可以使用工具自动生成。比如 WSDL 文件可以自动生成,和 WSDL 绑定的 Java 对象也自动生成,部署(本文仅指 JDK 提供的轻量 HTTP server 部署环境)也大大简化。这些全部归功于 JDK 6 中引入的一些新的 JSR 实现,即一些 API 和工具。表 2 给出了 JDK6 中为 Web 服务 API 提供支持的包。


表 2. JDK 中提供 Web 服务 API 支持的包
JSR Package
JSR 224

Java API for XML-Based Web Services 2.0

javax.xml.ws
javax.xml.ws.handler
javax.xml.ws.handler.soap
javax.xml.ws.http
javax.xml.ws.soap
javax.xml.ws.spi
JSR 222

Java Architecture for XML Binding (JAXB) 2.0

javax.xml.bind
javax.xml.bind.annotation
javax.xml.bind.annotation.adapters
javax.xml.bind.attachment
javax.xml.bind.helpers
javax.xml.bind.util
JSR 181

Web Services Metadata for the Java Platform

javax.jws
javax.jws.soap

除此之外 JDK 6 还提供了一些工具,包括 wsgen, wsimport 以及 Java 调用的轻量级 HTTP server。API 和工具联合提供了一个简单的 Web services IDE 开发环境,可以简化 Web 服务应用的开发。

Java class 和 XML 文件的绑定

从 上一段关于 Web 服务的叙述中,我们能够发现开发和部署 Web 服务的过程中存在多次 Java 对象和 XML 文件转化的过程。比如开发和部署服务的时候,将一个 Web Service EndPoint 发布成为一个 WSDL,或者使用服务的时候,将一个 WSDL 文件转换成一组 Java 对象。所有的转换,都是通过工具自动完成的。这里存在一些问题,Java 对象的类型转换成 XML 元素是需要符合一定的标准,还是随意转换呢?如果按照标准转换,那么这个标准是什么样子的?比如 Java 中的 int 类型是应该变成 <int></int> 呢,还是 <integer></integer> 。如 表 2 列出,JSR222- Java Architecture for XML Binding (JAXB) 2.0 标准为这些问题给出了一个规范的解答。

首先示范一个简单的例子,将根据一个 XML 文件的 schema,转换成 Java 对象。还是以 清单 6 中的数据文件为依据。构造一个 XML schema 文件,如 清单 11 所示。要运行这个例子,首先需要下载一个 JAXB Reference Implementation jar(下载请参见 参考资源 ),并将该 jar 文件加入到 classpath 中。


清单 11. 用于绑定的 workcontactinfo.xsd 文件
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <xsd:element name="workcontactinfo" type="workcontactinfo" />
 <xsd:complexType name="workcontactinfo">
  <xsd:sequence>
   <xsd:element ref="Location" maxOccurs="1" minOccurs="1" />
   <xsd:element ref="Postal" maxOccurs="1" minOccurs="1" />   
   <xsd:element ref="tel" maxOccurs="1" minOccurs="1" />
   <xsd:element ref="Appellation" maxOccurs="1" minOccurs="1" />
  </xsd:sequence>
 </xsd:complexType>
 <xsd:element name="tel" type="tel" />
 <xsd:complexType name="tel">
  <xsd:sequence>
   <xsd:element ref="fix" maxOccurs="1" minOccurs="1" />
   <xsd:element ref="mobile" maxOccurs="1" minOccurs="1" />
  </xsd:sequence>
 </xsd:complexType>
 <xsd:element name="Location" type="xsd:string" />
 <xsd:element name="Postal" type="xsd:string" />
 <xsd:element name="Appellation" type="xsd:string" />
 <xsd:element name="fix" type="xsd:string" />
 <xsd:element name="mobile" type="xsd:string" />
</xsd:schema>

  1. 运行命令 xjc workcontactinfo.xsd 。将会在当前目录下生成一个 generated 子目录。
  2. 运行命令 javac generated\*.java ,编译所有生成的 Java 文件。
  3. 操作生成的 Java 对象。清单 12 给出了一个操作生成的 java 对象的例子。要注意,一定要先将 JAXB Reference Implementation jar 放到 classpath 中。

清单 12. 调用生成的 Java 对象
import generated.*;

import java.io.FileOutputStream;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;

public class JAXBTest {

    public static void main(String[] args) {
        try {

            JAXBContext jContext = JAXBContext.newInstance("generated");

            ObjectFactory factory = new ObjectFactory();

            Workcontactinfo contactinfo = (Workcontactinfo) (factory
                .createWorkcontactinfo());

            contactinfo.setAppellation("Mr. Wang");
 
            contactinfo.setLocation("Shanghai-shuion-333");
 
            contactinfo.setPostal("200020");

             Tel tel = (Tel) (factory.createTel());
            tel.setFix("123456");
            tel.setMobile("1376666666");
 
            contactinfo.setTel(tel);
            Marshaller marshaller = jContext.createMarshaller();

            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
                Boolean.TRUE);

            marshaller.marshal(contactinfo, new FileOutputStream(
                "workcontactinfo1.xml"));

            System.out.println("java tree converted into xml & filed");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

运行这个程序,就能生成一个 XML 数据文件,如 清单 13 。


清单 13. XML 数据文件
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<workcontactinfo>
    <Location>Shanghai-shuion-333</Location>
    <Postal>200020</Postal>
    <tel>
        <fix>123456</fix>
        <mobile>1376666666</mobile>
    </tel>
    <Appellation>Mr. Wang</Appellation>
</workcontactinfo>

回顾一下 Web 服务的 WSDL 文件,如 图 5 所示,是一个符合 W3C XMLSchema 规范的 schema 文件,以及整个过程中生成的 Java 类,我们应该能更好的理解 Web 服务开发,部署,使用的全过程。首先 JDK 6 提供的工具 apt 根据 Web Service EndPoint 中相关的注释生成一些与 WSDL schema 绑定的 Java 类。察看这些类可以发现,它们与 JAXB 例子中 generated 目录下生成的 Java 文件十分相似。接着通过 HTTP 服务将这个 WSDL schema 文件发布出来。然后通过 wsimport 工具,生成一个 Web 服务的客户运行时代理,相当于 清单 12 的功能。最终 Web 服务的用户程序同运行时代理交互,该代理生成并传递形式如 清单 13 的 XML 数据文件。图 10 结合 表 2 给出了 Web 服务开发到使用整个周期的工作流和涉及到的 JDK 包。


图 10. Web 服务开发部署流程中 XML 技术的应用
Java SE 六 新特性: Web 服务

Java SE 六 新特性: Web 服务
Java SE 六 新特性: Web 服务
Java SE 六 新特性: Web 服务
Java SE 六 新特性: Web 服务 回页首


总结

比 较前一个版本的 JDK,新版本对 XML 处理技术进行了扩展。包括新加入的 StAX 和 JAXB。基于这些新的 XML 数据处理技术,JDK 6 对 Web 服务的支持也得到了大大的增强。这些增强体现在引入了一些注释和 API,增加了更多的工具,可以自动化大部分开发和部署的工作。对于 XML 应用开发者来说,有更多更有力地技术可以选用。对于 Web 服务提供者来说,开发工具更为强大,开发流程更为简化,工作效率得到提高。而对于 Web 服务的使用者,更多的底层细节被屏蔽。可以说,新版 JDK 在对 XML 相关应用开发上的支持,较前一个版本有了很大提升。