使用 Maven 和重用 类 生成 WS 客户端
WS Client generation using maven and reusing classes
我的应用程序分为两层,其中后端层公开了一堆 Web 服务,而表示层使用这些服务来获取业务数据。
为了使我的构造尽可能自动化,我将所有生成的 WSDL 和相关的 XSD 文件打包成一个 ZIP 依赖项(使用 Maven 汇编程序插件),它在安装时上传到我的 nexus相.
然后在 UI POM 上我将这个 ZIP 文件(使用 maven 依赖插件)解压到本地目录 (src/main/resources/wsdl
),然后使用 CXF-CODEGEN 插件生成客户端。
问题是——许多这些服务共享公共模型实体,例如很多方法使用 Catalogue
class,这是我用于对象的实体ID 和文本值。
使用 CXF 生成的代码,对于我拥有的每个 Web 服务,我最终得到不同的 Catalogue
class(具有不同的包名称),因此在我的代码中失去了 OO 多态性功能,因为它们都是class实践中的不同。
我听说您可以通过某种方式先将 XSD classes 编译成名为 "episodes" 的东西,然后将这些剧集文件提供给 CXF 以便告诉它,从而避免这个问题利用它们而不是生成 classes.
我尝试添加一个额外的编译步骤,其中我 运行 maven-jaxb2-plugin 从 XSD 生成 classes,但我得到了一个
org.xml.sax.SAXParseException; (...) 'catalogueDTO' is already defined
异常,因为此 class 在 XSD 个文件中重复出现。
任何人都可以指出正确的方向吗?
当您的 Web 服务中有一些基础 classes 将跨服务和操作使用时,最好在单个 XSD 中声明这些 classes,然后在您的项目中包含并使用此 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" />
或者,如果您喜欢视觉表示:
需要注意的是目录 class/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>
或者,如果您想要视觉表示:
Kitchen 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>
再一次在视觉上:
在这两个 WSDL 文件中,我都包含了 catalog.xsd 文件。您可以在以下代码行中看到这一点:
<xs:import schemaLocation="Catalog.xsd"
namespace="http://www.yourcompany.com/Services_V1/CommonType" />
现在,当我将这些 WSDL 和 XSD 与 cxf 一起使用时,两个服务将只使用一个目录 object/class。我很快做了一个shell项目,生成了如下结构:
请注意,我声明的 CatalogueType 现在与我声明它的命名空间位于同一个包中。
查看服务时 classes 浴室和厨房服务都将使用此服务 class。在厨房服务 class 它使用 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
);
}
而在厨房服务中 class 它使用 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
);
}
提醒您切勿编辑这些 classes,因为它们是由 CXF 派生和生成的,您的更改将会丢失。因此,通过优先使用 WSDL 方法,您必须确保正确构建 XSD 文件和 WSDL。
让我知道这是否有意义。
我的应用程序分为两层,其中后端层公开了一堆 Web 服务,而表示层使用这些服务来获取业务数据。
为了使我的构造尽可能自动化,我将所有生成的 WSDL 和相关的 XSD 文件打包成一个 ZIP 依赖项(使用 Maven 汇编程序插件),它在安装时上传到我的 nexus相.
然后在 UI POM 上我将这个 ZIP 文件(使用 maven 依赖插件)解压到本地目录 (src/main/resources/wsdl
),然后使用 CXF-CODEGEN 插件生成客户端。
问题是——许多这些服务共享公共模型实体,例如很多方法使用 Catalogue
class,这是我用于对象的实体ID 和文本值。
使用 CXF 生成的代码,对于我拥有的每个 Web 服务,我最终得到不同的 Catalogue
class(具有不同的包名称),因此在我的代码中失去了 OO 多态性功能,因为它们都是class实践中的不同。
我听说您可以通过某种方式先将 XSD classes 编译成名为 "episodes" 的东西,然后将这些剧集文件提供给 CXF 以便告诉它,从而避免这个问题利用它们而不是生成 classes.
我尝试添加一个额外的编译步骤,其中我 运行 maven-jaxb2-plugin 从 XSD 生成 classes,但我得到了一个
org.xml.sax.SAXParseException; (...) 'catalogueDTO' is already defined
异常,因为此 class 在 XSD 个文件中重复出现。
任何人都可以指出正确的方向吗?
当您的 Web 服务中有一些基础 classes 将跨服务和操作使用时,最好在单个 XSD 中声明这些 classes,然后在您的项目中包含并使用此 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" />
或者,如果您喜欢视觉表示:
需要注意的是目录 class/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>
或者,如果您想要视觉表示:
Kitchen 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>
再一次在视觉上:
在这两个 WSDL 文件中,我都包含了 catalog.xsd 文件。您可以在以下代码行中看到这一点:
<xs:import schemaLocation="Catalog.xsd"
namespace="http://www.yourcompany.com/Services_V1/CommonType" />
现在,当我将这些 WSDL 和 XSD 与 cxf 一起使用时,两个服务将只使用一个目录 object/class。我很快做了一个shell项目,生成了如下结构:
请注意,我声明的 CatalogueType 现在与我声明它的命名空间位于同一个包中。
查看服务时 classes 浴室和厨房服务都将使用此服务 class。在厨房服务 class 它使用 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
);
}
而在厨房服务中 class 它使用 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
);
}
提醒您切勿编辑这些 classes,因为它们是由 CXF 派生和生成的,您的更改将会丢失。因此,通过优先使用 WSDL 方法,您必须确保正确构建 XSD 文件和 WSDL。
让我知道这是否有意义。