简体   繁体   English

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

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

I'm attempting to create 2 separate web services, both within one spring deployment, both with the wsdl's being generated from the same xsd schemas, yet have them be routed to two separate end points so i can handle the requests differently in the separate contexts. 我试图在一个弹簧部署中创建两个单独的Web服务,两者都使用相同的xsd模式生成wsdl,但是将它们路由到两个单独的端点,这样我就可以在不同的上下文中以不同的方式处理请求。

Ex: 例如:

Webservice 1: subset of access, lower privileges and security constraints Webservice 1:访问子集,较低权限和安全性约束

Webservice 2: higher privileges 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>

Now since both wsdls are based off of the same xsds, the 'namespace' and 'localPart" of the requests come across the wire identical, regardless of which web service i'm hitting (/SpmlReadOnly or /SpmlCrud). 现在因为两个wsdl都基于相同的xsds,所以请求的'namespace'和'localPart'都是相同的,无论我正在点击哪个Web服务(/ SpmlReadOnly或/ SpmlCrud)。

Therefore, that's ruling out the deprecated PayloadRootQNameEndpointMapping since the localPart and namespace are still identical, etc,... and my current config simply routes the requests to the same endpoint method handler, and i have no way of distinguishing which web service was called: 因此,由于localPart和命名空间仍然完全相同等,因此排除了已弃用的PayloadRootQNameEndpointMapping,并且我的当前配置只是将请求路由到同一端点方法处理程序,我无法区分调用哪个Web服务:

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

Is what I'm able to do even possible? 我能做什么甚至可能? If the xsd's are shared and have identical namespaces at the root of the schema, and the same localPart method requests, will there ever be a way to distinguish between them and map to two different end points? 如果xsd是共享的并且在模式的根目录中具有相同的名称空间,并且相同的localPart方法请求,那么是否有办法区分它们并映射到两个不同的端点? Any information on this would be useful! 有关这方面的任何信息都很有用! I'm hoping i don't have to set up two separate .wars and deploy them separately with their own code bases on a server! 我希望我不必设置两个单独的.wars,并在服务器上使用自己的代码库单独部署它们!

Thanks, Damian 谢谢,达米安

You need something that combines URI and PayloadRoot mapping. 您需要结合URIPayloadRoot映射的东西。 Unfortunately Spring-Ws doesn't have something like this. 不幸的是,Spring-Ws没有这样的东西。 But because it's very extensible it's really easy to achieve this. 但由于它非常易于扩展,因此实现这一目标非常容易。

TL;DR TL; DR

See This branch at GitHub for working example 有关工作示例,请参阅GitHub上的此分支

Details 细节

You need to create mapping of combined URI+QName to org.springframework.ws.server.endpoint.MethodEndpoint instances. 您需要创建组合URI + QName到org.springframework.ws.server.endpoint.MethodEndpoint实例的映射。 Also you should minimize the code which would duplicate existing Spring-Ws functions. 您还应该最小化复制现有Spring-Ws函数的代码。

So 1) You need to explicitly configure Spring-Ws annotations without using <sws:annotation-driven /> : 因此1)您需要在不使用<sws:annotation-driven />情况下显式配置Spring-Ws注释:

This is your requirement (with my schemas): 这是你的要求(使用我的模式):

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

This is all you need to do by hand which normally is configured by <sws:annotation-driven /> (one adapter with one JAXB marshaller): 这就是您需要手动完成的任务,通常由<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>

This is custom mapping: 这是自定义映射:

<bean class="springws.PathAndPayloadRootAnnotationEndpointMapping" />

And 2) You should create your own mapping 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;
    }   
}

which extends org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping . 它扩展了org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping And all it does is extending the keys (QNames of payload root elements) of messages with the information extracted from the endpoint URI. 它所做的就是利用从端点URI提取的信息扩展消息的密钥 (有效负载根元素的QNames)。 I've used Spring's @org.springframework.web.bind.annotation.RequestMapping annotation for that, but someone thinking it's a hack may create his/her own annotation. 我已经使用了Spring的@org.springframework.web.bind.annotation.RequestMapping注释,但有人认为这是一个黑客可能会创建他/她自己的注释。

So for endpoint like this: 所以对于像这样的端点:

@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");
    }
}

the key is not: 关键不是:

namespace = urn:test
localName = method1Request

but this: 但是这个:

namespace = urn:test
localName = /ws/SpmlReadOnly/method1Request

The protected QName getLookupKeyForMessage(MessageContext messageContext) method ensures that the mapping URI is independent of the WAR context, the application is deployed at. protected QName getLookupKeyForMessage(MessageContext messageContext)方法确保映射URI独立于WAR上下文,应用程序部署在。

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

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