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);
}
}
我很难让 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);
}
}