Thomson-Blog ( 学习,学习,再学习;努力,努力,再努力。)
在学习的路上不断成长,成功之路就在脚下。

JAX-WS数据映射

参考:

http://www.ibm.com/developerworks/cn/webservices/ws-tip-jaxwsrpc2.html

http://www.ibm.com/developerworks/cn/webservices/ws-tip-jaxwsrpc.html

概述

JAX-WS 2.0 是 JAX-RPC 1.1 的后续版本,通过使用 JAXB (Java Architecture for XML Binding),一种 JCP 定义的技术,它对数据映射方法进行了改进。

       尽管 JAX-WS 2.0 中的一些方面是在 JAX-RPC 1.1 的基础上进行的改进,但其他的部分却是革命性的。例如,JAX-WS 没有提供 XML 模式和 Java 之间的映射,而这是 JAX-RPC 1.1 中的一个重要特性。相反,JAX-WS 使用了另一种 JCP 定义的技术 JAXB (Java Architecture for XML Binding) 2.0,为其完成数据映射。JAX-WS 仅仅提供了 Web 服务调用模型。它不再关心表示应用程序数据的 Java Bean,而仅仅关注于将其提供给目标 Web 服务。

 

简单类型映射

1. JAX-RPC 1.1 JAXB 2.0 XML 简单类型映射的差异

类型

JAX-RPC 1.1

JAXB 2.0

xsd:anySimpleType

java.lang.String

java.lang.Object

xsd:duration

java.lang.String

javax.xml.datatype.Duration(新的类型)

xsd:dateTime

java.util.Calendar

javax.xml.datatype.XMLGregorianCalendar(新的类型)

xsd:time

java.util.Calendar

javax.xml.datatype.XMLGregorianCalendar

xsd:date

java.util.Calendar

javax.xml.datatype.XMLGregorianCalendar

xsd:gYearMonth

java.lang.String

javax.xml.datatype.XMLGregorianCalendar

xsd:gYear

java.lang.String

javax.xml.datatype.XMLGregorianCalendar

xsd:gMonthDay

java.lang.String

javax.xml.datatype.XMLGregorianCalendar

xsd:gMonth

java.lang.String

javax.xml.datatype.XMLGregorianCalendar

xsd:gDay

java.lang.String

javax.xml.datatype.XMLGregorianCalendar

xsd:anyURI

java.net.URI

java.lang.String

xsd:NMTOKENS

java.lang.String[]

java.util.List<java.lang.String>

xsd:IDREF

java.lang.String

java.lang.Object

xsd:IDREFS

java.lang.String[]

java.util.List<java.lang.Object>

xsd:ENTITY

not supported

java.lang.String

xsd:ENTITIES

not supported

java.util.List<java.lang.String>

在 JAX-RPC 和 JAXB 之间,简单类型映射的纯 Java 方面几乎相同,但是 JAXB 映射还使用了新的 Java 注释特性。

在 JAX-RPC 1.1 所生成的 Java Bean 中,您无法区分下面的差别:

  • 元素字段和属性字段
  • 从 minOccurs="0" type="xsd:int" 映射的字段和从 nillable="true" type="xsd:int" 映射的字段
  • 从 type="xsd:string" 映射的字段和从 type="xsd:string" minOccurs="0" 映射的字段

   但由于 JAXB 使用了新的 Java 注释,现在您可以区分出它们之间的差别。@XmlElement 和 @XmlAttribute 注释具有一些选项。其中与本文相关的选项包括:

  • Required:该元素是否必须存在?例如,minOccurs 是否不等于 1?
  • Nillable:该字段是否包含 nillable="true" 属性

XML complexType 元素和属性

<xsd:element name="intField" type="xsd:int"/>

<xsd:element name="intMinField" type="xsd:int" minOccurs="0"/>

<xsd:element name="stringMinField" type="xsd:string" minOccurs="0"/>

<xsd:element name="stringNilField" type="xsd:string" nillable="true"/>

 

<xsd:attribute name="intAttr" type="xsd:int"/>

<xsd:attribute name="intAttrReq" type="xsd:int" use="required"/>

通过 JAXB 2.0 映射为 Java Bean 属性

protected int intField;

protected Integer intMinField;

@XmlElement(required = true)

protected String stringMinField;

@XmlElement(required = true, nillable = true)

protected String stringNilField;

 

@XmlAttribute

protected Integer intAtt;

@XmlAttribute(required = true)

protected int intAttReq;

 

数组映射

    在 JAX-RPC 和 JAXB 之间,从 XML 到 Java 的数组映射存在着差异,这是因为 JAXB 使用了新的泛型 Java 特性.

    注意访问器方法中的差别。JAX-RPC 映射遵循 Java Bean 数组访问器的严格定义。JAXB 映射并没有映射为数组,所以有些不同。getIntArrayField 返回一个引用,不仅仅是快照,而是实际的列表。因此,您对返回的列表所做的任何修改都将出现在属性中。这就是为什么对于数组属性没有 set 方法的原因。

Address.java

@XmlElement(required = true)

protected List<String> street;

    public List<String> getStreet() {

        if (street == null) {

            street = new ArrayList<String>();

        }

        return this.street;

    }

 

复杂类型的映射

     在 JAX-RPC 和 JAXB 中,对 complexType 的映射几乎相同,除了这些字段在 JAX-RPC 中是私有的,而在 JAXB 中是保护的,并且 JAXB 映射添加了相应的注释对字段顺序进行描述。

Address.java

@XmlAccessorType(XmlAccessType.FIELD)

@XmlType(name = "Address", propOrder = {

    "name",

    "street",

    "city",

    "country"

})

public class Address {

    @XmlElement(required = true)

    protected String name;

    @XmlElement(required = true)

    protected List<String> street;

    @XmlElement(required = true)

    protected String city;

    @XmlElement(required = true)

    protected String country;

 

ObjectFactory

      JAXB 生成了一个文件 ObjectFactory,而 JAX-RPC 则没有。每个包含 Java Bean 的目录都会有一个 ObjectFactory。对于在模式相应的命名空间中定义的每种类型,ObjectFactory 类都为该类型提供了一种创建方法。对于每个元素,ObjectFactory 类提供了一种创建元素的方法,该方法返回一个 javax.xml.bind.JAXBElement<Type>。例如,下面JAXBElement<BookOrderResponse>的例子,这个ObjectFactory类具有一个返回BookOrder的实例和一个返回 JAXBElement<BookOrder> 的实例的方法。您仍然可以直接实例化该目录中的 Java Bean,但最好是使用这个工厂。

ObjectFactory.java

package org.example.cxfstp04;

 

import javax.xml.bind.JAXBElement;

import javax.xml.bind.annotation.XmlElementDecl;

import javax.xml.bind.annotation.XmlRegistry;

import javax.xml.namespace.QName;

 

@XmlRegistry

public class ObjectFactory {

 

    private final static QName _BookOrderResponse_QNAME = new QName("http://www.example.org/cxfstp04/", "BookOrderResponse");

    private final static QName _BookOrder_QNAME = new QName("http://www.example.org/cxfstp04/", "BookOrder");

 

    public ObjectFactory() {

    }

    public USAddress createUSAddress() {

        return new USAddress();

}

// 返回BookOrder的方法

    public BookOrder createBookOrder() {

        return new BookOrder();

    }

    public BookOrderResponse createBookOrderResponse() {

        return new BookOrderResponse();

    }

    public Book createBook() {

        return new Book();

    }

    public UKAddress createUKAddress() {

        return new UKAddress();

    }

    public BriefUSAddress createBriefUSAddress() {

        return new BriefUSAddress();

    }

    public Address createAddress() {

        return new Address();

    }

    @XmlElementDecl(namespace = "http://www.example.org/cxfstp04/", name = "BookOrderResponse")

    public JAXBElement<BookOrderResponse> createBookOrderResponse(BookOrderResponse value) {

        return new JAXBElement<BookOrderResponse>(_BookOrderResponse_QNAME, BookOrderResponse.class, null, value);

    }

@XmlElementDecl(namespace = "http://www.example.org/cxfstp04/", name = "BookOrder")

//返回一个JAXBElement<BookOrder>的方法

    public JAXBElement<BookOrder> createBookOrder(BookOrder value) {

        return new JAXBElement<BookOrder>(_BookOrder_QNAME, BookOrder.class, null, value);

    }

}

 

实现代码

实现的业务代码包括:

  • 数据类实现.
  • OrderBook服务的实现.
  • 测试的客户代码.

 

数据类实现

Address.java

 protected List<String> street;

 public List<String> getStreet() {

        if (street == null) {

            street = new ArrayList<String>();

        }

        return this.street;

    }

    // 因为street定义成List,缺省设置List没有实现,需要手工添加

    public void setStreet (int _lineN, String _street) {

    if (street == null) {

            street = new ArrayList<String>();

            street.add(0, _street);

        }

    else {

            street.add(_lineN, _street);

    }

    }

BookOrderResponse.java

    protected List<String> returninfo;

public List<String> getReturninfo() {

        if (returninfo == null) {

            returninfo = new ArrayList<String>();

        }

        return this.returninfo;

    }

    // 返回信息同样也是List实现

    public void setReturninfo (int _lineN, String _info) {

    if (returninfo == null) {

            returninfo = new ArrayList<String>();

            returninfo.add(0, _info);

        }

    else {

            returninfo.add(_lineN, _info);

    }

    }

Address.java

protected XMLGregorianCalendar orderDate;

    public XMLGregorianCalendar getOrderDate() {

        return orderDate;

    }

    public void setOrderDate(XMLGregorianCalendar value) {

        this.orderDate = value;

    }

 

OrderBook服务的实现

OrderBookImpl.java

OrderBook服务的实现流程:获得Web Service的所有请求信息, BookOrder Schema,并且返回相关信息

package org.example.cxfstp04;

 

import java.util.logging.Logger;

import javax.jws.WebMethod;

import javax.jws.WebResult;

 

@javax.jws.WebService(name = "OrderBook", serviceName = "cxfstp04Service",

                      portName = "OrderBookPort",

                      targetNamespace = "http://www.example.org/cxfstp04/",

                      wsdlLocation = "file:/D:/2007/CodeWorm/WebService/SourceCode/CXF/cxfstp03/wsdl/cxfstp04.wsdl" ,

                    endpointInterface = "org.example.cxfstp04.OrderBook")

                     

public class OrderBookImpl implements OrderBook {

 

    private static final Logger LOG = Logger.getLogger(OrderBookImpl.class.getName());

    public org.example.cxfstp04.BookOrderResponse orderBookOper(org.example.cxfstp04.BookOrder parameters) {

        LOG.info("Executing operation orderBookOper");

        System.out.println(parameters);

        try {

            //创建BookOrderResponse返回对象

            //采用ObjectFactory方法

org.example.cxfstp04.ObjectFactory _objfactory = new org.example.cxfstp04.ObjectFactory();

               org.example.cxfstp04.BookOrderResponse _return = _objfactory.createBookOrderResponse();

            _return.setReturn("OK");

            //设置返回值的状态为”OK”

            _return.setReturn("OK");

            //获得Web Service请求中的AccountName和AccountNumber信息

            String _info_0 = "AccountName is: '" + parameters.getAccountName()+ "' and AccountNumber is : '" +parameters.getAccountNumber()+ "'";

            //获得ship地址信息

            org.example.cxfstp04.UKAddress _shipAddress = ((org.example.cxfstp04.UKAddress)(parameters.shipAddress));

            String _info_1 = _shipAddress.getName()+" "+  _shipAddress.getCity()+" "+ _shipAddress.getCountry() +" "+ _shipAddress.getPostcode();

            String _shipstreet = "";

            for (int _i=0; _i<_shipAddress.getStreet().size(); _i++)

                   _shipstreet =       _shipstreet +" "+ _shipAddress.getStreet().get(_i);

            //获得billing地址信息

            org.example.cxfstp04.BriefUSAddress _billAddress = ((org.example.cxfstp04.BriefUSAddress)(parameters.billAddress));

            String _info_2 = _billAddress.getName()+" "+_billAddress.getZip();

            String _billstreet ="";

            for (int _i=0; _i<_billAddress.getStreet().size(); _i++)

                   _billstreet +=       _billAddress.getStreet().get(_i);

            //获得书的信息

            String _info_3 = "BOOK Name, Quantity and Wholesale-prise is: '" + parameters.getBook().getTitle() + " , " +  parameters.getBook().getQuantity() + " , " + parameters.getBook().getWholesalePrice()+ "'";

            //获得书总价信息

            String _info_4 = "Total " + parameters.getTotal();

            //获得订单时间信息

            String _info_5 = "The Orderdate is: " + parameters.getOrderDate().getYear()+" , "+parameters.getOrderDate().getMonth()+" , "+parameters.getOrderDate().getDay();

            //设置所有返回信息

            _return.setReturninfo(0, _info_0);

            _return.setReturninfo(1, "shiping address is :" + _info_1+_shipstreet);

            _return.setReturninfo(2, "biliing address is :" + _info_2+_billstreet);

            _return.setReturninfo(3, _info_3);

            _return.setReturninfo(4, _info_4);

            _return.setReturninfo(5, _info_5);

            return _return;

        } catch (Exception ex) {

            ex.printStackTrace();

            throw new RuntimeException(ex);

        }

    }

}

 

测试的客户代码

OrderBook_OrderBookPort_Client.java

package org.example.cxfstp04;

 

import java.io.File;

import java.net.MalformedURLException;

import java.net.URL;

import javax.xml.namespace.QName;

import javax.xml.datatype.DatatypeFactory;

import javax.xml.datatype.XMLGregorianCalendar;

 

public final class OrderBook_OrderBookPort_Client {

    private static final QName SERVICE_NAME = new QName("http://www.example.org/cxfstp04/", "cxfstp04Service");

    private OrderBook_OrderBookPort_Client() {

    }

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

        if (args.length == 0) {

            System.out.println("please specify wsdl");

            System.exit(1);

        }

        URL wsdlURL = null;

        File wsdlFile = new File(args[0]);

        try {

            if (wsdlFile.exists()) {

                wsdlURL = wsdlFile.toURL();

            } else {

                wsdlURL = new URL(args[0]);

            }

        } catch (MalformedURLException e) {

            e.printStackTrace();

        }

      

        Cxfstp04Service ss = new Cxfstp04Service(wsdlURL, SERVICE_NAME);

        OrderBook port = ss.getOrderBookPort(); 

       

 

        System.out.println("Invoking orderBookOper...");

        // Add By bldmickey      

        org.example.cxfstp04.BookOrder _orderBookOper_parameters = new org.example.cxfstp04.BookOrder();

        // 设置帐号名和帐号

        _orderBookOper_parameters.setAccountName("Amazon.com");

        _orderBookOper_parameters.setAccountNumber(923);

        // 设置Ship地址和Billing地址

        org.example.cxfstp04.UKAddress _ship_address = new org.example.cxfstp04.UKAddress();

        org.example.cxfstp04.BriefUSAddress _bill_address = new org.example.cxfstp04.BriefUSAddress();

        _ship_address.setName("Amazon.co.uk");

        //因为街道可以有多行,代码生成的是字符串List

        _ship_address.setStreet(0,"line1: Ridgmont Road");

        _ship_address.setStreet(1,"line2: Ridgmont Road");

        _ship_address.setCity("Bedford");

        _ship_address.setCountry("United Kingdom");

        _ship_address.setPostcode("MK43 0ZA");

        _bill_address.setName("Amazon.com");

        _bill_address.setStreet(0,"line1: 1516 2nd Ave");

        _bill_address.setStreet(1,"line2: 1516 2nd Ave");

        _bill_address.setStreet(2,"line3: 1516 2nd Ave");

        _bill_address.setZip("90952");

        // 设置图书信息

        org.example.cxfstp04.Book _book = new org.example.cxfstp04.Book();

        _book.setTitle("Java Web Services");

        _book.setQuantity(300);

        _book.setWholesalePrice(24.99f);

        _orderBookOper_parameters.setShipAddress(_ship_address);

        _orderBookOper_parameters.setBillAddress(_bill_address);

        _orderBookOper_parameters.setBook(_book);

        _orderBookOper_parameters.setTotal(8997.00f);

// 对于时间JAXB缺省绑定成XMLGregorianCalendar类型,参见

//http://java.sun.com/j2se/1.5.0/docs/api/javax/xml/datatype/XMLGregorianCalendar.html

        XMLGregorianCalendar _orderdate= DatatypeFactory.newInstance().newXMLGregorianCalendar();

        _orderdate.setYear(2007);

        _orderdate.setMonth(9);

        _orderdate.setDay(8);

        _orderdate.setTimezone(0);

        _orderBookOper_parameters.setOrderDate(_orderdate);

 

        org.example.cxfstp04.BookOrderResponse _orderBookOper__return = port.orderBookOper(_orderBookOper_parameters);

        System.out.println("The Status of Return is : " + _orderBookOper__return.getReturn());

        for (int _i=0; _i<_orderBookOper__return.getReturninfo().size(); _i++)

               System.out.println("Return info " + _i +" is: " + _orderBookOper__return.getReturninfo().get(_i));

        //System.out.println("orderBookOper.result=" + _orderBookOper__return);

 

        System.exit(0);

    }

 

}

 

简单测试

运行测试服务器:

  • 菜单选择Run->Open Run Dialog…->选择Java Application ->选择OrderBookServer_server_cxfstp04->Main Class设置为: org.example.cxfstp04.OrderBook_OrderBookPort_Server->选择Run

 

运行服务器后显示类似如下:

……

INFO: Started SelectChannelConnector @ 0.0.0.0:9090

Server ready...

 

运行测试客户端

  • 菜单选择Run->Open Run Dialog…->选择Java Application ->选择OrderBookClient_client_cxfstp04->Main Class设置为: org.example.cxfstp04.OrderBook_OrderBookPort_Client->选择Run

  

运行测试客户端后显示如下:

INFO: Creating Service {http://www.example.org/cxfstp04/}cxfstp04Service from WSDL: file:/D:/2007/CodeWorm/WebService/SourceCode/CXF/cxfstp03/wsdl/cxfstp04.wsdl

Invoking orderBookOper...

The Status of Return is : OK

Return info 0 is: AccountName is: 'Amazon.com' and AccountNumber is : '923'

Return info 1 is: shiping address is :Amazon.co.uk Bedford United Kingdom MK43 0ZA line1: Ridgmont Road line2: Ridgmont Road

Return info 2 is: biliing address is :Amazon.com 90952line1: 1516 2nd Aveline2: 1516 2nd Aveline3: 1516 2nd Ave

Return info 3 is: BOOK Name, Quantity and Wholesale-prise is: 'Java Web Services , 300 , 24.99'

Return info 4 is: Total 8997.0

Return info 5 is: The Orderdate is: 2007 , 9 , 8

 

 

TcpMonitor

  • 运行tcpmonitor

          设置目的服务地址和端口号loclhost:9090(服务器)

          设置监听的端口为8888

 
  • 运行客户端

         修改测试客户端的wsdl参数. 客户端测试代码中,从命令行参数中获得wsdl文件的路径,从中获得请求服务的信息

OrderBook_OrderBookPort_Client.java

wsdlURL = new URL(args[0]);

Cxfstp04Service ss = new Cxfstp04Service(wsdlURL, SERVICE_NAME);

        修改wsdl中的服务地址,从原来的localhost:9090改成localhost:8888,意思将服务请求发送到tcpmonitor的8888端口,由tcpmonitor转发给9090

cxfstp04_test.wsdl

<wsdl:service name="cxfstp04Service">

    <wsdl:port name="OrderBookPort" binding="ns1:cxfstp04ServiceBinding">

      <soap:address location="http://localhost:8888/OrderBook"/>

    </wsdl:port>

</wsdl:service>

         菜单选择Run->Open Run Dialog…->选择Java Application ->选择OrderBookClient_client_cxfstp04_testing->Main Class设置为: org.example.cxfstp04.OrderBook_OrderBookPort_Client->在参数中设置程序的参数为: 修改后的cxfstp04_test.wsdl->选择Run

 

请求和返回

  • TCPMonitor返回的结果
省略

省略

 

服务部署

详细参见:<< Eclipse Apache CXF集成.doc>>

  • 启动本地的tomcat服务器
  • 菜单选择File->New->Other…->选择SOA Tools->Deployment Profile后选择Next;
  • 在scxstp04中点击wsdl,在File Name中输入:scxstp04Deploy,如下图:选择Next;
  • 在Deployment Description选择继续;Package中选择继续;Target Server选择继续;Summary中选择Finish
  • 在wsdl目录下将创建scxstp04Deploy.deploy项,右边显示deploy文件,在文件显示框中选择Configuration Tab
  • 选择Add Target…->在弹出对话框中选择刚才启动的“Tomcat v5.5 Server at localhost”,选择OK,在Server框中将显示刚才添加的target server。
  • 选择Create Target
  • 选择Deploy Package
  • 查看Console Tab,将显示Package Deploy的状态(类似下面的log)

INFO: Creating Service {http://www.example.org/cxfstp04/}cxfstp04Service from WSDL: WEB-INF/wsdl/cxfstp04.wsdl

客户端测试

  • Web 测试wsdl

浏览器中输入: http://localhost:8081/cxfstp04/services/cxfstp04?wsdl

 
  • 考虑到目前tomcat监听在8081端口,所以修改测试wsdl文件

cxfstp04_testtomcat.wsdl

<wsdl:service name="cxfstp04Service">

    <wsdl:port name="OrderBookPort" binding="ns1:cxfstp04ServiceBinding">

      <soap:address location="http://localhost:8081/cxfstp04/services/cxfstp04"/>

    </wsdl:port>

</wsdl:service>

  • 运行客户端,输出结果

省略

 

部署到生产服务器

posted on 2008-11-17 11:25  Thomson-Blog  阅读(861)  评论(0编辑  收藏  举报