繁体   English   中英

如何将具有相同名称空间和本地名称请求的两个单独Web服务路由到不同的端点?

[英]How can i have two separate web services with identical name space and local name requests be routed to different end points?

我试图在一个弹簧部署中创建两个单独的Web服务,两者都使用相同的xsd模式生成wsdl,但是将它们路由到两个单独的端点,这样我就可以在不同的上下文中以不同的方式处理请求。

例如:

Webservice 1:访问子集,较低权限和安全性约束

Webservice 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>

现在因为两个wsdl都基于相同的xsds,所以请求的'namespace'和'localPart'都是相同的,无论我正在点击哪个Web服务(/ SpmlReadOnly或/ SpmlCrud)。

因此,由于localPart和命名空间仍然完全相同等,因此排除了已弃用的PayloadRootQNameEndpointMapping,并且我的当前配置只是将请求路由到同一端点方法处理程序,我无法区分调用哪个Web服务:

    @PayloadRoot(namespace = NAMESPACE_URI, localPart = "lookupRequest")
    @ResponsePayload
    public Source handleLookupRequest(SoapMessage message) throws Exception {
        ...
    }

我能做什么甚至可能? 如果xsd是共享的并且在模式的根目录中具有相同的名称空间,并且相同的localPart方法请求,那么是否有办法区分它们并映射到两个不同的端点? 有关这方面的任何信息都很有用! 我希望我不必设置两个单独的.wars,并在服务器上使用自己的代码库单独部署它们!

谢谢,达米安

您需要结合URIPayloadRoot映射的东西。 不幸的是,Spring-Ws没有这样的东西。 但由于它非常易于扩展,因此实现这一目标非常容易。

TL; DR

有关工作示例,请参阅GitHub上的此分支

细节

您需要创建组合URI + QName到org.springframework.ws.server.endpoint.MethodEndpoint实例的映射。 您还应该最小化复制现有Spring-Ws函数的代码。

因此1)您需要在不使用<sws:annotation-driven />情况下显式配置Spring-Ws注释:

这是你的要求(使用我的模式):

<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 marshaller的适配器)配置:

<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提取的信息扩展消息的密钥 (有效负载根元素的QNames)。 我已经使用了Spring的@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上下文,应用程序部署在。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM