记录:315
场景:解决org.apache.axis2.AxisFault: Unmarshalling Error: unexpected element(uri:"http://www.pro.com", local:"xmlStr"). Expected elements are<{}arg0>。
版本:
JDK 1.8
Spring Boot 2.6.3
Apache CXF 3.5.1
Apache Axis2 1.8.2
基础环境:
服务端:基于Spring Boot应用Apache CXF发布的Web Services服务作为服务端。
客户端:基于Spring Boot使用Apache Axis2实现的Web Services客户端。
1.报错解决
1.1报错信息
报错信息一:org.apache.axis2.AxisFault: Unmarshalling Error: 意外的元素 (uri:"http://www.pro.com", local:"xmlStr")。所需元素为<{}arg0>
报错信息二:org.apache.axis2.AxisFault: Unmarshalling Error: unexpected element(uri:"http://www.pro.com", local:"xmlStr"). Expected elements are<{}arg0>
报错信息三org.apache.axis2.AxisFault: Unmarshalling Error: 意外的元素 (uri:"http://www.pro.com", local:"arg0")。所需元素为<{}arg0>
报错信息四:org.apache.axis2.AxisFault: Unmarshalling Error: unexpected element(uri:"http://www.pro.com", local:"arg0"). Expected elements are<{}arg0>
报错信息五:org.apache.axis2.AxisFault: Unmarshalling Error: 意外的元素 (uri:"http://www.pro.com", local:"xmlStr")。所需元素为<{}xmlStr>
报错信息六:org.apache.axis2.AxisFault: Unmarshalling Error: unexpected element(uri:"http://www.pro.com", local:"xmlStr"). Expected elements are<{}xmlStr>
1.2问题分析
分析原因:
(1)Apache Axis2实现的客户端,在调用服务端方法时,客户端设置调用方法的参数名和服务端参数名称不匹配;客户端设置设置命名空间名称和服务端发布方法上的命名空间不匹配。
(2)如果使用Apache CXF实现的客户端不会出现这种报错,区别在于Apache CXF一般都是动态方式创建客户端,Apache CXF底层会去做这些参数匹配。而使用Apache Axis2实现的客户端,一般的都是静态指定的相关参数,因此,需要严格匹配。
1.3解决
(1)服务端设置
在服务端发布的方法上,加上@WebParam注解,并且该注解的name和targetNamespace属性都得赋值。
例如:
@WebService(targetNamespace = "http://www.pro.com")
public interface IProvinceInfo {
String getProvince(@WebParam(name = "xmlStr", targetNamespace = "http://www.pro.com") String xmlStr);
}
(2)客户端设置
客户端需严格匹配服务端的设置。
例如:
@Slf4j
public class Axis2ClientUtils {
public static void main(String[] args) {
// 1.服务端地址
String wsdlAddr = "http://127.0.0.1:18080/example-cxf/WebServices/provinceInfoWS?wsdl";
// 2.服务端的命名空间
String targetNamespace = "http://www.pro.com";
// 3.服务端发布的方法
String methodName = "getProvince";
// 4.服务端发布的方法的入参的参数名称
String paramName = "xmlStr";
// 5.服务端发布的方法的入参的参数值
String paramValue = "Hangzhou";
try {
String result = Axis2ClientUtils.invokeWs(wsdlAddr, targetNamespace,
methodName, paramName, paramValue);
log.info("Axis2客户端接收到服务端返回值:" + result.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
public static String invokeWs(String wsdlAddr, String targetNamespace, String methodName, Object... params) {
String result = "";
try {
ServiceClient serviceClient = new ServiceClient();
Options options = serviceClient.getOptions();
EndpointReference endpointReference = new EndpointReference(wsdlAddr);
options.setTo(endpointReference);
// 服务端没有指定soapAction,则直接设置为空
options.setAction("");
OMFactory omFactory = OMAbstractFactory.getOMFactory();
OMNamespace omNamespace = omFactory.createOMNamespace(targetNamespace, "");
// 服务端发布的方法,客户端会用一个OMElement对象去对应
OMElement methodOMElement = omFactory.createOMElement(methodName, omNamespace);
// 服务端方法的形式参数名称和实参的值是一对的且传入一个OMElement
// 如果服务端方法有多个参数,则就会构造多个OMElement
for (int i = 0; i < params.length; i = i + 2) {
// 参数名称
OMElement paraOMElement = omFactory.createOMElement(String.valueOf(params[i]), omNamespace);
// 参数值
paraOMElement.setText(String.valueOf(params[i + 1]));
// 把设置参数的OMElement加入到方法的OMElement中
methodOMElement.addChild(paraOMElement);
}
methodOMElement.build();
// 返回结果有一个OMElement对象去对应
OMElement resultOMElement = serviceClient.sendReceive(methodOMElement);
result = resultOMElement.getFirstElement().toString();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
public static String getXmlStr() {
String xmlStr = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<data>\n" +
" <row>\n" +
" <column Name=\"ProvinceName\">浙江</column>\n" +
" <column Name=\"ProvinceNo\">330000</column>\n" +
" </row>\n" +
"</data>";
return xmlStr;
}
}
2.查看wsdl文件
在开发客户端时,一般需要了解到服务端发布服务信息,一般从wsdl文件中获取。
服务端发布wsdl地址:
http://127.0.0.1:18080/example-cxf/WebServices/provinceInfoWS?wsdl
使用wsdl地址在浏览器中访问,可以看到页面信息。
命名空间名称:targetNamespace="http://www.pro.com"。
方法名称:getProvince。
方法参数名称:xmlStr。
soapAction名称:<soap:operation soapAction="" style="document"/>。
服务名称,<wsdl:service name="ProvinceInfoImplService">。
以上,感谢。
2022年11月13日