Как можно направить две разные веб-службы с одинаковым пространством имен и запросами локальных имен в разные конечные точки?
Я пытаюсь создать 2 отдельных веб-сервиса, оба в рамках одного весеннего развертывания, оба с wsdl, сгенерированным из одних и тех же схем xsd, но все же они будут направлены в две отдельные конечные точки, чтобы я мог обрабатывать запросы по-разному в разных контекстах,
Пример:
Веб-сервис 1: подмножество доступа, более низкие привилегии и ограничения безопасности
Веб-сервис 2: более высокие привилегии
<sws:dynamic-wsdl id="spml-readonly"
portTypeName="SpmlReadOnlyService"
locationUri="SpmlReadOnly">
<sws:xsd location="/WEB-INF/xsd/spml/pstc_spmlv2_core.xsd"/>
</sws:dynamic-wsdl>
<sws:dynamic-wsdl id="spml-crud"
portTypeName="SpmlCrudService"
locationUri="SpmlCrud">
<sws:xsd location="/WEB-INF/xsd/spml/pstc_spmlv2_core.xsd"/>
<sws:xsd location="/WEB-INF/xsd/spml/pstc_spmlv2_search.xsd"/>
<sws:xsd location="/WEB-INF/xsd/spml/pstc_spmlv2_batch.xsd"/>
</sws:dynamic-wsdl>
Теперь, поскольку оба wsdls основаны на одном и том же xsds, "пространство имен" и "localPart" запросов встречаются идентично, независимо от того, к какому веб-сервису я обращаюсь (/SpmlReadOnly или /SpmlCrud).
Следовательно, это исключает устаревший PayloadRootQNameEndpointMapping, так как localPart и пространство имен все еще идентичны и т. Д., И моя текущая конфигурация просто перенаправляет запросы в один и тот же обработчик метода конечной точки, и у меня нет способа определить, какая веб-служба была вызвана:
@PayloadRoot(namespace = NAMESPACE_URI, localPart = "lookupRequest")
@ResponsePayload
public Source handleLookupRequest(SoapMessage message) throws Exception {
...
}
Что я могу сделать, даже возможно? Если xsd являются общими и имеют одинаковые пространства имен в корне схемы и одинаковые запросы метода localPart, будет ли когда-нибудь способ различать их и сопоставлять с двумя разными конечными точками? Любая информация об этом будет полезна! Я надеюсь, что мне не нужно настраивать два отдельных.wars и развертывать их отдельно со своими базами кода на сервере!
Спасибо Дамиан
1 ответ
Вам нужно то, что сочетает в себе URI
а также PayloadRoot
отображение. К сожалению Spring-W не имеет ничего подобного. Но поскольку это очень расширяемо, это действительно легко достичь.
TL; DR
Посмотрите эту ветку на GitHub для рабочего примера
подробности
Вам необходимо создать отображение комбинированного URI+QName на org.springframework.ws.server.endpoint.MethodEndpoint
экземпляров. Также вы должны минимизировать код, который дублирует существующие функции Spring-Ws.
Итак 1) Вам необходимо явно настроить аннотации Spring-W без использования <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
, И все, что он делает, это расширяет ключи (QNames корневых элементов полезной нагрузки) сообщений информацией, извлеченной из URI конечной точки. Я использовал Spring's @org.springframework.web.bind.annotation.RequestMapping
аннотации для этого, но кто-то думает, что это взломать, может создать свою собственную аннотацию.
Так для конечной точки, как это:
@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, в котором развернуто приложение.