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

1rhkuytd  于 2022-11-15  发布在  其他
关注(0)|答案(1)|浏览(159)

我尝试创建两个单独的web服务,都在一个spring部署中,都使用从相同的xsd模式生成的wsdl,但将它们路由到两个单独的端点,这样我就可以在单独的上下文中以不同的方式处理请求。
例如:
网络服务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>

现在,由于两个wsdl都基于相同的xsds,因此无论我点击的是哪个Web服务(/SpmlReadOnly或/SpmlCrud),请求的“namespace”和“localPart”都是相同的。
因此,由于localPart和命名空间仍然相同,因此排除了已弃用的PayloadRootQNameEndpointMapping,等等,...我当前的配置只是将请求路由到同一个端点方法处理程序,我无法区分调用了哪个Web服务:

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

我所能做的一切是否可能?如果xsd是共享的,并且在模式的根目录下有相同的名称空间,以及相同的localPart方法请求,是否有办法区分它们并Map到两个不同的端点?任何有关这方面的信息都将是有用的!我希望我不必设置两个单独的. war并在服务器上使用它们自己的代码库单独部署它们!
谢谢你达米安

qij5mzcb

qij5mzcb1#

你需要一些结合了URIPayloadRootMap的东西。不幸的是Spring-Ws没有这样的东西。但是因为它是非常可扩展的,所以很容易实现。

TL;DR

工作示例参见This branch at GitHub

详细数据

你需要创建URI+QName到org.springframework.ws.server.endpoint.MethodEndpoint示例的Map。同时你应该尽量减少重复现有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>

这是自定义Map:

<bean class="springws.PathAndPayloadRootAnnotationEndpointMapping" />

2)您应该创建自己的Map

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中提取的信息扩展消息的 keys(有效负载根元素的QName)。我已经使用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)方法确保MapURI独立于部署应用程序的WAR上下文。

相关问题