我必须准备一个 web 服务来接受一个已经定义的 wsdl 结构。我跟着教程found here , 带有测试项目的源代码 downloadable here .
对于这样的 xsd:
<xs:element name="getCountryRequest">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
应用程序返回的请求的wsdl操作是可以的,看起来像这样:
<wsdl:binding name="CountriesPortSoap11" type="tns:CountriesPort">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getCountry">
<soap:operation soapAction=""/>
<wsdl:input name="getCountryRequest">
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="getCountryResponse">
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
但是当我将 xsd 更改为(元素名称中没有“请求”)时:
<xs:element name="getCountry">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
wsdl 无效,并且没有
<input>
指定的:<wsdl:binding name="CountriesPortSoap11" type="tns:CountriesPort">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getCountry">
<soap:operation soapAction=""/>
<wsdl:output name="getCountryResponse">
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
我该如何解决?我如何制作
Request
-less 元素是否正确显示为 wsdl 中的肥皂操作输入?
最佳答案
根据 official Spring WS documentation ,请求/响应后缀是用于自动确定请求/响应并因此生成预期 WSDL 的默认后缀。
The DefaultWsdl11Definition which builds a WSDL from a XSD schema. This definition iterates over all element elements found in the schema, and creates a message for all elements. Next, it creates WSDL operation for all messages that end with the defined request or response suffix. The default request suffix is Request; the default response suffix is Response, though these can be changed by setting the requestSuffix and responseSuffix properties, respectively.
因此,您可以在上述示例代码中更改
WebServiceConfig
中的后缀。配置类,defaultWsdl11Definition
方法,添加以下方法调用:wsdl11Definition.setRequestSuffix("your-new-prefix-here");
例如,您可以将其设置为
Req
而不是 Request
,构建将自动生成一个新的 GetCountryReq
类,代码ApplicationTests
和 CountryEndpoint
然后需要手动调整,删除编译错误(因为它们仍然指向以前存在的 GetCountryRequest
类),但还要确保更改 localPart = "getCountryReq"
@PayloadRoot
的属性CountryEndPoint
中的注释类(class)。我试过了,构建很顺利,WSDL 也相应地更新了。
这是关于将默认后缀更改为另一个后缀。 但是将其更改为空后缀呢?
wsdl11Definition.setRequestSuffix("");
异常(exception):后缀不能为空。 Spring 不支持它。根据这个thread :
Basically, the problem is this:
We have to differentiate which schema elements are wsdl messages, and which aren't.
Of all wsdl messages, we have to figure out which are input (request) messages.
Of all wsdl messages, we have to figure out which are output (response) messages.The DefaultWsdl11Definition figures this out by suffixes. Or, more specifically, it delegates to a SuffixBasedMessagesProvider and SuffixBasedPortTypesProvider to do so.
So if you have some other preferred way of determining what makes an input/output message, you will have to write your own messagesprovider and or porttypesprovider.Simply put: there is no generic way for Spring-WS to determine what makes up a request and a response, rather than using suffixes.
注意:此消息的发布者是
DefaultWsdl11Definition
的作者 Arjen Poutsma类(根据 javadocs),处理基于这些后缀约定的自动映射的组件。但他留下了一扇敞开的门:写你自己的
SuffixBasedMessagesProvider
和 SuffixBasedPortTypesProvider
.但是,他也将所有内容保留在 DefaultWsdl11Definition
中。 (实例化这些提供程序的地方),因此您还需要编写(复制)您自己的 WSDL11 定义映射器。这是我当时遵循的过程:
setRequestSuffix
方法并删除对空后缀的检查,在 isMessageElement
中您需要处理新映射的方法 setRequestSuffix
方法并删除对空后缀的检查,在 getOperationName
中和 isInputMessage
处理新映射所需的方法 WebServiceConfig
类(class),defaultWsdl11Definition
方法,使用您自己的 CustomWsdl11Definition 以应用整个自定义。 然而,空后缀带来了一些挑战,因为它适用于任何元素(即每个元素都有一个空后缀)。这就是为什么我提到了
isMessageElement
, isInputMessage
和 getOperationName
处理:在不断增长的 WSDL 上,您可能很容易最终对映射进行编码(对于 GetCountry 请求,GetCountryResponse 是响应)或传递属性/映射(如上述 thread 中所建议的),但再次重复您的大部分 XSD再次在您的 WebServiceConfig
配置类,使其难以维护、故障排除、共享。所以,我真的建议不要走这条路,要么坚持使用默认后缀(如果可能),要么创建一个新后缀,但要避免空后缀(毕竟图书馆不允许)。
但自从我踏上旅程以来,这里是可行的解决方案:
MySuffixBasedMessagesProvider 自定义类(为简洁起见删除了导入):
package hello;
public class MySuffixBasedMessagesProvider extends SuffixBasedMessagesProvider {
protected String requestSuffix = DEFAULT_REQUEST_SUFFIX;
public String getRequestSuffix() {
return this.requestSuffix;
}
public void setRequestSuffix(String requestSuffix) {
this.requestSuffix = requestSuffix;
}
@Override
protected boolean isMessageElement(Element element) {
if (isMessageElement0(element)) {
String elementName = getElementName(element);
Assert.hasText(elementName, "Element has no name");
return elementName.endsWith(getResponseSuffix())
|| (getRequestSuffix().isEmpty() ? true : elementName.endsWith(getRequestSuffix()))
|| elementName.endsWith(getFaultSuffix());
}
return false;
}
protected boolean isMessageElement0(Element element) {
return "element".equals(element.getLocalName())
&& "http://www.w3.org/2001/XMLSchema".equals(element.getNamespaceURI());
}
}
MySuffixBasedPortTypesProvider 自定义类(为简洁起见删除了导入):
package hello;
public class MySuffixBasedPortTypesProvider extends SuffixBasedPortTypesProvider {
private String requestSuffix = DEFAULT_REQUEST_SUFFIX;
public String getRequestSuffix() {
return requestSuffix;
}
public void setRequestSuffix(String requestSuffix) {
this.requestSuffix = requestSuffix;
}
@Override
protected String getOperationName(Message message) {
String messageName = getMessageName(message);
String result = null;
if (messageName != null) {
if (messageName.endsWith(getResponseSuffix())) {
result = messageName.substring(0, messageName.length() - getResponseSuffix().length());
} else if (messageName.endsWith(getFaultSuffix())) {
result = messageName.substring(0, messageName.length() - getFaultSuffix().length());
} else if (messageName.endsWith(getRequestSuffix())) {
result = messageName.substring(0, messageName.length() - getRequestSuffix().length());
}
}
return result;
}
@Override
protected boolean isInputMessage(Message message) {
String messageName = getMessageName(message);
return messageName != null && !messageName.endsWith(getResponseSuffix());
}
private String getMessageName(Message message) {
return message.getQName().getLocalPart();
}
}
MyWsdl11定义自定义类(本质上是默认类的副本,只是实例化上面的类,为简洁起见删除了导入):
package hello;
public class MyWsdl11Definition implements Wsdl11Definition, InitializingBean {
private final InliningXsdSchemaTypesProvider typesProvider = new InliningXsdSchemaTypesProvider();
private final SuffixBasedMessagesProvider messagesProvider = new MySuffixBasedMessagesProvider();
private final SuffixBasedPortTypesProvider portTypesProvider = new MySuffixBasedPortTypesProvider();
private final SoapProvider soapProvider = new SoapProvider();
private final ProviderBasedWsdl4jDefinition delegate = new ProviderBasedWsdl4jDefinition();
private String serviceName;
public MyWsdl11Definition() {
delegate.setTypesProvider(typesProvider);
delegate.setMessagesProvider(messagesProvider);
delegate.setPortTypesProvider(portTypesProvider);
delegate.setBindingsProvider(soapProvider);
delegate.setServicesProvider(soapProvider);
}
public void setTargetNamespace(String targetNamespace) {
delegate.setTargetNamespace(targetNamespace);
}
public void setSchema(XsdSchema schema) {
typesProvider.setSchema(schema);
}
public void setSchemaCollection(XsdSchemaCollection schemaCollection) {
typesProvider.setSchemaCollection(schemaCollection);
}
public void setPortTypeName(String portTypeName) {
portTypesProvider.setPortTypeName(portTypeName);
}
public void setRequestSuffix(String requestSuffix) {
portTypesProvider.setRequestSuffix(requestSuffix);
messagesProvider.setRequestSuffix(requestSuffix);
}
public void setResponseSuffix(String responseSuffix) {
portTypesProvider.setResponseSuffix(responseSuffix);
messagesProvider.setResponseSuffix(responseSuffix);
}
public void setFaultSuffix(String faultSuffix) {
portTypesProvider.setFaultSuffix(faultSuffix);
messagesProvider.setFaultSuffix(faultSuffix);
}
public void setCreateSoap11Binding(boolean createSoap11Binding) {
soapProvider.setCreateSoap11Binding(createSoap11Binding);
}
public void setCreateSoap12Binding(boolean createSoap12Binding) {
soapProvider.setCreateSoap12Binding(createSoap12Binding);
}
public void setSoapActions(Properties soapActions) {
soapProvider.setSoapActions(soapActions);
}
public void setTransportUri(String transportUri) {
soapProvider.setTransportUri(transportUri);
}
public void setLocationUri(String locationUri) {
soapProvider.setLocationUri(locationUri);
}
public void setServiceName(String serviceName) {
soapProvider.setServiceName(serviceName);
this.serviceName = serviceName;
}
@Override
public void afterPropertiesSet() throws Exception {
if (!StringUtils.hasText(delegate.getTargetNamespace()) && typesProvider.getSchemaCollection() != null &&
typesProvider.getSchemaCollection().getXsdSchemas().length > 0) {
XsdSchema schema = typesProvider.getSchemaCollection().getXsdSchemas()[0];
setTargetNamespace(schema.getTargetNamespace());
}
if (!StringUtils.hasText(serviceName) && StringUtils.hasText(portTypesProvider.getPortTypeName())) {
soapProvider.setServiceName(portTypesProvider.getPortTypeName() + "Service");
}
delegate.afterPropertiesSet();
}
@Override
public Source getSource() {
return delegate.getSource();
}
}
此外,
defaultWsdl11Definition
WebServiceConfig
的方法类将更改如下(使用上面的自定义):@Bean(name = "countries")
public Wsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema) {
MyWsdl11Definition wsdl11Definition = new MyWsdl11Definition();
wsdl11Definition.setPortTypeName("CountriesPort");
wsdl11Definition.setLocationUri("/ws");
wsdl11Definition.setRequestSuffix("");
wsdl11Definition.setTargetNamespace("http://spring.io/guides/gs-producing-web-service");
wsdl11Definition.setSchema(countriesSchema);
return wsdl11Definition;
}
请注意
wsdl11Definition.setRequestSuffix("");
这有效地将后缀设置为空。在此自定义之后,您可以更改 XSD 删除请求后缀,将生成新的 GetCountry 类,您需要手动删除以前存在的 GetCountryRequest 并修复上述编译错误(测试和端点类,只是不要不要忘记更新@PayloadRoot 注释)。
然后构建将运行良好。运行
Application
main 之后,生成的 WSDL 将根据要求包含:<wsdl:binding name="CountriesPortSoap11" type="tns:CountriesPort">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getCountry">
<soap:operation soapAction=""/>
<wsdl:input name="getCountry">
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="getCountryResponse">
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
希望能帮助到你。这是一个真实的例子,说明了配置上的约定极大地提供了什么,而框架中的一个小的不可预见的变化在编写代码和添加自定义方面意味着什么。
关于java - 请求元素不以 'Request'结尾时spring-ws生成的wsdl无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34525587/