Java使用Axis2调用【.net】Web Service服务(快速上手、精简)

就在昨天临下班,项目经理提了个需求!!反馈档案系统的对接,这个系统 .net开发而不是用Java写的WebService接口 虽说都一样,但还是有坑的,与往常的域名端口号相比,发布一般都是用WSDL文件样式发布,在文件里包含这个WebService对外暴露可使用的接口信息,使用.asmx站点路径和namespace访问。看完客户发来的文档看能看懂,技术完全没接触过一头雾水。。。。。花了点时间问技术经理思路加上自己搜索资料,接下来我们来看看简单的使用吧~ ~~ 开锤!!!

这里我使用的是 Apache AXIS (技术点)
客户那边是用 .net开发 的WebSerivce服务端

http://www.webxml.com.cn/WebServices/IpAddressSearchWebService.asmx
这是一个很好的WebService服务地址,后面加(?wsdl)可以查看WSDL文件样式
wsimport -s ./ url (这是个命令,可以将wsdl文件生成本地文件 ./ 是生成地的目录)
wsimport命令是jdk提供的,作用是根据使用说明书生成客户端代码,wsimport只支持SOAP1.1客户端的生成

这里能使用的技术有很多种,根据自己的需要选择

  • 使用Apache的AXIS 1.x … AXIS 2.x
  • 使用Document方式生成参数列表调用,使用也是AXIS(传递字符类型很好用,对于数组什么类型比较麻烦)不用生成客户端代码
  • 使用OkHttp自己组装soap协议(应该就是拼接成XML的形式)然后调用
  • 使用wsdl2java工具,生成客户端代码调用WebService(一般内网系统没有WSDL文件没法生成)
  • 其他方法。。。

1. 听说了下面就是整合使用,先引入.jar包

这里我使用的是1.x版本

   	 <dependency>
   	      <groupId>org.apache.axis</groupId>
   	      <artifactId>axis</artifactId>
   	      <version>1.4</version>
   	  </dependency>
   	  <dependency>
   	      <groupId>org.apache.axis</groupId>
   	      <artifactId>axis-jaxrpc</artifactId>
   	      <version>1.4</version>
   	  </dependency>
   	  <dependency>
   	      <groupId>axis</groupId>
   	      <artifactId>axis-wsdl4j</artifactId>
   	      <version>1.5.1</version>
   	  </dependency> 

2. 编写工具类调用服务

import cn.hutool.core.lang.Assert;
import com.google.common.collect.Lists;
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.axis.encoding.XMLType;
import org.apache.axis.encoding.ser.Base64DeserializerFactory;
import org.apache.axis.encoding.ser.Base64SerializerFactory;
import org.apache.axis.message.SOAPHeaderElement;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.xml.namespace.QName;
import javax.xml.rpc.ParameterMode;
import java.net.URL;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Component
public final class WebServiceUtils {
	// 接口的调用地址
	private static String ENDPOINT;
	// 命名空间
	private static String NAMESPACE;
	
	@Value("${websevice.endpoint}")
	public void setENDPOINT(String ENDPOINT) {
    	Assert.notEmpty(ENDPOINT, "服务地址未配置");
    	WebServiceUtils.ENDPOINT = ENDPOINT;
	}

   @Value("${websevice.namespace}")
   public void setNAMESPACE(String NAMESPACE) {
       Assert.notEmpty(NAMESPACE, "命名空间值未设置");
       WebServiceUtils.NAMESPACE = NAMESPACE;
   }
   
   /**
   	* methodName:调用的方法名
   	* params:调用方法需要的参数
   	* return:String类型的返回值
   	*/
   @SuppressWarnings("rawtypes")
   public static String call(String methodName, LinkedHashMap<String, LinkedHashMap<Object, Class>> params) {
   		Service service = new Service();
   		Call call = (Call) service.createCall();
   		SOAPHeaderElement soapHeaderElement = new SOAPHeaderElement(NAMESPACE, methodName);
   		soapHeaderElement.setNamespaceURI(NAMESPACE);
   		call.setTargetEndpointAddress(new URL(ENDPOINT));
   		QName qName = new QName(NAMESPACE, methodName);
   		call.setOperationName(qName);
   		call.setSOAPActionURI(NAMESPACE + methodName);
   		call.setUseSOAPAction(true);
   		call.setReturnType(qName, String.class);
   		call.addHeader(soapHeaderElement);
   		// 如果参数中包含字节数组 注册Base64编码解码器,主要是用传送文件
   		if (params.values().stream().map(LinkedHashMap::values).anyMatch(v -> v.stream().anyMatch(t -> t == byte[].class))) {
   			call.registerTypeMapping(byte[].class, qName, new Base64SerializerFactory(byte[].class, qName), new Base64DeserializerFactory(byte[].class, qName));
   		}
   		
   		List<Object> parameterList = Lists.newArrayList();
   		for (Map.Entry<String, LinkedHashMap<Object, Class>> keyEntry : params.entrySet()) {
   			for (Map.Entry<Object, Class> valueEntry : keyEntry.getValue().entrySet()) {
   				call.addParameter(new QName(NAMESPACE, keyEntry.getKey()), getXmlType(valueEntry), ParameterMode.IN);
   				parameterList.add(valueEntry.getKey());
   			}
   		}

   		String result = String.valueOf(call.invoke(parameterList.toArray()));
   		return result;
   }

   /**
   	* valueEntry:参数值对应的Class对象
   	* return:QName对象,表示参数的类型
   	*/
   private static QName getXmlType(Map.Entry<Object, Class> valueEntry) {
       Class clazz = valueEntry.getValue();
       QName qName = null;
       if (clazz == byte[].class) {
           qName = XMLType.XSD_BASE64;
       } else {
           qName = XMLType.XSD_STRING;
       }
       return qName;
   }

   /**
   	* methodName:调用的方法名
   	* params:调用方法需要的参数
   	* return:返回对象类型
   	*/
   public static <T> T call(String methodName, LinkedHashMap<String, LinkedHashMap<Object, Class>> params, Class<T> clazz) {
   		Service service = new Service();
   		Call call = (Call) service.createCall();
   		SOAPHeaderElement soapHeaderElement = new SOAPHeaderElement(NAMESPACE, methodName);
   		soapHeaderElement.setNamespaceURI(NAMESPACE);
   		call.setTargetEndpointAddress(new URL(ENDPOINT));
   		QName qName = new QName(NAMESPACE, methodName);
   		call.setOperationName(qName);
   		call.setSOAPActionURI(NAMESPACE + methodName);
   		call.setUseSOAPAction(true);
   		call.addHeader(soapHeaderElement);
   		// 需要注册,进行序列化 实体类也要序列化 implements Serializable
   		call.registerTypeMapping(clazz, qName, new BeanSerializerFactory(clazz, qName), new BeanDeserializerFactory(clazz, qName));
   		// 设置输出的类
   		call.setReturnClass(clazz);
   		
   		List<Object> parameterList = Lists.newArrayList();
   		for (Map.Entry<String, LinkedHashMap<Object, Class>> keyEntry : params.entrySet()) {
   			for (Map.Entry<Object, Class> valueEntry : keyEntry.getValue().entrySet()) {
   				call.addParameter(new QName(NAMESPACE, keyEntry.getKey()), getXmlType(valueEntry), ParameterMode.IN);
   				parameterList.add(valueEntry.getKey());
   			}
   		}

   		T result = (T) call.invoke(parameterList.toArray());
   		return result;
   }
}

到这里已经成功的完成客户端掉取服务的工具,可以根据自己项目的需求进行修改。其他未涉及的技术点可自行查阅,如有报错分享或补充技术点可以评论

e.g. 其他方式拓展 AXIS 2.x

1. 引入.jar包

如果引用过EasyExcel或者POI之类的依赖,小心poi-ooxml-schemas —> xmlbeans冲突

		<dependency>
		    <groupId>org.apache.axis2</groupId>
		    <artifactId>axis2-spring</artifactId>
		    <version>1.7.8</version>
		</dependency>
		<dependency>
		    <groupId>org.apache.axis2</groupId>
		    <artifactId>axis2-transport-http</artifactId>
		    <version>1.7.8</version>
		</dependency>
		<dependency>
		    <groupId>org.apache.axis2</groupId>
		    <artifactId>axis2-transport-local</artifactId>
		    <version>1.7.8</version>
		</dependency>
		
		<!-- 版本与EasyExcel中的xmlbeans版本冲突,因此排除 -->
		<dependency>
		    <groupId>org.apache.axis2</groupId>
		    <artifactId>axis2-xmlbeans</artifactId>
		    <version>1.7.8</version>
		    <exclusions>
		        <exclusion>
		            <groupId>org.apache.xmlbeans</groupId>
		            <artifactId>xmlbeans</artifactId>
		        </exclusion>
		    </exclusions>
		</dependency>

2. 使用RPCServiceClient远程调用

	public static String call(String methodName, LinkedHashMap<String, Object> params) {
		RPCServiceClient serviceClient = new RPCServiceClient();
		Options options = serviceClient.getOptions();
		
		EndpointReference endpointReference = new EndpointReference(ENDPOINT);
		options.setTo(endpointReference);
		options.setAction(NAMESPACE + methodName);
		options.setTransportInProtocol(Constants.TRANSPORT_HTTP);
		options.setProperty(HTTPConstants.CHUNKED, "false");
		options.setProperty(Constants.Configuration.HTTP_METHOD, HTTPConstants.HTTP_METHOD_POST);
		
		QName qName = new QName(NAMESPACE, methodName);
		
		List<Object> parameterList = Lists.newArrayList();
		for (String key : params.keySet()) {
		    parameterList.add(params.get(key));
		}
		
		Class[] returnClass = {String.class};
		result = String.valueOf(serviceClient.invokeBlocking(qName, parameterList.toArray(), returnClass)[0]);
	}

3. 使用ServiceClient调用

使用OMElement可以完成文件的字节传输吧,我也没有过多的研究 包装类也没有研究,不如直接注册个序列化器方便。。根据自己的业务需求和代码风格来衡量

	public static void call(String value) {
        ServiceClient client = new ServiceClient();
        Options options = client.getOptions();
        EndpointReference endpointReference = new EndpointReference(ENDPOINT);
        options.setTo(endpointReference);
        options.setAction(NAMESPACE + methodName);

        OMFactory factory = OMAbstractFactory.getOMFactory();
        OMNamespace namespace = factory.createOMNamespace(NAMESPACE, "");
        OMElement method = factory.createOMElement(methodName, namespace);
        // 这里有多少参数,就要创建多少个Element
        OMElement param = factory.createOMElement("parameter", namespace);
        param.addChild(factory.createOMText(param, value));
        method.addChild(param);

        // 增加附件 这个就可以完成文件上传等功能 
        OMElement fileData = factory.createOMElement("imageByte", namespace);  
        java.io.File file = new java.io.File("c:\\test.jpg");  
        FileDataSource fs = new FileDataSource(file);  
        DataHandler fileHandle = new DataHandler(fs);  
        OMText textData = factory.createOMText(fileHandle, true);  
        fileData.addChild(textData);  
        method.addChild(fileData);

		OMElement metaData = factory.createOMElement("length", namespace);  
		metaData.setText(file.length() + "");  
		method.addChild(metaData);  
		
        method.build();

        OMElement result = client.sendReceive(method);
     }

本文没有对技术的源码进行分析,如果感兴趣可以自己翻阅,进行更细致的学习。。在这里,让我们一起渴望新的知识,在探索的路上勇攀高峰!!!!!!!

关注我 ~ 分享更多技术干货

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值