【问题标题】:SOAP WS - make @WebParam optionalSOAP WS - 使 @WebParam 可选
【发布时间】:2014-02-06 09:10:08
【问题描述】:

我有一个非常简单的方法,我通过 JAX-WS 注释在 WS API 中使用它:

@WebMethod
public MyResponse sendSingle2(
    @WebParam(name="username") String username,
    @WebParam(name="password") String password,
    @WebParam(name="newParam") String newParam) {
        // the code
    }

现在我希望 newParam 是可选的。我的意思是我希望该方法不仅在传递的 xml 中的参数为空时仍然有效:

<ws:sendSingle2>
    <username>user</username>
    <password>pass</password>
    <newParam></newParam>
</ws:sendSingle2>

但当它不存在时:

<ws:sendSingle2>
    <username>user</username>
    <password>pass</password>
</ws:sendSingle2>

我不需要它来破坏现有的 API,它在没有新参数的情况下也可以工作。

【问题讨论】:

    标签: java web-services soap jaxb jax-ws


    【解决方案1】:

    @WebParam 将消息部分映射到参数,并且部分不能是可选的。见Optional Message Parts in WSDL。因此,简短的回答是,您所要求的正是无法完成的。但是,如果您可以重构此方法,则可以使用下面描述的方法之一。

    通常通过模式minOccurs=0 设置参数的可选性。此外,您可以在架构中定义一个请求参数,而不是使用多个参数,您可以将其定义为WebMethod 的参数。可选性现在被封装在参数中,并且调用相同的方法来调用带有或不带有可选参数的调用。

    我更喜欢先定义合同,而不是依赖自动生成的文件。一旦您弄清楚了 XSD、SOAP 和 WSDL 如何协同工作,您就再也不想使用基于注释/代码优先的定义了,因为反过来您会更加灵活。

    代码示例:

    <xs:schema
        targetNamespace="http://your.namespace.com"
        xmlns:tns="http://your.namespace.com"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        elementFromDefault="qualified"
        attributeFromDefault="qualified">
    
    ...
    
    <xs:element name="MyRequest" type="tns:MyRequestType" />
    <xs:element name="MyResponse" type="tns:MyResponseType" />
    
    <xs:complexType name"MyRequestType">
        <xs:sequence>
            <xs:element name="username" type="xs:string" minOccurs="1" maxOccurs="1" />
            <xs:element name="password" type="xs:string" minOccurs="1" maxOccurs="1" />
            <xs:element name="newParam" type="xs:string" minOccurs="0" maxOccurs="1" />
        </xs:sequence>
    </xs:complexType>
    
    ...
    
    </xs:schema>
    

    在您的 WSDL 文件中,您可以这样定义消息:

    <wsdl:definitions
        xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
        xmlns:msg="http://your.namespace.com"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
        xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
        xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
        targetNamespace="http://your.namespace.com">
    
        <wsdl:types>
            <xs:schema>
                <!-- either import the externalized schema -->
                <xs:import namespace="http://your.namespace.com"
                           schemaLocation="someDir/yourMessageSchema.xsd" />
            </xs:schema>
            <!-- or define the schema within the WSDL - just copy the schema here -->
            <xs:schema
                targetNamespace="http://your.namespace.com"
                xmlns:tns="http://your.namespace.com"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                elementFromDefault="qualified"
                attributeFromDefault="qualified">
                    ...
            </xs:schema>
        </wsdl:types>
    
        ...
    
        <wsdl:message name="sendSingle2Request">
            <wsdl:part name="in" element="msg:MyRequest" />
        </wsdl:message>
    
        <wsdl:message name="sendSingle2Response">
            <wsdl:part name="out" element="msg:MyResponse" />
        </wsdl:message>
    
        ...
    
        <wsdl:portType name="YourServiceEndpoint">
            <wsdl:operation name="sendSingle2">
                <wsdl:input message="tns:sendSingle2Request" />
                <wsdl:output message="tns:sendSingle2Response" />
            </wsdl:operation>
            ...
        </wsdl:portType>
    
        <wsdl:binding name="YourServiceBinding" type="YourServiceEndpoint">
            <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
            <wsdl:operation name=""sendSingle2">
                <soap:operation soapAction="http://your.namespace.com/SendSingle2" style="document" />
                <wsdl:input>
                    <soap:body parts="in" use="literal" />
                </wsdl:input>
                <wsdl:output>
                    <soap:body parts="out" use="literal" />
                </wsdl:output>
            </wsdl:operation>
            ...
        </wsdl:binding>
    
        <wsdl:service name="YourService">
            <wsdl:port name="YourServicePort binding="tns:YourServiceBinding">
                <soap:address location="http://your.server:port/path/to/the/service" />
            </wsdl:port>
        </wsdl:service>
    </wsdl:definitions>
    

    这里的 WSDL 契约定义使用样式:document/literal,并且在模式的帮助下,实际的 SOAP 消息将是 document/literal wrapped,这进一步符合 WS-I。

    因此,您的方法将更改为公共MyResponse sendSinge2(MyRequest request),其中request 现在封装usernamepassowrdnewParam。如果 newParam 没有与 SOAP 请求一起发送,它只会返回 null,所以最好在使用之前先检查一下。

    如果您坚持代码优先的方法,则需要首先定义您的 MyRequest 类,将其用作请求参数,而不是那些 2 或 3 个值。

    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlRootElement(name = "MyRequest", namespace="http://your.namespace.com")
    public class MyRequest implements Serializable
    {
       @XmlElement(name = "username", required = true)
       protected String username;
       @XmlElement(name = "password", required = true)
       protected String password;
       @XmlElement(name = "newParam", required = false)
       protected String newParam;
       ...
    }
    

    MyResult 如果您还没有这样做,也应该这样做。 Web 方法现在可能看起来像这样:

    @WebMethod(operationName = "sendSingle2")
    @WebResult(name = "sendSingle2Response", targetNamespace = "http://your.namespace.com")
    public MyResult sendSingle2(@WebParam(name = "sendSingle2Request") MyRequest request)
    {
       ...
    }
    

    再次,request 封装了 3 个参数,您首先应该检查可选参数是否为空。

    HTH

    【讨论】:

    • 谢谢。这就是我想采取的方式。
    • @Roman Vottner 很好的解释。你能推荐一个开始学习 Web 服务合同优先开发方法的好地方吗?关于 WSDL、SOAP、XSD?有什么书吗?
    • @Octopus 通常维基百科条目(WSDLSOAPXSD)是开始的好地方。谷歌和 SO 也提供了足够多的关于这个问题的好链接。阅读 WSDL 规范也可能有所帮助,但不是强制性的。 F.e:IBMOracle 也有有用的信息
    • @RomanVottner 您能否解释一下如何在 rpc/literal 中执行此操作?我目前正在处理需要在 rpc 中的项目。
    • 一旦有了wsdl,如何生成java服务。我已经尝试了在互联网上找到的所有教程,但没有一个有效。我正在使用 JBoss eap 6.4
    【解决方案2】:

    这完全取决于你的实现类,你在哪里使用这些参数。 在端点界面只需将此参数添加为 webparam。

    确保在您的实现类中如果您在任何地方使用此参数,请添加替代代码(Else 部分)以执行您的操作或在没有此参数的情况下执行。

    我认为所有参数都视为可选,除非您验证它们或按照建议在实现类中使用它们。

    【讨论】:

    • 嗯,没那么简单。这个方法甚至没有被输入,因为它在方法调用之前就失败了。
    • 无法理解你,我只是解释了概念明智。给我一些关于你的问题的更多意见。
    • 我编辑了源代码,并在那里添加了“newParam”。我希望在这两种情况下都调用我的方法(带注释的@WebMethod),并包含我的两个 SOAP sn-ps。现在,只有当我在 SOAP 消息(第一个 XML sn-p)中包含“”时才调用它。如果不包含它(第二个 XML sn-p),我的方法甚至不会被调用。正如对这个问题 (stackoverflow.com/questions/8324847/…) 的回答所暗示的那样,恐怕我想要实现的目标是不可能的。
    • 等一下,让我试试这个,虽然上面的答案似乎有道理,但应该有办法解决。
    猜你喜欢
    • 2018-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多