Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Делаем веб сервис сверху вниз от WSDL до БД(JBOSS), JBOSS: WSDL->JAVA->HIBERNATE->DB 
:(
    Опции темы
sl_ava
Дата 18.8.2007, 17:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 20.1.2007

Репутация: 1
Всего: 3



Вариант 1 : создание HIBERNATE mapping файлов. Может напрямую использоваться для простых проектов. Можно модифицировать для более сложных ( скачать ).

Как известно существует 2 метода разработки веб-сервисов :
снизу вверх (bottom-up) от JAVA-классов к SOAP-интерфейсу, т. е. генерирование определений для веб-сервиса (WSDL) на основе JAVA-классов
сверху вниз (top-down) от WSDL к реализации сервиса в JAVA классах. В этом случае наоборот из определений веб-сервиса создаются JAVA классы
Каждый метод имеет свою область применения, свои плюсы и минусы. Я использую вариант разработки приложения сверху вниз в случаях построения веб-сервиса с нуля.
 

Создаются 2 файла : XSD - содержащий определения базовой объектной структуры проекта и WSDL, который определяет интерфейс и объекты взаимодействия (запросы и ответы, случай Document/Literal ). Причем XSD включен в WSDL посредством "xsd:import". Эти 2 файла компактно представляют предметную область проекта и связи между базовыми объектами (XSD) а также взаимодействие с внешним миром (WSDL). Затем я пользуюсь стандартными генераторами для создания всех необходимых классов. В случае Axis это Wsdl2java а в случае JbossWS - wsconsume. Остается только добавить логику в приготовленный скелет.

Однако есть еще некоторые возможности для облегчения работы программиста в случае разработки проекта сверху-вниз. Поскольку все определения компактно собраны в одном месте и причем в структурированном виде, как XML файл, то можно воспользоваться этим для автоматического создания не только классов но и базы данных а возможно и заготовок для реализации логики проекта. Раньше я автоматически генерировал структуру БД и некоторые вспомогательные классы для работы с БД .

С появлением продуктов типа HIBERNATE для реализации уровня управления данными, возникли более простые пути генерирования сущностей для связи с БД. Достаточно просто создать конфигурационные файлы HIBERNATE и мы автоматически получим не только базу данных но и мощный инструмент управления данными. При этом для генерирования нам не нужно ничего кроме ANT ( ant.apache.org ) с расширениями ( ant-contrib.sourceforge.net ).

Поскольку речь идет о статическом преобразовании XML (XSD->конфигурационные файлы) то самое разумное - использовать для этого специальный инструмент, разработанный именно для этой цели, т.е. XSL(T). Файлы конфигурации создаются из XSD с помощью задания <xslt> из стандартного набора АНТа и специально приготовленных XSL файлов.


Пример.

Рассмотрим на примере (исходники примера без библиотек лежат тут ). Файл с техническими деталями readme.txt находится в корневой папке ztest. Нужно сначала все правильно сконфигурировать как написано в readme.txt.

Создаем определения будущей системы. XSD представляет предметную область: продукты (ZProduct) и заказы (ZOrder), которые могут содержать продукты:
Код

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

<xsd:schema version="0.1" id="ztest.xsd.0.1"
targetNamespace="http://www.opentest.org/model/mytest"
xmlns:typens="http://www.opentest.org/model/mytest"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:my="http://my.personal.param">

<xsd:element name="zOrder">
<xsd:annotation>
<xsd:documentation xml:lang="en">Order object</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="id" type="xsd:int">
<xsd:annotation>
<xsd:documentation xml:lang="en">ID field is requred for Hibernate mapping,
it is requred (minOccurs="1" and maxOccurs="1" by default)</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="clientid" type="xsd:int">
<xsd:annotation>
<xsd:documentation xml:lang="en">ID of client</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="created" type="xsd:dateTime" minOccurs="0">
<xsd:annotation>
<xsd:documentation xml:lang="en">timestamp for the order</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="descr" minOccurs="0">
<xsd:annotation>
<xsd:documentation xml:lang="en">Order notes, simple text, optional, restricted length.
In object model definition we should care about strings length to create correct DB automatically</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="128"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element ref="typens:zProduct" minOccurs="1" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>

<xsd:element name="zProduct">
<xsd:annotation>
<xsd:documentation xml:lang="en">Product object</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="id" type="xsd:int">
<xsd:annotation>
<xsd:documentation xml:lang="en">ID field is requred for Hibernate mapping</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="name">
<xsd:annotation>
<xsd:documentation xml:lang="en">Product name</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="32"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="type">
<xsd:annotation>
<xsd:documentation xml:lang="en">Type of the Product</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="16"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>

</xsd:schema>



Для правильной работы с HIBERNATE полезно добавить в каждый объект-элемент его идентификатор- ID. В этом примере предполагается что только объекты с ID должны конфигурироваться для уровня управления данными, т.е. если ID не определен, то HIBERNATE файл не создается
WSDL определяет внешний интерфейс :

Код

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

<definitions name="ztest"
targetNamespace="http://base.ztest.com"
xmlns:tns="http://base.ztest.com"
xmlns:typens="http://www.opentest.org/model/mytest"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns="http://schemas.xmlsoap.org/wsdl/">

<types>

<xsd:schema version="0.1" id="ztest.xsd.0.1"
targetNamespace="http://base.ztest.com"
xmlns:typens="http://www.opentest.org/model/mytest"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<!-- Incklude basic object model definitions -->
<xsd:import namespace="http://www.opentest.org/model/mytest" schemaLocation="ztest.xsd"/>

<!-- Elements for Request/Responce definitions -->
<xsd:element name="createProductRQ">
<xsd:annotation>
<xsd:documentation xml:lang="en">creating order request object</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="typens:zProduct"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="createProductRS">
<xsd:annotation>
<xsd:documentation xml:lang="en">creating order responce object, returns new product's ID</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="id" type="xsd:int"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>

<xsd:element name="createOrderRQ">
<xsd:annotation>
<xsd:documentation xml:lang="en">creating order request object</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="typens:zOrder"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="createOrderRS">
<xsd:annotation>
<xsd:documentation xml:lang="en">creating order responce object, returns new order's ID</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="id" type="xsd:int"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>

<xsd:element name="findOrdersRQ">
<xsd:annotation>
<xsd:documentation xml:lang="en">find order by client ID, request object</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="clientid" type="xsd:int"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="findOrdersRS">
<xsd:annotation>
<xsd:documentation xml:lang="en">find order response object</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="typens:zOrder" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</types>

<!-- Messages definitions -->
<message name="empty"/>

<message name="createProductRQMsg">
<part name="arg" element="tns:createProductRQ"/>
</message>
<message name="createProductRSMsg">
<part name="rez" element="tns:createProductRS"/>
</message>

<message name="createOrderRQMsg">
<part name="arg" element="tns:createOrderRQ"/>
</message>
<message name="createOrderRSMsg">
<part name="rez" element="tns:createOrderRS"/>
</message>

<message name="findOrdersRQMsg">
<part name="arg" element="tns:findOrdersRQ"/>
</message>
<message name="findOrdersRSMsg">
<part name="rez" element="tns:findOrdersRS"/>
</message>

<!-- Port -->
<portType name="ztestServer">
<operation name="createProduct">
<documentation>Create a new Product</documentation>
<input message="tns:createProductRQMsg"/>
<output message="tns:createProductRSMsg"/>
</operation>
<operation name="createOrder">
<documentation>Create a new Order</documentation>
<input message="tns:createOrderRQMsg"/>
<output message="tns:createOrderRSMsg"/>
</operation>
<operation name="findOrders">
<documentation>Find orders</documentation>
<input message="tns:findOrdersRQMsg"/>
<output message="tns:findOrdersRSMsg"/>
</operation>
</portType>

<!-- Binding -->
<binding name="ztestSOAPBinding" type="tns:ztestServer">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="createProduct">
<soap:operation style="document" soapAction=""/>
<input><soap:body use="literal"/></input>
<output><soap:body use="literal"/></output>
</operation>
<operation name="createOrder">
<soap:operation style="document" soapAction=""/>
<input><soap:body use="literal"/></input>
<output><soap:body use="literal"/></output>
</operation>
<operation name="findOrders">
<soap:operation style="document" soapAction=""/>
<input><soap:body use="literal"/></input>
<output><soap:body use="literal"/></output>
</operation>
</binding>

<!-- Services -->
<service name="ztestService">
<port name="ztestPort" binding="tns:ztestSOAPBinding">
<soap:address location="http://localhost:8080/ws/ztestService"/>
</port>
</service>

</definitions>



Генерирование исходников.

Запускаем "build.bat generate.source". Выполняется задание org.jboss.wsf.spi.tools.ant.WSConsumeTask из инструментария JbossWS 2.0, которое создает все нужные для самого WS исходники. Созданные WSConsume JAVA классы к сожалению не годятся напрямую для работы с HIBERNATE поскольку для элементов типа List не определен "сеттер" (как например setZOrder(List<ZOrder> ...) ). Поэтому пришлось добавить недостающие методы. Они создаются поочередно для каждого класса с помощью generate.java-addition.xsl и затем добавляются в исходник. Создается также класс *Impl.java как скелет для реализации собственно логики (если он отсутствует). На этом этапе можно уже наполнять этот класс каким-то содержанием - положить что-то в БД, выбрать и т.п.

Вообще можно было бы на этом шаге сделать не простой скелет сервера но сразу включить в него автоматически какие-то методы работы с данными в тех методах, где они могут понадобиться. Пока я этого не сделал.

Создание конфигурации HIBERNATE

Запускаем "build.bat generate.hibernate". Файлы отображения классов в БД создаются по одному для каждого соответствующего класса. Например для класса ZOrder.java будет создан ZOrder.hbm.xml. Затем создается общий конфигурационный файл hibernate.cfg.xml.

Запуск

Теперь можно выложить приложение на сервер "build.bat deploy". По умолчанию приложение находится по адресу http://localhost/mycontext/zservice?wsdl Чтобы заменить на другой адрес измените в файле ZtestServerImpl.java строку :

"@WebContext( contextRoot = "/mycontext" , urlPattern="/zservice" )"

Чтобы потестировать приложение запускаем "build.bat testclient". Тест находится тут ztest\src\com\ztest\base\ZtestServerTest.java. Что происходит тут?

Код

ZProduct prod1 = new ZProduct();
prod1.setName("Apple");
prod1.setType("fruit");

CreateProductRQ rq1= new CreateProductRQ();
rq1.setZProduct(prod1);

CreateProductRS rs1= server.createProduct(rq1);
prod1.setId(rs1.getId());


Создается объект Zproduct и передается на сохранение серверу. При этом на сервере происходит следующее :

Код

Session session = getSessionFactory().getCurrentSession();
session.beginTransaction();
session.save(arg.getZProduct());
session.getTransaction().commit();

CreateProductRS rs = new CreateProductRS();
rs.setId(arg.getZProduct().getId());

return rs;


HIBERNATE позаботился о сохранении объекта в БД и при этом присвоил ему ID. Этот ID возвращается клиенту.

Также создается объект prod2.

Теперь создадим заказ, содержащий 2 уже существующих продукта :

Код

ZOrder ord1 = new ZOrder();
ord1.setClientid(1);
ord1.setDescr("description ....");
ord1.setCreated(null);
ord1.getZProduct().add(prod1);
ord1.getZProduct().add(prod2);

CreateOrderRQ rq3= new CreateOrderRQ();
rq3.setZOrder(ord1);

CreateOrderRS rs3= server.createOrder(rq3);
ord1.setId(rs3.getId());


Интересно что при сохранении в БД создается новая запись для zOrder и для связей с уже существующими продуктами prod1 prod2.

В следующем примере мы кладем в ДБ заказ с четырьмя продуктами внутри - 2 из них не имеют ID поэтому при сохранении HIBERNATE создает для этих продуктов новые записи в таблице zProduct но естественно не создает записи для уже существующих продуктов.

Теперь запросим список заказов с сервера :

Код

FindOrdersRQ rq4 = new FindOrdersRQ();
rq4.setClientid(1);
FindOrdersRS rs4=server.findOrders(rq4);


На сервере случается вот что :

Код

Session session = getSessionFactory().getCurrentSession();
session.beginTransaction();
List result = session.createQuery("from ZOrder").list();
//when we call .size() children odgects are loaded!
for (Iterator i = result.iterator(); i.hasNext(); ){
((ZOrder)i.next()).getZProduct().size();
}
session.getTransaction().commit();
FindOrdersRS rs = new FindOrdersRS();
rs.getZOrder().addAll(result);
return rs;


Здесь делается странная вещь : ((Zorder)i.next()).getZProduct().size();
Смысл в том, что при такой процедуре родительский объект загружает дочерние.
Можно настроить HIBERNATE конфигурацию объекта так, чтобы объект добывался сразу
с дочерними, но в общем случае это означает много лишней работы, что чаще всего не желательно.

Копия этой статьи тут

Это сообщение отредактировал(а) sl_ava - 18.8.2007, 17:23
PM MAIL   Вверх
maxterbear
Дата 11.10.2010, 17:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 27
Регистрация: 11.10.2010

Репутация: нет
Всего: нет



sl_ava, спасибо! а не подскажите чем можно сгенерировать классы для дотнет платформы?
PM MAIL   Вверх
powerOn
Дата 12.10.2010, 12:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


software saboteur
****


Профиль
Группа: Участник
Сообщений: 4367
Регистрация: 7.10.2005

Репутация: 28
Всего: 159



maxterbear, это Вам лучше в разделе по .NET спросить.


--------------------
user posted image нет времени думать - нужно писать КОД!

PM MAIL   Вверх
Старовъръ
Дата 13.10.2010, 13:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 491
Регистрация: 8.5.2008

Репутация: 1
Всего: 10



sl_ava, скажи, а что ты делаешь, когда нужно добавить что-то новое? Можно, конечно, перегенерировать все сущности, однако тогда все перетирается (мы не можем, например, содержать javadocs в классе в таком случае). Лично я руками все правил/добавлял, но может есть какие-то еще интересные способы?
PM MAIL WWW   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java EE (J2EE) и Spring | Следующая тема »


 




[ Время генерации скрипта: 0.0745 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.