Как можно направить две разные веб-службы с одинаковым пространством имен и запросами локальных имен в разные конечные точки?

Я пытаюсь создать 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, в котором развернуто приложение.

Другие вопросы по тегам