提问人:Prototype 提问时间:11/3/2023 最后编辑:Prototype 更新时间:11/3/2023 访问量:51
如何基于其他SOAP服务生成WSDL?
How to generate WSDL based on another SOAP service?
问:
我正在开发一个基于 的 SOAP 服务,根据业务任务,它必须通过自身代理请求。Spring WebServices
SOAP
我的问题是我无法在输出中获得正确生成的 WSDL,我可以将其提供给客户,因为实际上由于我使用生成的 SOAP 服务,我的主 xsd 中几乎没有元素的描述,对象参与@RequestPayload和@ResponsePayload。我的服务添加的唯一元素是 和(目前未使用,但稍后将需要)。setDataInQueue
message
由于 xsd 文件中的链接数量众多,我无法发布我的问题,因为它被标记为垃圾邮件,所以我不得不省略它们。
在以下位置生成 WSDL:localhost:8080/ws/proxy.wsdl
<wsdl:definitions ...>
<wsdl:types>
<xs:schema ...>
<xs:import schemaLocation="message.xsd"/>
<xs:import namespace="http://service.example.com/" schemaLocation="setDataInQueue.xsd"/>
</xs:schema>
</wsdl:types>
<wsdl:portType name="ProxyPort"></wsdl:portType>
<wsdl:binding name="ProxyPortSoap11" type="tns:ProxyPort">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
</wsdl:binding>
<wsdl:service name="ProxyService">
<wsdl:port binding="tns:ProxyPortSoap11" name="ProxyPortSoap11">
<soap:address location="http://localhost:8080/ws"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
在以下位置生成 WSDL:localhost:8080/ws/ehdproxy.wsdl
<wsdl:definitions ... >
<wsdl:types>
<xs:schema ...>
<xs:import schemaLocation="message.xsd"/>
<xs:import namespace="service.exampe.com/" schemaLocation="setDataInQueue.xsd"/>
</xs:schema>
</wsdl:types>
<wsdl:portType name="EhdProxyPort"></wsdl:portType>
<wsdl:binding name="EhdProxyPortSoap11" type="tns:EhdProxyPort">
<soap:binding style="document" transport="schemas.xmlsoap.org/soap/http"/>
</wsdl:binding>
<wsdl:service name="EhdProxyService">
<wsdl:port binding="tns:EhdProxyPortSoap11" name="EhdProxyPortSoap11">
<soap:address location="localhost:8080/ws"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
正如你所看到的,最终的 wsdl 没有任何包含请求/响应操作和描述的部分,根据这些部分,客户最终可以生成一个客户端来使用我的代理服务。
我有两个端点: 我不得不将端点拆分为单独的类和声明,因为它们具有不同的命名空间。
ProxyEndPoint
:
@Endpoint
@RequiredArgsConstructor
public class ProxyEndPoint {
public static final String BUS_NAMESPACE_URI = "http...service.example.com/";
private final ConverterService converterService;
private final EhdService ehdService;
@ResponsePayload
@PayloadRoot(namespace = BUS_NAMESPACE_URI, localPart = "setDataInQueue")
public SetDataInQueueResponse handleSetDataInQueue(@RequestPayload SetDataInQueue request) {
final var converted = this.converterService.convert(request);
return this.ehdService.callSetDataInQueue(converted);
}
EhdProxyEndPoint
:
@Endpoint
@RequiredArgsConstructor
public class EhdProxyEndPoint {
public static final String EHD_NAMESPACE_URI = "http...contractor.com/";
private final EhdService ehdService;
@ResponsePayload
@PayloadRoot(namespace = EHD_NAMESPACE_URI, localPart = "setDataInResult")
public SetDataInResultResponse handleSetDataInResult(@RequestPayload SetDataInResult request) {
return this.ehdService.callSetDataInResult(request);
}
}
这些端点是根据 Spring WebServices 中主要指南的示例之一配置的:
WebServiceConfig
:
@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
@Bean
public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(ApplicationContext context) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(context);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean<>(servlet, "/ws/*");
}
@Bean(name = "proxy")
public DefaultWsdl11Definition proxySchemaDefinition(XsdSchema proxySchema) {
DefaultWsdl11Definition definition = new DefaultWsdl11Definition();
definition.setServiceName("ProxyService");
definition.setPortTypeName("ProxyPort");
definition.setLocationUri("/ws");
definition.setTargetNamespace(ProxyEndPoint.BUS_NAMESPACE_URI);
definition.setSchema(proxySchema);
return definition;
}
@Bean(name = "ehdproxy")
public DefaultWsdl11Definition ehdProxySchemaDefinition(XsdSchema proxySchema) {
DefaultWsdl11Definition definition = new DefaultWsdl11Definition();
definition.setServiceName("EhdProxyService");
definition.setPortTypeName("EhdProxyPort");
definition.setLocationUri("/ws");
definition.setTargetNamespace(EhdProxyEndPoint.EHD_NAMESPACE_URI);
definition.setSchema(proxySchema);
return definition;
}
@Bean
public XsdSchema proxySchema() {
return new SimpleXsdSchema(new ClassPathResource("/xsd/proxy.xsd"));
}
}
resources/xsd/proxy.xsd
:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
...
jaxb:version="3.0"
elementFormDefault="qualified"
attributeFormDefault="unqualified"
>
<xs:import schemaLocation="message.xsd"/>
<xs:import namespace="service.example.com" schemaLocation="setDataInQueue.xsd"/>
</xs:schema>
resources/xsd/setDataInQueue.xsd
:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0"
...
>
<xs:element name="setDataInQueue" type="tns:setDataInQueue"/>
<xs:complexType name="setDataInQueue">
<xs:sequence>
<xs:element name="FileName" type="xs:string"/>
<xs:element name="File" type="xs:base64Binary"/>
<xs:element name="Signature" type="xs:base64Binary"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
/resources/xsd/message.xsd
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0">
<xs:element name="category" type="categoryEntity" />
<xs:element name="message" type="messageEntity" />
<xs:complexType name="messageEntity">
<xs:sequence>
<xs:element name="id" type="xs:string" minOccurs="0" />
<xs:element name="catalog" type="catalogEntity" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="catalogEntity">
<xs:sequence>
<xs:element name="item" type="itemEntity" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
<xs:attribute name="name" type="xs:string" />
<xs:attribute name="parent_catalog_id" type="xs:int" />
</xs:complexType>
<xs:complexType name="itemEntity">
<xs:sequence>
<xs:element name="geodata" type="xs:string" minOccurs="0" />
<xs:element name="categories" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element ref="category" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="data" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="attribute" type="attributeEntity" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="action" type="xs:string" />
<xs:attribute name="isManualGeo" type="xs:boolean" />
</xs:complexType>
<xs:complexType name="categoryEntity">
<xs:simpleContent>
<xs:extension base="xs:int">
<xs:attribute name="nameHier" type="xs:string" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="attributeEntity">
<xs:sequence>
<xs:element name="values" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="value" type="valueEntity" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="field_id" type="xs:int" />
<xs:attribute name="type" type="xs:string" />
<xs:attribute name="pk" type="xs:string" />
<xs:attribute name="isManual" type="xs:boolean" />
</xs:complexType>
<xs:complexType name="valueEntity">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="occurrence" type="xs:int" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:schema>
resources/jxb/bindings.xjb
(用于生成注释):@XMlRootElement
<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings version="3.0"
...
jaxb:extensionBindingPrefixes="xjc">
<jaxb:globalBindings generateElementProperty="false" >
<xjc:simple/>
<xjc:serializable uid="-1"/>
</jaxb:globalBindings>
</jaxb:bindings>
由于我需要代理来自另一个 SOAP 服务的请求,因此我使用 wsimport 使用基于 WSDL 的代码生成:
plugins {
id 'java'
id 'org.springframework.boot' version '3.1.5'
id 'io.spring.dependency-management' version '1.1.3'
}
group = 'com.group'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '21'
}
ext.jaxwsSourceDir = "${buildDir}/generated/sources/jaxws"
configurations {
jaxb
jaxws
compileOnly {
extendsFrom annotationProcessor
}
}
sourceSets {
main {
java {
srcDir 'src/main/java'
srcDir 'build/generated/sources/jaxb'
srcDir jaxwsSourceDir
}
}
}
task genJaxb {
ext.sourcesDir = "${buildDir}/generated/sources/jaxb"
ext.schema = "src/main/resources/xsd/proxy.xsd"
ext.binding = "src/main/resources/jxb/bindings.xjb"
outputs.dir sourcesDir
doLast() {
project.ant {
taskdef name: "xjc", classname: "com.sun.tools.xjc.XJCTask",
classpath: configurations.jaxb.asPath
mkdir(dir: sourcesDir)
xjc(destdir: sourcesDir, schema: schema, binding: ext.binding) {
arg(value: "-wsdl")
produces(dir: sourcesDir, includes: "**/*.java")
}
}
}
}
task wsimport {
System.setProperty('javax.xml.accessExternalSchema', 'all')
description = 'Generate classes from wsdl using wsimport'
doLast {
project.mkdir(jaxwsSourceDir)
ant {
taskdef(name: 'wsimport',
classname: 'com.sun.tools.ws.ant.WsImport',
classpath: configurations.jaxws.asPath
)
wsimport(
keep: true,
destdir: jaxwsSourceDir,
extension: "true",
verbose: true,
wsdl: "%WSDL LINK PLACEHOLDER%", // <- WSDL contractor inserted here
binding: "${projectDir}/src/main/resources/jxb/bindings.xjb",
xnocompile: true,
package: "contractor") {
xjcarg(value: "-XautoNameResolution")
}
}
}
}
compileJava.dependsOn genJaxb, wsimport
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web-services'
// support xml/xsd/wsdl
implementation 'wsdl4j:wsdl4j'
implementation 'com.sun.xml.ws:rt:4.0.2'
jaxb('org.glassfish.jaxb:jaxb-xjc:4.0.4')
jaxb('org.glassfish.jaxb:jaxb-core:4.0.4')
jaxb('org.glassfish.jaxb:jaxb-runtime:4.0.4')
jaxws 'com.sun.xml.ws:jaxws-tools:4.0.2',
'jakarta.xml.ws:jakarta.xml.ws-api:3.0.0',
'jakarta.xml.bind:jakarta.xml.bind-api:4.0.1',
'jakarta.activation:jakarta.activation-api:2.1.2',
'com.sun.xml.ws:jaxws-rt:4.0.2'
// dev / test utils ...
}
我最近一直在开发SOAP服务,并且在尝试解决问题时研究了很多指南,但是我无法取得成果。 我还想指出,在尝试将我的SOAP服务导入SoapUI时出现错误:
加载 [http://localhost:8080/ws/message.xsd] 时出错:org.apache.xmlbeans.XmlException:org.apache.xmlbeans.XmlException:错误:文件过早结束
答: 暂无答案
评论