Click here to view and discuss this page in DocCommentXchange. In the future, you will be sent there automatically.

SQL Anywhere 11.0.1 (中文) » SQL Anywhere 服务器 - 编程 » SQL Anywhere 数据访问 API » SQL Anywhere Web 服务

 

教程:将数据类型与 JAX-WS 一起使用

以下教程演示了如何使用 Java API for XML Web Services (JAX-WS) 访问 Web 服务。

如果您已完成了更早版本的 JAX-WS 教程,那么这些步骤中的一些已经执行过了。

在开始之前,您需要有 Sun 提供的 JAX-WS 工具。如果您的系统上没有安装此软件包,您必须下载 JAX-WS 工具并安装它们。要下载 JAX-WS 工具,请访问 [external link] http://java.sun.com/webservices/。单击 JAX-WS 的链接。您将进入 [external link] Java API for XML Web Services 页面。单击 [Download Now] 链接。在您已经下载了软件包之后,将它安装在您的系统上。

此示例是使用 JAX-WS 2.1.3 for Windows 开发的。

应将从 JAX-WS 访问的 SQL Anywhere SOAP Web 服务声明为 CONCRETE 格式。

♦  创建 SOAP 和 DISH 服务
  1. 在命令提示符处,运行以下命令以启动个人 Web 服务器。将 samples-dir 替换为示例数据库的实际位置。-xs http(port=80) 选项会告知数据库服务器接受来自端口 80 的请求。如果在端口 80 上已有 Web 服务器在运行,则将另一个端口号(如 8080)用于本教程。

    dbeng11 -xs http(port=80) samples-dir\demo.db
  2. 启动 Interactive SQL,并以 DBA 身份连接到 SQL Anywhere 示例数据库。执行以下语句:

    1. 定义一个列出 Employees 表的某些列的存储过程。

      CREATE PROCEDURE ListEmployees()
      RESULT (
       EmployeeID            INTEGER,
       Surname               CHAR(20),
       GivenName             CHAR(20),
       StartDate             DATE,
       TerminationDate       DATE )
      BEGIN
        SELECT EmployeeID, Surname, GivenName, 
          StartDate, TerminationDate 
        FROM Employees;
      END;
    2. 定义一个调用此存储过程的 SOAP 服务。

      CREATE SERVICE "WS/EmployeeList2"
      TYPE 'SOAP'
      FORMAT 'CONCRETE' EXPLICIT ON
      DATATYPE OUT
      AUTHORIZATION OFF
      SECURE OFF
      USER DBA
      AS CALL ListEmployees();

      EXPLICIT 子句仅能用于 CONCRETE 类型的 SOAP 或 DISH 服务。在此示例中,EXPLICIT ON 表示相应的 DISH 服务应生成说明 EmployeeList2Dataset 对象的 XML 模式。此选项仅影响生成的 WSDL 文档。在前面的 JAX-WS 教程中,我们看过使用 EXPLICIT OFF 的示例。请参见教程:从 JAX-WS 访问 Web 服务

      DATATYPE OUT 表示显式数据类型信息在 XML 结果集响应中生成。如果已指定 DATATYPE OFF,那么所有数据将作为字符串键入。此选项不影响生成 WSDL 文档。

      由于授权已关闭,因此任何人都可使用此服务而无需提供用户名和口令。命令在用户 DBA 下运行。这种安排虽然简单,但不安全。

    3. 创建一个 DISH 服务以充当 SOAP 服务的代理并生成 WSDL 文档。

      CREATE SERVICE "WSDish"
      TYPE 'DISH'
      FORMAT 'CONCRETE'
      GROUP "WS"
      AUTHORIZATION OFF
      SECURE OFF
      USER DBA;
      

      SOAP 和 DISH 服务必须都是 CONCRETE 格式。由于 EmployeeList2 服务在 WS 组中,因此会包括 GROUP 子句。

  3. 查看 DISH 服务自动创建的 WSDL。为此,请打开 Web 浏览器并浏览至以下 URL:[external link] http://localhost:80/demo/WSDish。DISH 服务会自动生成一个 WSDL 文档,该文档将出现在浏览器窗口中。

    特别是要观察被公开的 EmployeeList2Dataset 对象,因为该服务是 CONCRETE 格式并且 EXPLICIT 为 ON。在随后的步骤中,wsimport 应用程序使用此信息为该服务生成一个 SOAP 1.1 客户端接口。

    <s:complexType name="EmployeeList2Dataset">
    <s:sequence>
    <s:element name="rowset">
      <s:complexType>
      <s:sequence>
      <s:element name="row" minOccurs="0" maxOccurs="unbounded">
        <s:complexType>
        <s:sequence>
        <s:element minOccurs="0" maxOccurs="1" name="EmployeeID" 
            nillable="true" type="s:int" /> 
        <s:element minOccurs="0" maxOccurs="1" name="Surname" 
            nillable="true" type="s:string" /> 
        <s:element minOccurs="0" maxOccurs="1" name="GivenName" 
            nillable="true" type="s:string" /> 
        <s:element minOccurs="0" maxOccurs="1" name="StartDate" 
            nillable="true" type="s:date" /> 
        <s:element minOccurs="0" maxOccurs="1" name="TerminationDate" 
            nillable="true" type="s:date" /> 
        </s:sequence>
        </s:complexType>
      </s:element>
      </s:sequence>
      </s:complexType>
    </s:element>
    </s:sequence>
    </s:complexType>
♦  为这些 Web 服务生成 JAX-WS 接口
  1. 在本示例中,Java API for XML Web Services (JAX-WS) 和 Sun Java 1.6.0 JDK 安装在驱动器 C: 上。设置 PATH 环境变量,使其包含 JAX-WS 二进制文件和 JDK 二进制文件。二进制文件位于以下目录中。

    c:\Sun\jaxws-ri\bin
    c:\Sun\SDK\jdk\bin
  2. 在命令提示符处,设置 CLASSPATH 环境变量。

    SET classpath=.;C:\Sun\jaxws-ri\lib\jaxb-api.jar
    ;C:\Sun\jaxws-ri\lib\jaxws-rt.jar
  3. 下一步是生成调用 Web 服务所需的接口。

    在同一命令提示符处,创建一个新的项目目录,并使该目录成为您的当前目录。在此目录中执行以下命令。

    wsimport -keep -Xendorsed "http://localhost:80/demo/WSDish"

    该 wsimport 工具从给定的 URL 中检索 WSDL 文档,并生成为其定义接口的 Java 文件,然后编译 Java 文件。

    keep 选项将指示 wsimport 不要删除 .java 文件。如果不使用此选项,则会在生成相应的 .class 文件后删除这些文件。如果保存这些文件,会更易于检查接口的组成。

    Xendorsed 选项允许您使用 JDK6 版的 JAX-WS 2.1 API。

    此命令完成后,会在您的当前目录中生成一个名为 localhost\demo\ws 的新子目录结构,其中包含以下 Java 文件,以及每个 Java 文件编译后的 .class 版本。

    EmployeeList2.java
    EmployeeList2Dataset.java
    EmployeeList2Response.java
    FaultMessage.java
    ObjectFactory.java
    package-info.java
    WSDish.java
    WSDishSoapPort.java
♦  使用生成的 JAX-WS 接口
  1. 将以下 Java 源代码保存到 SASoapDemo2.java 中。确保该文件位于含有 localhost 子目录(由 wsimport 工具生成)的同一目录中。

    // SASoapDemo2.java illustrates a web service client that
    // calls the WSDish service and prints out the data.
    
    import java.util.*;
    import javax.xml.ws.*;
    import org.w3c.dom.Element;
    import org.w3c.dom.Node;
    import javax.xml.datatype.*;
    import localhost.demo.ws.*;
    
    public class SASoapDemo2
    {
      public static void main( String[] args )
      {
        try {
          WSDish service = new WSDish();
    
          Holder<EmployeeList2Dataset> response = 
              new Holder<EmployeeList2Dataset>();
          Holder<Integer> sqlcode = new Holder<Integer>();
                
          WSDishSoapPort port = service.getWSDishSoap();
    
          // This is the SOAP service call to EmployeeList2
          port.employeeList2( response, sqlcode );
    
          EmployeeList2Dataset result = response.value;
          EmployeeList2Dataset.Rowset rowset = result.getRowset();
    
          List<EmployeeList2Dataset.Rowset.Row> rows = rowset.getRow();
    
          String fieldType;
          String fieldName;
          String fieldValue;
          Integer fieldInt;
          XMLGregorianCalendar fieldDate;
          
          for ( int i = 0; i < rows.size(); i++ ) {
            EmployeeList2Dataset.Rowset.Row row = rows.get( i );
    
            fieldType = row.getEmployeeID().getDeclaredType().getSimpleName();
            fieldName = row.getEmployeeID().getName().getLocalPart();
            fieldInt = row.getEmployeeID().getValue();
            System.out.println( "(" + fieldType + ")" + fieldName + 
                                "=" + fieldInt );
            
            fieldType = row.getSurname().getDeclaredType().getSimpleName();
            fieldName = row.getSurname().getName().getLocalPart();
            fieldValue = row.getSurname().getValue();
            System.out.println( "(" + fieldType + ")" + fieldName + 
                                "=" + fieldValue );
            
            fieldType = row.getGivenName().getDeclaredType().getSimpleName();
            fieldName = row.getGivenName().getName().getLocalPart();
            fieldValue = row.getGivenName().getValue();
            System.out.println( "(" + fieldType + ")" + fieldName + 
                                 "=" + fieldValue );
            
            fieldType = row.getStartDate().getDeclaredType().getSimpleName();
            fieldName = row.getStartDate().getName().getLocalPart();
            fieldDate = row.getStartDate().getValue();
            System.out.println( "(" + fieldType + ")" + fieldName + 
                                "=" + fieldDate );
            
            if ( row.getTerminationDate() == null ) {
              fieldType = "unknown";
              fieldName = "TerminationDate";
              fieldDate = null;
            } else {
              fieldType = 
                row.getTerminationDate().getDeclaredType().getSimpleName();
              fieldName = row.getTerminationDate().getName().getLocalPart();
              fieldDate = row.getTerminationDate().getValue();
            }
            System.out.println( "(" + fieldType + ")" + fieldName + 
                                "=" + fieldDate );
            System.out.println();
          }
        }
        catch (Exception x) {
          x.printStackTrace();
        }
      }
    }

    如果您选择使用一个不同的端口号(如 8080)来启动 web 服务器,则必须将 [import localhost] 源行更改为如下形式:

    import localhost._8080.demo.ws.*;
  2. 编译 SASoapDemo2.java

    javac SASoapDemo2.java
  3. 运行编译过的类文件。

    java SASoapDemo2

    当应用程序向 Web 服务器发送请求时,它会收到一个包含 EmployeeList2Result(带有含有几个行条目的行集)的 XML 结果集响应。此响应中还包含执行查询的 sqlcode 结果。响应的示例如下所示。

    <tns:EmployeeList2Response>
     <tns:EmployeeList2Result xsi:type='tns:EmployeeList2Dataset'>
      <tns:rowset>
        <tns:row>...</tns:row>
    .
    .
    .
        <tns:row>...</tns:row>
       </tns:rowset>
     </tns:EmployeeList2Result>
     <tns:sqlcode>0</tns:sqlcode>
    </tns:EmployeeList2Response>

    行集中的每行均以类似如下的格式发送。

    <tns:row>
       <tns:EmployeeID xsi:type="xsd:int">1751</tns:EmployeeID>
       <tns:Surname xsi:type="xsd:string">Ahmed</tns:Surname>
       <tns:GivenName xsi:type="xsd:string">Alex</tns:GivenName>
       <tns:StartDate xsi:type="xsd:date">1994-07-12-04:00</tns:StartDate>
       <tns:TerminationDate xsi:type="xsd:date">2008-04-18-04:00
           </tns:TerminationDate>
    </tns:row>

    请注意,列名和数据类型包括在内。

    使用代理

    您可以通过使用记录 XML 消息流量的代理软件来观察上面所示的响应。代理软件置身于客户端应用程序和 Web 服务器之间。

    SASoapDemo2 应用程序将以 (type)column name=value 对的形式显示 EmployeeList2 结果集。将生成如下所示的几行输出。

    (Integer)EmployeeID=102
    (String)Surname=Whitney
    (String)GivenName=Fran
    (XMLGregorianCalendar)StartDate=1984-08-28-04:00
    (unknown)TerminationDate=null
    
    (Integer)EmployeeID=105
    (String)Surname=Cobb
    (String)GivenName=Matthew
    (XMLGregorianCalendar)StartDate=1985-01-01-05:00
    (unknown)TerminationDate=null
    .
    .
    .
    (Integer)EmployeeID=1740
    (String)Surname=Nielsen
    (String)GivenName=Robert
    (XMLGregorianCalendar)StartDate=1994-06-24-04:00
    (unknown)TerminationDate=null
    
    (Integer)EmployeeID=1751
    (String)Surname=Ahmed
    (String)GivenName=Alex
    (XMLGregorianCalendar)StartDate=1994-07-12-04:00
    (XMLGregorianCalendar)TerminationDate=2008-04-18-04:00

    请注意,仅当 TerminationDate 列值为非 NULL 时,才发送它。Java 应用程序用于检测 TerminationDate 列何时不出现。对于本示例,Employees 表的最后一行被改动,因此将设置一个非 NULL 终止日期。

    还应注意,日期值包含一个 UTC 时间偏移值。在上面的示例数据中,服务器位于北美东部时区。如果不执行夏令时,该时区的时间比 UTC 时间早 5 个小时 (-05:00);如果执行夏令时,该时区的时间比 UTC 时间早 4 个小时 (-04:00)。

    要进一步了解 SASoapDemo2 应用程序中使用的 Java 方法,值得研究一下 java.sun.com Web 站点 ([external link] http://java.sun.com/javaee/5/docs/api/) 上的 javax.xml.bind.JAXBElement 类文档。