2015-02-05 4 views
2

Мое приложение разделено на два уровня, где бэкэнд-слой предоставляет множество веб-сервисов, а слои представления потребляют те, которые получают бизнес-данные.WS Создание клиента с использованием maven и повторного использования классов

Чтобы сделать мое строительство максимально автоматическим, я упаковываю все полученные в результате WSDL и связанные с ними файлы XSD в зависимость от ZIP (используя плагин ассемблера Maven), который загружается в мою связь на этапе установки.

Затем в UI POM я распакую этот ZIP-файл (с использованием плагина зависимостей maven) в локальный каталог (src/main/resources/wsdl), а затем с помощью CXF-CODEGEN плагина для создания клиентов.

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

Сгенерированный код CXF В конечном итоге у меня есть класс Catalogue (с другим именем пакета) для каждой веб-службы, что приводит к потере возможностей полиморфизма OO в моем коде, поскольку на практике все они являются разными классами.

Я слышал, что вы можете избежать этой проблемы, как-то скомпилировать классы XSD сначала во что-то, называемое «эпизодами», а затем подавать эти файлы эпизодов на CXF, чтобы сказать, чтобы использовать их вместо того, чтобы генерировать классы.

Я пытался добавить дополнительный шаг компиляции, в которой я бегу Maven-jaxb2-плагин для создания классов из XSD, но я получаю исключение org.xml.sax.SAXParseException; (...) 'catalogueDTO' is already defined , поскольку этот класс повторяется по XSD файлов.

Может ли кто-нибудь указать мне правильное направление?

+0

Является ли ваш класс 'catalogue' определенным в одном файле XSD или нескольких файлах XSD? – Namphibian

+0

Несколько, в основном по одному для каждого wsdl –

+0

Ну, это была бы ваша проблема. Скоро ответит. – Namphibian

ответ

2

Если у вас есть базовые классы в ваших веб-сервисах, которые будут использоваться через службы и операции, лучше всего объявить эти классы в одном XSD, а затем включить и использовать этот XSD через ваш проект.

Следующий пример покажет вам, как это сделать. Я основываю этот пример на предоставленной информации, таким образом, это может быть не совсем точный подход к тому, что вам нужно, но покажет вам концепции.

Первая позволяет создать файл Catalog.xsd и объявить наш каталог объект в этом файле следующим кодом:

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

<xs:schema xmlns="http://www.yourcompany.com/Services_V1/CommonType" 
     elementFormDefault="qualified" 
     targetNamespace="http://www.yourcompany.com/Services_V1/CommonType" 
     xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
<xs:simpleType name="CatalogueID_Type"> 
    <xs:annotation> 
     <xs:documentation>The Catalogue ID is an integer value that is used to uniquely identify the catalog item on the database.</xs:documentation> 
    </xs:annotation> 
    <xs:restriction base="xs:int" /> 
</xs:simpleType> 
<xs:simpleType name="CatalogueValue_Type"> 
    <xs:annotation> 
     <xs:documentation>The catalog is a string value that will contain the information describing the catalog key.</xs:documentation> 
    </xs:annotation> 
    <xs:restriction base="xs:string" /> 
</xs:simpleType> 
<xs:complexType name="Catalogue_Type"> 
    <xs:sequence> 
     <xs:element ref="CatalogID" 
        minOccurs="1" 
        maxOccurs="1" /> 
     <xs:element ref="CatalogueValue" 
        minOccurs="0" 
        maxOccurs="1" /> 
    </xs:sequence> 
</xs:complexType> 
<xs:element name="CatalogID" 
      type="CatalogueID_Type" /> 
<xs:element name="CatalogueValue" 
      type="CatalogueValue_Type" /> 
<xs:element name="Catalogue" 
      type="Catalogue_Type" /> 

Или, если вам нравится визуальное представление:

Catalogue XML Object

Следует отметить, что класс/объект каталога имеет пространство имен http://www.yourcompany.com/Services_V1/CommonType, мы будем использовать эти имена снова в нашем WSDL. Этот объект теперь будет использоваться двумя службами службы BathroomCatalogue и службой KicthenCatalogue. Для простоты у меня есть только одна операция в службе под названием GetCatalogueItem. Для каждой из этих служб я буду включать файл catalog.xsd и повторно использовать этот объект каталога.

Вот WSDL для ванной службы:

<?xml version="1.0" encoding="utf-8"?> 
<wsdl:definitions name="BathroomCatalogueSRV" 
       targetNamespace="http://www.yourcompany.com/Services_V1/BathroomCatalogueService" 
       xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
       xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" 
       xmlns:tns="http://www.yourcompany.com/Services_V1/BathroomCatalogueService" 
       xmlns:xs="http://www.w3.org/2001/XMLSchema" 
       xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" 
       xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" 
       xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
       xmlns:catalogue="http://www.yourcompany.com/Services_V1/CommonType"> 
<wsdl:types> 
    <xs:schema elementFormDefault="qualified" 
       targetNamespace="http://example.com/"> 
     <xs:import schemaLocation="Catalog.xsd" 
        namespace="http://www.yourcompany.com/Services_V1/CommonType" /> 

    </xs:schema> 
</wsdl:types> 
<wsdl:message name="GetCatalogueItemReq"> 
    <wsdl:part name="GetCatalogueItemReq" 
       element="catalogue:Catalogue" /> 
</wsdl:message> 
<wsdl:message name="GetCatalogueItemRs"> 
    <wsdl:part name="GetCatalogueItemRs" 
       element="catalogue:Catalogue" /> 
</wsdl:message> 
<wsdl:portType name="BathroomCataloguePortType"> 
    <wsdl:operation name="GetCatalogueItem"> 
     <wsdl:input message="tns:GetCatalogueItemReq" /> 
     <wsdl:output message="tns:GetCatalogueItemRs" /> 
    </wsdl:operation> 
</wsdl:portType> 
<wsdl:binding name="BathroomCatalogueBinding" 
       type="tns:BathroomCataloguePortType"> 
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" 
        style="document" /> 
    <wsdl:operation name="GetCatalogueItem"> 
     <wsdl:input /> 
     <wsdl:output /> 
    </wsdl:operation> 
</wsdl:binding> 
<wsdl:service name="BathroomCatalogueService"> 
    <wsdl:port name="BathroomCataloguePort" 
       binding="tns:BathroomCatalogueBinding"> 
     <soap:address location="http://www.yourcompany.com/Services_V1/BathroomCatalogueService" /> 
    </wsdl:port> 
</wsdl:service> 

Или, если вы хотите, визуальное представление:

Bathroom Service

Кухня WSDL выглядит следующим образом:

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

<wsdl:definitions name="KitchenCatalogueSRV" 
       targetNamespace="http://www.yourcompany.com/Services_V1/KitchenCatalogueService" 
       xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
       xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" 
       xmlns:tns="http://www.yourcompany.com/Services_V1/KitchenCatalogueService" 
       xmlns:xs="http://www.w3.org/2001/XMLSchema" 
       xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" 
       xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" 
       xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
       xmlns:catalogue="http://www.yourcompany.com/Services_V1/CommonType"> 
<wsdl:types> 
    <xs:schema elementFormDefault="qualified" 
       targetNamespace="http://example.com/"> 
     <xs:import schemaLocation="Catalog.xsd" 
        namespace="http://www.yourcompany.com/Services_V1/CommonType" /> 

    </xs:schema> 
</wsdl:types> 
<wsdl:message name="GetCatalogueItemReq"> 
    <wsdl:part name="GetCatalogueItemReq" 
       element="catalogue:Catalogue" /> 
</wsdl:message> 
<wsdl:message name="GetCatalogueItemRs"> 
    <wsdl:part name="GetCatalogueItemRs" 
       element="catalogue:Catalogue" /> 
</wsdl:message> 
<wsdl:portType name="KitchenCataloguePortType"> 
    <wsdl:operation name="GetCatalogueItem"> 
     <wsdl:input message="tns:GetCatalogueItemReq" /> 
     <wsdl:output message="tns:GetCatalogueItemRs" /> 
    </wsdl:operation> 
</wsdl:portType> 
<wsdl:binding name="KitchenCatalogueBinding" 
       type="tns:KitchenCataloguePortType"> 
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" 
        style="document" /> 
    <wsdl:operation name="GetCatalogueItem"> 
     <wsdl:input /> 
     <wsdl:output /> 
    </wsdl:operation> 
</wsdl:binding> 
<wsdl:service name="KitchenCatalogueService"> 
    <wsdl:port name="KitchenCataloguePort" 
       binding="tns:KitchenCatalogueBinding"> 
     <soap:address location="http://www.yourcompany.com/Services_V1/KitchenCatalogueService" /> 
    </wsdl:port> 
</wsdl:service> 

И еще раз визуально:

Kitchen Service

В обоих этих файлах WSDL я включил файл catalog.xsd. Вы можете увидеть это в следующих строках кода:

<xs:import schemaLocation="Catalog.xsd" 
namespace="http://www.yourcompany.com/Services_V1/CommonType" /> 

Теперь, когда я использую эти WSDL и XSD вместе с CXF будет только один каталог объект/класс, используемый обеими службами. Я быстро сделал аа проект оболочки и следующая структура была сгенерирована:.

Project Folders

Обратите внимание, что CatalogueType я объявляю теперь в одном пакете с пространством имен я заявил в

При просмотре классов обслуживания как в ванной, так и в кухне будет использоваться этот класс. В классе обслуживания кухни он использует com.yourcompany.services_v1.commontype.CatalogueType.

@WebService(targetNamespace = "http://www.yourcompany.com/Services_V1/KitchenCatalogueService", name = "KitchenCataloguePortType") 
@XmlSeeAlso({com.yourcompany.services_v1.commontype.ObjectFactory.class}) 
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE) 
public interface KitchenCataloguePortType { 

@WebResult(name = "Catalogue", targetNamespace = "http://www.yourcompany.com/Services_V1/CommonType", partName = "GetCatalogueItemRs") 
@WebMethod(operationName = "GetCatalogueItem") 
public com.yourcompany.services_v1.commontype.CatalogueType getCatalogueItem(
    @WebParam(partName = "GetCatalogueItemReq", name = "Catalogue", targetNamespace = "http://www.yourcompany.com/Services_V1/CommonType") 
    com.yourcompany.services_v1.commontype.CatalogueType getCatalogueItemReq 
); 
} 

А в классе кухня службы он использует com.yourcompany.services_v1.commontype.CatalogueType.

@WebService(targetNamespace = "http://www.yourcompany.com/Services_V1/BathroomCatalogueService", name = "BathroomCataloguePortType") 
@XmlSeeAlso({com.yourcompany.services_v1.commontype.ObjectFactory.class}) 
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE) 
public interface BathroomCataloguePortType { 

@WebResult(name = "Catalogue", targetNamespace = "http://www.yourcompany.com/Services_V1/CommonType", partName = "GetCatalogueItemRs") 
@WebMethod(operationName = "GetCatalogueItem") 
public com.yourcompany.services_v1.commontype.CatalogueType getCatalogueItem(
    @WebParam(partName = "GetCatalogueItemReq", name = "Catalogue", targetNamespace = "http://www.yourcompany.com/Services_V1/CommonType") 
    com.yourcompany.services_v1.commontype.CatalogueType getCatalogueItemReq 
); 
} 

Просто напоминание, что вы никогда не должны изменять эти классы как они получены, и порождены CXF и ваши изменения будут потеряны. Таким образом, делая первый подход WSDL, вы должны убедиться, что вы правильно структурируете свои XSD-файлы и WSDL.

Дайте мне знать, если это имеет смысл.

+0

Ничего себе, это какой-то тщательный ответ ... спасибо за огромное усилие! Это имеет смысл, если я правильно понял, что проблема, с которой я сталкиваюсь, заключается в том, что мои объекты объявляются в каждом WSDL с разными пространствами имен ... Я проверил их, и это действительно так. У меня есть контроль над моими веб-службами, поэтому я мог бы изменить это, если CXF (это то, что я использую для создания WS) позволяет мне явно объявлять пространство имен для моих объектов. –

+0

Ну, я предлагаю вам попробовать. Уверен, у вас будет больше вопросов. Просто помните, что при первом подходе к контракту «сверху вниз» важно, чтобы пространства имен хорошо поддерживались. Эти концепции являются частью управления SOA и жизненно важны для приложения SOA для получения преимуществ SOA. – Namphibian

+0

Спасибо, ты действительно указал мне в правильном направлении, поскольку я новичок в веб-сервисах SOAP и все :) –

Смежные вопросы