你需要一些结合URI
和PayloadRoot
映射的东西。不幸的是 Spring-Ws 没有这样的东西。但是因为它非常可扩展,所以很容易实现这一点。
TL;博士
有关工作示例,请参阅GitHub 上的此分支
细节
您需要创建组合 URI+QName 到org.springframework.ws.server.endpoint.MethodEndpoint
实例的映射。此外,您应该最小化重复现有 Spring-Ws 功能的代码。
所以 1)您需要显式配置 Spring-Ws 注释而不使用<sws:annotation-driven />
:
这是您的要求(使用我的模式):
<ws:dynamic-wsdl id="spml-readonly" portTypeName="SpmlReadOnlyService" locationUri="SpmlReadOnly">
<ws:xsd location="classpath:springws/model/schema.xsd" />
</ws:dynamic-wsdl>
<ws:dynamic-wsdl id="spml-crud" portTypeName="SpmlCrudService" locationUri="SpmlCrud">
<ws:xsd location="classpath:springws/model/schema.xsd" />
<ws:xsd location="classpath:springws/model/schema2.xsd" />
</ws:dynamic-wsdl>
这就是您需要手动执行的所有操作,通常由<sws:annotation-driven />
(一个适配器和一个 JAXB 编组器)配置:
<bean class="org.springframework.ws.server.endpoint.adapter.DefaultMethodEndpointAdapter">
<property name="methodArgumentResolvers">
<list>
<ref local="marshallingPayloadMethodProcessor"/>
</list>
</property>
<property name="methodReturnValueHandlers">
<list>
<ref local="marshallingPayloadMethodProcessor"/>
</list>
</property>
</bean>
<bean id="marshallingPayloadMethodProcessor" class="org.springframework.ws.server.endpoint.adapter.method.MarshallingPayloadMethodProcessor">
<property name="marshaller" ref="marshaller" />
<property name="unmarshaller" ref="marshaller" />
</bean>
<bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="contextPaths">
<list>
<value>springws.model</value>
</list>
</property>
</bean>
这是自定义映射:
<bean class="springws.PathAndPayloadRootAnnotationEndpointMapping" />
2)你应该创建自己的映射
public class PathAndPayloadRootAnnotationEndpointMapping extends PayloadRootAnnotationMethodEndpointMapping
{
@Override
protected QName getLookupKeyForMessage(MessageContext messageContext) throws Exception
{
String urlPart = "";
QName payloadRootPart = super.getLookupKeyForMessage(messageContext);
TransportContext transportContext = TransportContextHolder.getTransportContext();
if (transportContext != null) {
WebServiceConnection connection = transportContext.getConnection();
if (connection != null && connection instanceof HttpServletConnection) {
String requestURI = ((HttpServletConnection)connection).getHttpServletRequest().getRequestURI();
String contextPath = ((HttpServletConnection)connection).getHttpServletRequest().getContextPath();
urlPart = requestURI.substring(contextPath.length());
}
}
return new QName(payloadRootPart.getNamespaceURI(), urlPart + "/" + payloadRootPart.getLocalPart());
}
@Override
protected List<QName> getLookupKeysForMethod(Method method)
{
List<QName> result = new ArrayList<QName>();
RequestMapping rm = AnnotationUtils.findAnnotation(method.getDeclaringClass(), RequestMapping.class);
String urlPart = rm == null || rm.value().length != 1 ? "" : rm.value()[0];
List<QName> methodPart = super.getLookupKeysForMethod(method);
for (QName qName : methodPart) {
result.add(new QName(qName.getNamespaceURI(), urlPart + "/" + qName.getLocalPart()));
}
return result;
}
}
延伸org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping
。它所做的只是使用从端点 URI 中提取的信息来扩展消息的键(有效负载根元素的 QName)。我为此使用了 Spring 的@org.springframework.web.bind.annotation.RequestMapping
注释,但认为这是一个 hack 的人可能会创建他/她自己的注释。
所以对于这样的端点:
@org.springframework.ws.server.endpoint.annotation.Endpoint
@RequestMapping("/ws/SpmlReadOnly")
public class Endpoint1
{
@ResponsePayload
@PayloadRoot(namespace = "urn:test", localPart = "method1Request")
public Response2 method(@RequestPayload Request1 request) throws Exception
{
return new Response2("e1 m1");
}
}
关键不是:
namespace = urn:test
localName = method1Request
但是这个:
namespace = urn:test
localName = /ws/SpmlReadOnly/method1Request
该protected QName getLookupKeyForMessage(MessageContext messageContext)
方法确保映射 URI 独立于应用程序部署的 WAR 上下文。