本文介绍了SOAP WS - 使@WebParam可选的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have quite a simple method, which I use in WS API by JAX-WS annotations:

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

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

Now I want newParam to be optional. I mean I want the method still to work not only when parameter is empty in passed xml:

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

但是当它不存在时:

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

我需要它不要破坏现有的API,它可以在没有新参数的情况下运行。

I need it not to break existing API, which works without the new param.

推荐答案

@WebParam将消息部分映射到参数,而部分不能是可选的。请参阅。因此,简短的回答是,你所要求的正是无法完成的。但是如果你可以重构这个方法,你可以使用下面描述的方法之一。

@WebParam maps a message part to a parameter, and parts can't be optional. See Optional Message Parts in WSDL. Therefore the short answer is that precisely what you're asking can't be done. But if you can refactor this method, you can use one of the approaches described below.

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

Usually the optionality of a parameter is set via the schema minOccurs=0. Furthermore, instead of using multiple parameters you could define one Request parameter in your schema which you define as parameter for your WebMethod. The optionality is now encapsulated within the parameter and the same method is invoked for a call with or without the optional parameter(s).

我更喜欢先定义合约而不是依靠自动生成的文件。一旦你弄清楚XSD,SOAP和WSDL如何一起玩,你几乎不想再使用基于注释/代码优先的定义了,因为你反过来更灵活。

I prefer defining the contract first instead of relying on automatically generated files. Once you figured out how XSD, SOAP and WSDL play in-together, you hardly want to use annotation/code-first based definitions any longer as you are more flexible the other way around.

代码示例:

<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文件中,您可以定义如下消息:

In your WSDL file you define the message like that:

<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标准。

The WSDL contract here defines to use style: document/literal and with the help of the schema the actual SOAP message will be document/literal wrapped which is furthermore WS-I compliant.

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

Your method will therefore change to public MyResponse sendSinge2(MyRequest request) where request now encapsulates username, passowrd and newParam. In case newParam was not send with the SOAP request it simply will return null, so better check if first before you use it.

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

If you stick to the code-first approach, you will need to define your MyRequest class first which you use as request parameter instead of those 2 or 3 values.

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

同样应该为<$ c做同样的事情$ c> MyResult 如果你还没有这样做的话。 web方法现在看起来像这样:

The same should be done for MyResult if you haven't done it yet. The web method may now look something like that:

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

再次,请求封装3个参数,你应该检查可选参数是否为空。

Again, request encapsulates the 3 parameters where you fist should check if the optional parameters are null.

HTH

这篇关于SOAP WS - 使@WebParam可选的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-24 03:06