Web Services 是否将SOAP转换为虚拟Restful服务?

ct2axkht  于 2022-11-15  发布在  其他
关注(0)|答案(5)|浏览(226)

是否有办法将我的SOAP Web服务(spring-ws、java)虚拟地用作基于XML的RESTful服务?
我不想用java从头开始将整个SOAP Web服务重写到RESTful中,但我需要使用REST通过iPhone访问它,他们已经有了简单的本地支持。
XMLGateway、Proxys......或一些额外的java代码?既然我的SOAP请求和响应只是一个XML文件,为什么我不能修改它以供REST服务使用?
或者,在不更改应用程序中的任何逻辑和xml解析的情况下,添加jax-rs注解并创建一个rest请求xml是那么容易吗?
我的配置spring文件是这样的:

<bean id="webServicePluginDescriptor"
    class="com.mysite.ws.configuration.MyWebservicePluginDescriptor" />

<bean id="payloadMapping"
    class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping">
    <property name="defaultEndpoint" ref="inferenceEndPoint" />
    <property name="interceptors">
        <list>
            <ref local="validatingInterceptor" />
            <ref local="payLoadInterceptor" />
        </list>
    </property>
</bean>

<bean id="payLoadInterceptor"
    class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor" />

<bean id="validatingInterceptor"
    class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
    <property name="schema"
        value="classpath:/wsdl/Request.xsd" />
    <property name="validateRequest" value="true" />
    <property name="validateResponse" value="false" />
</bean>

<bean id="PropertyResource" class="com.mysite.ws.im.PropertyResource">
    <property name="resource"
        value="/WEB-INF/client-specific/InferenceMachine.properties" />
</bean>

<bean id="inferenceEndPoint" class="com.mysite.ws.web.InferenceEndPoint">
    <property name="messageWebService" ref="messageWebService" />
</bean>
<bean id="messageWebService" class="com.mysite.ws.service.MessageWebService"
    scope="request">
    <aop:scoped-proxy />
    <property name="inferenceService" ref="inferenceService" />
</bean>

<bean id="Request" class="org.springframework.xml.xsd.SimpleXsdSchema">
    <property name="xsd" value="classpath:/wsdl/Request.xsd" />
</bean>

<bean id="Response" class="org.springframework.xml.xsd.SimpleXsdSchema">
    <property name="xsd" value="classpath:/wsdl/Response.xsd" />
</bean>

<bean id="Error" class="org.springframework.xml.xsd.SimpleXsdSchema">
    <property name="xsd" value="classpath:/wsdl/Error.xsd" />
</bean>

<bean id="mwsid"
    class="org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition">
    <constructor-arg value="classpath:/wsdl/mtchwsdl.wsdl" />
</bean>

<bean id="inferenceService" class="com.mysite.ws.im.InferenceService"
    scope="request">
    <aop:scoped-proxy />
    <property name="webServiceConfiguration" ref="wsPlayerConfiguration" />

    <property name="properties">
        <bean class="com.mysite.ws.im.PropertyResource">
            <property name="resource"
                value="/WEB-INF/client-specific/InferenceMachine.properties" />
        </bean>
    </property>
</bean>

<!-- ~~~~~~~ Application beans ~~~~~~~ -->
<bean id="wsPlayerConfiguration"
    class="com.mysite.ws.configuration.WebServiceConfiguration"
    scope="request">
    <aop:scoped-proxy />
    <property name="playerConfiguration" ref="playerConfiguration"></property>
    <property name="configurationSetup" ref="configurationSetup"></property>
</bean>

这是我的端点类:

/**
 * The EndPoint of the Web Service Application. This class gets the raw
 * SOAP-body message from the Spring Payload Dispatcher and sends the message to
 * the @see MessageService class. After it has gotten the response XML message
 * it returns this back to the Spring Payload Dispatcher.
 */
public class InferenceEndPoint extends AbstractJDomPayloadEndpoint {

    private MessageWebService messageWebService;
    public InferenceEndPoint() {
    }

    @Override
    protected Element invokeInternal(Element inferenceRequest) throws Exception {
        Element ret = messageWebService.handleRequest(inferenceRequest);
        return ret;
    }

    /**
     * @param messageWebService
     */
    public void setMessageWebService(MessageWebService messageWebService) {
        this.messageWebService = messageWebService;
    }
}

有什么主意吗?

mpgws1up

mpgws1up1#

Spring-WS只是给bean添加了一些注解,然后你让Spring bean做了大部分繁重的工作。假设你有一些用@Endpoint,@PayloadRoot等注解的类。你应该能够以三种方式之一重用所有这些。
如果您的Spring-WS端点类是适配器模式风格的(例如,您的Endpoint类被注入了一个执行真实的工作的POJO服务),那么您可以做一个类似的适配器风格的Spring MVC控制器(Spring 3.0中存在REST)。
如果直接在业务逻辑类上添加注解,那么理论上,您应该能够添加更多的注解(可能看起来有点忙)。
如果您有POX(而不是SOAP)的Spring-WS bean,那么您也许可以使用一些花哨的URLMap来为它们提供更符合RESTful外观的URL
为了迁移到Spring 3以获得REST支持,添加适当的@RequestMapping和其他注解,将它们公开为REST服务以匹配特定的URL。在添加时,您可能还需要删除旧的@PayloadRoots和@Endpoint,但这可能不是什么大问题。当然,如果您保留旧的Spring-WS注解,您仍然需要在类路径中使用Spring-WS jar。但是只要您没有在Spring文件中使用Spring-WSservlet或任何其他bean,就应该没问题(理论上...)。
最大的难题是:

  • 不要忘记从Spring文件中删除Spring-WS bean
  • 一定要记住将SpringMVC bean添加到Spring文件中,最重要的是添加不同的Dispatcherservlet
  • Spring中的REST安全性将由SpringSecurity提供,而不是Spring-WS中的SOAP拦截器,因此这将是一次彻底的改革。
qco9c6ql

qco9c6ql2#

通过查看代码,很难判断哪种方法最好。REST和SOAP是想象基于Web的服务接口如何工作的完全不同的方法:SOAP是所有关于方法调用的,而REST是所有关于资源、表示和链接的。要转换,你必须从你的底层抽象API开始。
如果您的基本API是“我给予您一个文档,您给我一个响应文档”,并且除此之外没有任何其他公开内容,那么它就是一个 * 非常 * 面向SOAP的模型。您可以在REST中通过POST一个文档并获得响应来对此建模,但它一点也不优雅。如果您可以将您的界面视为“这是一个总体资源,带有我可以设置的属性,和某些我可以做的操作”,那么Map到REST就容易得多(整个资源表示为一个文档,其中充满了指向各个属性资源和操作的链接,各个属性可以是GET和PUT --也可能是DELETEd --如果需要的话)。但我只是猜测,因为真实的确定它需要查看比所显示的更多的代码。

9o685dep

9o685dep3#

没有什么可以阻止您发送填充了XML的POST,以返回填充了XML的结果。
最简单的方法是捕获来回的SOAP请求,然后简单地将请求转换为一个模板,其中的空白作为参数,然后对生成的XML使用XPath来提取结果。
唯一的缺点是你可能需要SOAPAction头在你的POST中,但很可能不是。
这真的没什么大不了的。如果你有几十个方法,那就更麻烦了。而且,如果你使用SOAP的任何加密部分,那就更麻烦了。但是如果只有几个,最终它只是XML,而且大部分XML都是样板文件,所以从这个Angular 看,这是非常简单的。
附录:
如果您有一个后端逻辑,您希望将其与一个更友好的HTTP服务放在一起,那么JAX-RS可以很容易地做到这一点,但是它需要在服务器端进行编码。
如果您希望使用现有的SOAPWeb服务,那么请忘记等式中的整个SOAP部分,而简单地将其视为使用XML有效负载的HTTPWeb服务。它仍然是SOAP,但您没有在客户端使用任何SOAP工具。您只是在客户端请求上组装XML有效负载(从模板是最简单的,恕我直言),并消费XML有效负载作为结果,并通过HTTP交易这些。
根据您打算调用的现有Web服务上的不同方法的数量,您可以了解所涉及的工作范围。这是一项简单的工作(一旦您可以轻松地查看有效负载),但它仍然是工作。如果您只有几个方法,特别是如果接口是稳定的,不会发生变化,那么只使用原始XML比学习和使用一些新的不熟悉的框架要容易得多。

yhqotfr8

yhqotfr84#

这就是我如何解决这个问题的,使用Sping Boot + Spring Integration。

  • 有了SOAPWS的WSDL,我使用maven-jaxb 2-plugin在构建时生成我的JavaPOJO。
  • 或者,您可以创建转换以使这些类和属性适应REST客户端的预期。
  • 使用Spring Integration,我将每个REST端点Map到SOAP网关,如下所示:
@Bean
public IntegrationFlow myFlow(GenericTransformer reqTransformer, GenericTransformer resTransformer) {
    return IntegrationFlows
        .from(this.getRestGateway(POST, "/api/entity", MyRestResponse.class))
        .transform(reqTransformer)
        .handle(this.getSoapGateway("gwBean"))
        .enrichHeaders(h -> h.header(HttpHeaders.STATUS_CODE, HttpStatus.OK))
        .transform(resTransformer)
        .logAndReply();
}

private HttpRequestHandlingMessagingGateway getRestGateway(HttpMethod method, String path, Class payloadType) {
    HttpRequestHandlingMessagingGateway httpGateway = new HttpRequestHandlingMessagingGateway();
    RequestMapping requestMapping = new RequestMapping();
    requestMapping.setMethods(method);
    requestMapping.setPathPatterns(path);
    httpGateway.setRequestMapping(requestMapping);
    httpGateway.setReplyTimeout(timeout);
    httpGateway.setRequestPayloadTypeClass(payloadType);
    httpGateway.setMessageConverters(asList(jsonConverter));
    return httpGateway;
}

private MarshallingWebServiceOutboundGateway getSoapGateway(String nameBean) {
    Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
    marshaller.setContextPath(generatedClassesPackage);
    SaajSoapMessageFactory messageFactory = new SaajSoapMessageFactory();
    messageFactory.setSoapVersion(SoapVersion.SOAP_12);
    messageFactory.afterPropertiesSet();
    MarshallingWebServiceOutboundGateway webServiceGateway = new MarshallingWebServiceOutboundGateway(soapUri, marshaller);
    webServiceGateway.setMessageFactory(messageFactory);
    webServiceGateway.setBeanName(nombreBean);
    return webServiceGateway;
}
cedebl8k

cedebl8k5#

如果我们根本不使用spring,也没有@Payload这样的注解,那么应该采取什么方法呢?简单地将xsd生成的类重用为Pojo,并公开rest控制器应该可以解决问题,否则还有更多的问题。

相关问题