使用Apache CXF和Apache Axis2实现Web Services客户端

记录: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日

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值