记录:314
场景:在Spring Boot微应用上,使用Apache CXF框架实现Web Services客户端,调用Web Services服务端;使用Apache Axis2框架实现Web Services客户端,调用Web Services服务端。
版本:
JDK 1.8
Spring Boot 2.6.3
Apache CXF 3.5.1
Apache Axis2 1.8.2
一、Web Services服务端
本例是基于基于Spring Boot使用Apache CXF发布Web Services服务,作为服务端,用来验证客户端。
集成方式具体细节可以参考如下博文,本例只列出关键部分。
名称:基于Spring Boot应用Apache CXF发布Web Services服务
地址:https://blog.csdn.net/zhangbeizhen18/article/details/127417394
1.发布Web Services服务的接口类和实现类
1.1接口类
package com.hub.example.webservice;
import javax.jws.WebParam;
import javax.jws.WebService;
/**
* 发布WebService服务的接口
* 使用@WebService标记,并指定命名空间.
* 本例指定: http://www.pro.com
* 不指定则默认: webservice.example.hub.com
* 实际就是包名倒序.
* @date: 2022-11-13 16:55
*/
@WebService(targetNamespace = "http://www.pro.com")
public interface IProvinceInfo {
/**
* 入参: XML格式字符串
* 返回: XML格式字符串
*/
String getProvince(@WebParam(name = "xmlStr",targetNamespace = "http://www.pro.com")String xmlStr);
}
1.2实现类
package com.hub.example.webservice.impl;
import com.hub.example.webservice.IProvinceInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.jws.WebParam;
import javax.jws.WebService;
import java.util.UUID;
@Slf4j
@WebService(targetNamespace = "http://www.pro.com")
@Component
public class ProvinceInfoImpl implements IProvinceInfo {
/**
* 接口实现类
* */
@Override
public String getProvince(@WebParam(name = "xmlStr",targetNamespace = "http://www.pro.com")String xmlStr) {
String result = "";
log.info("WebService的getProvince方法,接收入参,xmlStr:" + xmlStr);
String uuid = UUID.randomUUID().toString().toUpperCase().replace("-", "");
result = buildXml("1", "执行成功",uuid);
log.info("WebService的getProvince方法,返回,result:" + result);
return result;
}
/**
* 辅助方法,组装xml格式字符串
* */
private String buildXml(String rtnCode, String rtnMsg,String uuid) {
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<data>\n" +
" <row>\n" +
" <column Name=\"code\">" + rtnCode + "</column>\n" +
" <column Name=\"message\">" + rtnMsg + "</column>\n" +
" <column Name=\"randomUUID\">" + uuid + "</column>\n" +
" </row>\n" +
"</data>";
return xml;
}
}
2.发布Web Services服务的配置类
@Configuration
public class CxfConfiguration {
@Autowired
private Bus bus;
/**
* 注入对外提供服务的实现类
*/
@Autowired
private ProvinceInfoImpl provinceInfoImpl;
/**
* 配置CXFServlet,拦截/WebServices请求
* 注意: /WebServices作为http请求url前缀专门给CXFServlet使用
**/
@Bean
public ServletRegistrationBean<CXFServlet> configCXFServlet() {
return new ServletRegistrationBean<CXFServlet>(new CXFServlet(), "/WebServices/*");
}
/**
* 发布CXF服务,使用org.apache.cxf.jaxws包的EndpointImpl发布
*/
@Bean
public Endpoint endpointProvinceInfo() {
EndpointImpl endpoint = new EndpointImpl(bus, provinceInfoImpl);
endpoint.publish("/provinceInfoWS");
return endpoint;
}
}
3.发布Web Services地址
本例发布服务地址,根据配置类中信息可以组装完成。
地址:http://127.0.0.1:18080/example-cxf/WebServices/provinceInfoWS?wsdl
解析:example-cxf,是微服务名称;WebServices,专门给CXFServlet使用,用来确认请求是WebServices的请求;provinceInfoWS,是Web Services发布的地址;wsdl,是Web Services约定的标识符。
二、使用Apache CXF框架实现Web Services客户端
使用Apache CXF框架实现客户端方式有很多,开发者按需选择。
1.客户端一
1.1客户端代码
package com.hub.example.cxf;
import lombok.extern.slf4j.Slf4j;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
@Slf4j
public class CxfClientUtils {
public static void main(String[] args) {
// 1.服务端地址
String wsdlAddr = "http://127.0.0.1:18080/example-cxf/WebServices/provinceInfoWS?wsdl";
// 2.服务端发布的方法
String methodName = "getProvince";
// 3.服务端发布的方法的入参的参数值
String xmlStr = getXmlStr();
Object[] para = new Object[]{xmlStr};
// 4.客户端发起调用
invokeWs(wsdlAddr, methodName, para);
}
/**
* wsdlAddr: 服务端发布的地址
* methodName: 服务端发布的方法名称
* params: 服务端发布的方法的参数值
*/
public static Object[] invokeWs(String wsdlAddr, String methodName, Object[] para) {
// 设置90秒接收超时
long receiveTimeout = 1000 * 90;
// 设置90秒连接超时
long connectionTimeout = 1000 * 90;
// 以动态方式创建客户端以及设置相关参数
JaxWsDynamicClientFactory jwdcf = JaxWsDynamicClientFactory.newInstance();
Client cli = jwdcf.createClient(wsdlAddr);
Object[] obj = null;
HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
HTTPConduit conduit = (HTTPConduit) cli.getConduit();
httpClientPolicy.setConnectionTimeout(connectionTimeout);
httpClientPolicy.setReceiveTimeout(receiveTimeout);
conduit.setClient(httpClientPolicy);
try {
obj = cli.invoke(methodName, para);
log.info("cxf客户端接收到服务端返回值:" + obj[0].toString());
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
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;
}
}
1.2在main函数验证
直接右键,main函数调用即可。
三、使用Apache Axis2框架实现Web Services客户端
使用Apache Axis2框架实现客户端方式有很多,开发者按需选择。
1.客户端一个
1.1客户端代码
package com.hub.example.axis2;
import lombok.extern.slf4j.Slf4j;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axis2.AxisFault;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
@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 = getXmlStr();
try {
String result = Axis2ClientUtils.invokeWs(wsdlAddr, targetNamespace,
methodName, paramName, paramValue);
log.info("Axis2客户端接收到服务端返回值:" + result.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* wsdlAddr: 服务端发布的地址
* targetNamespace: 服务端发布的命名空间
* methodName: 服务端发布的方法名称
* params: 服务端发布的方法的参数名称和参数值
*/
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;
}
}
1.2在main函数验证
直接右键,main函数调用即可。
四、小结
使用Apache CXF实现的客户端,代码简洁,手动设置参数少。
使用Apache Axis2实现的客户端,需要仔细比对客户端和服务端,对应参数需要确认一致。
以上,感谢。
2022年11月13日