Apache CXF:如何将命名空间添加到 SOAP 请求中的 XML 标记

Apache CXF: How do I add the namespace to a XML tag in a SOAP request

我很难让 Java SOAP 客户端工作。客户端是使用 wsdl 文件和 Apache CXF Maven 插件 3.4.3(见下文)生成的。问题似乎是为请求生成的 XML 不包含正确的命名空间。至少这是我的看法。这是请求 xml:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
  <!-- Security information -->
  </soap:Header>
  <soap:Body>
    <ns2:createUserRequest xmlns:ns2="http://www.server.com/schema/user">
      <user>
        <username>homer.simpson</username>
        <surname>simpson</surname>
        <firstname>homer</firstname>
        <email>homer.simpson@springfield.com</email>
        <password>superSecretPassword</password>
      </user>
    </ns2:createUserRequest>
  </soap:Body>
</soap:Envelope>

这是服务器的响应:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Header/>
  <SOAP-ENV:Body>
    <SOAP-ENV:Fault>
      <faultcode>SOAP-ENV:Client</faultcode>
      <faultstring xml:lang="en">Validation error</faultstring>
      <detail>
        <spring-ws:ValidationError xmlns:spring-ws="http://springframework.org/spring-ws">cvc-complex-type.2.4.a: Invalid content was found starting with element 'user'. One of '{"http://www.server.com/schema/user":user}' is expected.</spring-ws:ValidationError>
      </detail>
    </SOAP-ENV:Fault>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

我已经使用 SOAP UI 5.6.0 成功创建了一个请求。在这里,请求如下所示:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
                   xmlns:user="http://www.server.com/schema/user">
  <soapenv:Header>
  <!-- Security information -->
  </soapenv:Header>
  <soapenv:Body>
    <user:createUserRequest>
      <user:user>
        <user:username>bart.simpson</user:username>
        <user:firstname>Bart</user:firstname>
        <user:surname>Simpson</user:surname>
        <user:email>bart.simpson@springfield.com</user:email>
        <user:password>superSecretPassword.</user:password>
      </user:user>
    </user:createUserRequest>
  </soapenv:Body>
</soapenv:Envelope>

因此,不同之处在于第一个 xml 中未使用名称空间前缀(已编辑 - 感谢 vanje)。 xml 两个文件似乎都有效。但是,应该注意的是,模式文件显然无法从 Internet 访问。

我该如何补救?

这是生成的客户端文件的问题吗?或者我使用客户端的方式?

我使用 Apache CXF Maven 插件 3.4.3 从 wsdl 文件创建了一个 SOAP 客户端。使用了以下配置:

 <plugin>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-codegen-plugin</artifactId>
    <version>${cxf.version}</version>
    <executions>
      <execution>
        <id>generate-sources</id>
        <phase>generate-sources</phase>
        <configuration>
          <sourceRoot>${project.build.directory}/generated-sources/cxf</sourceRoot>
          <disableDirectoryScan>true</disableDirectoryScan>
          <defaultOptions>
            <extraargs>
              <extraarg>-verbose</extraarg>
              <extraarg>-validate</extraarg>
              <extraarg>-impl</extraarg>
              <extraarg>-client</extraarg>
              <extraarg>-suppress-generated-date</extraarg>
            </extraargs>
          </defaultOptions>
          <wsdlOptions>
            <wsdlOption>
              <wsdl>${project.basedir}/src/main/resources/wsdl/user.wsdl</wsdl>
              <serviceName>UserService</serviceName>
              <wsdlLocation>classpath:user.wsdl</wsdlLocation>
            </wsdlOption>
          </wsdlOptions>  
        </configuration>
        <goals>
          <goal>wsdl2java</goal>
        </goals>
      </execution>
    </executions>
  </plugin>

我使用的方法:

@WebMethod
  @WebResult(name = "createUserResponse", targetNamespace = "http://www.server.com/schema/user",
      partName = "createUserResponse")
  public CreateUserResponse createUser(

      @WebParam(partName = "createUserRequest", name = "createUserRequest",
          targetNamespace = "http://www.server.com/schema/user") CreateUserRequest createUserRequest);

这是客户:

public final class User_UserSoap11_Client {

  private static final QName SERVICE_NAME =
      new QName("http://www.server.com/schema/user", "UserService");

  private User_UserSoap11_Client() {}

  public static void main(String args[]) throws Exception {
    URL wsdlURL = UserService.WSDL_LOCATION;
    if (args.length > 0 && args[0] != null && !"".equals(args[0])) {
      File wsdlFile = new File(args[0]);
      try {
        if (wsdlFile.exists()) {
          wsdlURL = wsdlFile.toURI().toURL();
        } else {
          wsdlURL = new URL(args[0]);
        }
      } catch (MalformedURLException e) {
        e.printStackTrace();
      }
    }

    UserService ss = new UserService(wsdlURL, SERVICE_NAME);

    User port = ss.getUserSoap11();

    // Adding security information

    {
      System.out.println("Invoking createUser...");

      final Newusertype newuser = new Newusertype();
      newuser.setUsername("homer.simpson");
      newuser.setFirstname("homer");
      newuser.setSurname("simpson");
      newuser.setEmail("homer.simpson@springfield.com");
      newuser.setPassword("mySecretPassword");
      CreateUserRequest _createUser_createUserRequest =
          new ObjectFactory().createCreateUserRequest();
      _createUser_createUserRequest.setUser(newuser);
    
      CreateUserResponse _createUser__return = null;
      try {
        _createUser__return = port.createUser(_createUser_createUserRequest);
      } catch (Exception e) {
        System.out.println(e.getMessage());
        e.printStackTrace();
      }

}}

这是使用的 WSDL 文件的缩短版本:

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
                  xmlns:tns="http://www.server.com/schema/user" targetNamespace="http://www.server.com/schema/user">
  <wsdl:types>
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:vendoruser="http://www.server.com/schema/user"
               elementFormDefault="qualified" targetNamespace="http://www.server.com/schema/user" version="1.0">

      <xs:element name="createUserRequest" xmlns:xs="http://www.w3.org/2001/XMLSchema">
        <xs:complexType xmlns:xs="http://www.w3.org/2001/XMLSchema">
          <xs:all xmlns:xs="http://www.w3.org/2001/XMLSchema">
            <xs:element name="user" type="vendoruser:newusertype" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
          </xs:all>
        </xs:complexType>
      </xs:element>
      <xs:element name="createUserResponse" xmlns:xs="http://www.w3.org/2001/XMLSchema">
        <xs:complexType xmlns:xs="http://www.w3.org/2001/XMLSchema">
          <xs:all xmlns:xs="http://www.w3.org/2001/XMLSchema">
            <xs:element name="userid" type="xs:int" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
            <xs:element minOccurs="0" name="passwordlink" type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
          </xs:all>
        </xs:complexType>
      </xs:element>

      <xs:complexType name="newusertype" xmlns:xs="http://www.w3.org/2001/XMLSchema">
        <xs:all xmlns:xs="http://www.w3.org/2001/XMLSchema">
          <xs:element name="username" type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
          <xs:element name="surname" type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
          <xs:element name="firstname" type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
          <xs:element name="email" type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
          <xs:element name="password" type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
          <xs:element name="customeridlist" type="vendoruser:idlist" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
        </xs:all>
      </xs:complexType>

      <xs:simpleType name="idlist" xmlns:xs="http://www.w3.org/2001/XMLSchema">
        <xs:list itemType="xs:int" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>
      </xs:simpleType>

    </xs:schema>
  </wsdl:types>
  <wsdl:message name="createUserRequest">
    <wsdl:part element="tns:createUserRequest" name="createUserRequest">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="createUserResponse">
    <wsdl:part element="tns:createUserResponse" name="createUserResponse">
    </wsdl:part>
  </wsdl:message>
  <wsdl:portType name="User">
    <wsdl:operation name="createUser">
      <wsdl:input message="tns:createUserRequest" name="createUserRequest">
      </wsdl:input>
      <wsdl:output message="tns:createUserResponse" name="createUserResponse">
      </wsdl:output>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="UserSoap11" type="tns:User">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="createUser">
      <soap:operation soapAction=""/>
      <wsdl:input name="createUserRequest">
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="createUserResponse">
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="UserService">
    <wsdl:port binding="tns:UserSoap11" name="UserSoap11">
      <soap:address location="https://server.com/vendor/services/"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

这是 Apache CXF 3.4.3 生成的 CreateUserRequest

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {

})
@XmlRootElement(name = "createUserRequest")
public class CreateUserRequest {

    @XmlElement(required = true)
    protected Newusertype user;

  // Getter and Setter
}

这是生成的 Newusertype 对象:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "newusertype", propOrder = {

})
public class Newusertype {

    @XmlElement(required = true)
    protected String username;
    @XmlElement(required = true)
    protected String surname;
    @XmlElement(required = true)
    protected String firstname;
    @XmlElement(required = true)
    protected String email;
    @XmlElement(required = true)
    protected String password;
    @XmlList
    @XmlElement(type = Integer.class)
    protected List<Integer> customeridlist;

    // Getter and setter

}

问题已解决。莫洛克做出了正确的决定。我将生成的 类 从目标文件夹移动到源文件夹并重命名了包。当我保留生成的包名称时,一切正常。

我将 wsdl 文件放在 src/main/resources 下,因为生成的服务使用以下内容加载 wsdl:

URL url = UserService.class.getClassLoader().getResource("user.wsdl");

如果 wsdl 文件放在 src/main/resources/wsdl 下,这将不起作用。

public class UserService extends Service {

    public final static URL WSDL_LOCATION;

    public final static QName SERVICE = new QName("http://www.vendor.com/schema/user", "UserService");
    public final static QName UserSoap11 = new QName("http://www.vendor.com/schema/user", "UserSoap11");
    static {
        URL url = UserService.class.getClassLoader().getResource("user.wsdl");
        if (url == null) {
            java.util.logging.Logger.getLogger(UserService.class.getName())
                .log(java.util.logging.Level.INFO,
                     "Can not initialize the default wsdl from {0}", "classpath:user.wsdl");
        }
        WSDL_LOCATION = url;
    }

    public UserService() {
        super(WSDL_LOCATION, SERVICE);
    }
}