加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

axis2实现WebService之复合类型数据的传递

发布时间:2020-12-17 00:33:30 所属栏目:安全 来源:网络整理
导读:?????? 接着昨天的程序,今天又进了一步,学习了webservice的复合类型数据的传递,尤其是教程上没有的部分,我自己尝试着写,虽说耗费了一个下午的时间,但是还是非常值的,废话少说,看招! ????? 在实际的应用中,不仅需要使用 WebService 来传递简单类型

?????? 接着昨天的程序,今天又进了一步,学习了webservice的复合类型数据的传递,尤其是教程上没有的部分,我自己尝试着写,虽说耗费了一个下午的时间,但是还是非常值的,废话少说,看招!

????? 在实际的应用中,不仅需要使用WebService来传递简单类型的数据,有时也需要传递更复杂的数据,这些数据可以被称为复合类型的数据。数组与类(接口)是比较常用的复合类型。在Axis2中可以直接使用将WebService方法的参数或返回值类型声明成数组或类(接口)。但要注意,在定义数组类型时只能使用一维数组,如果想传递多维数组,可以使用分隔符进行分隔,如下面的代码所示:

String[] strArray = new String[]{ "自行车,飞机,火箭","中国,美国,德国","超人,蜘蛛侠,钢铁侠" } ;

????上面的代码可以看作是一个3*3的二维数组。

????在传递类的对象实例时,除了直接将数组类型声明成相应的类或接口,也可以将对象实例进行序列化,也就是说,将一个对象实例转换成字节数组进行传递,然后接收方再进行反序列化,还原这个对象实例。

????下面的示例代码演示了如何传递数组与类(接口)类型的数据,并演示如何使用字节数组上传图像。本示例的客户端代码使用Java编写。要完成这个例子需要如下几步:

??

一、实现服务端代码

import java.io.FileOutputStream;
import data.DataForm;

public class ComplexTypeService
{
    //  上传图像,imageByte参数表示上传图像文件的字节,
    //  length参数表示图像文件的字节长度(该参数值可能小于imageByte的数组长度)
    public boolean uploadImageWithByte(byte[] imageByte,int length)
    {
        FileOutputStream fos = null;
        try
        {
            //  将上传的图像保存在D盘的test1.jpg文件中
            fos = new FileOutputStream("d:test1.jpg");
            //  开始写入图像文件的字节
            fos.write(imageByte,length);
            fos.close();
        }
        catch (Exception e)
        {
            return false;
        }
        finally
        {
            if (fos != null)
            {
                try
                {
                    fos.close();
                }
                catch (Exception e)
                {

                }
            }
        }
        return true;
    }
    //  返回一维字符串数组
    public String[] getArray()
    {
        String[] strArray = new String[]{ "自行车","飞机","火箭" };
        return strArray;
    } 
    //  返回二维字符串数组
    public String[] getMDArray()
    {
        String[] strArray = new String[]{ "自行车,飞机,火箭","中国,美国,德国","超人,蜘蛛侠,钢铁侠" } ;
        return strArray;
    }
    //  返回DataForm类的对象实例
    public DataForm getDataForm()
    {
        return new DataForm();
    }
    //  将DataForm类的对象实例序列化,并返回序列化后的字节数组
    public byte[] getDataFormBytes() throws Exception 
    {
        java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
        java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(baos);
        oos.writeObject(new DataForm());        
        return baos.toByteArray();
    }    
}

二、实现DataForm

package data;

public class DataForm implements java.io.Serializable
{
    private String name = "bill";
    private int age = 20;
    setter…………getter方法
}

三、发布WebService

????由于本示例的WebService类使用了一个Java类(DataForm类),因此,在发布WebService之前,需要先将DataForm.class文件复制到<Tomcat安装目录>webappsaxis2WEB-INFclassesdata目录中,然后将ComplexTypeService.class文件复制到<Tomcat安装目录>webappsaxis2WEB-INFpojo目录中,最后启动Tomcat(如果Tomcat已经启动,由于增加了一个DataForm类,因此,需要重新启动Tomcat)。发布之后的结果如下图所示

?

?

?四、使用Java编写调用WebService的客户端代码??? 在客户端仍然使用了RPC的调用方式,代码如下:

package client;

import javax.xml.namespace.QName;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.rpc.client.RPCServiceClient;

public class ComplexTypeRPCClient {

	public static void main(String[] args) throws Exception {
		RPCServiceClient serviceClient = new RPCServiceClient();
		Options options = serviceClient.getOptions();
		EndpointReference targetEPR = new EndpointReference(
				"http://localhost:8080/axis2/services/ComplexTypeService");
		options.setTo(targetEPR);
		// 下面的代码调用uploadImageWithByte方法上传图像文件
		// 打开图像文件,确定图像文件的大小
		java.io.File file = new java.io.File("f:images.jpg");
		java.io.FileInputStream fis = new java.io.FileInputStream(
				"f:images.jpg");
		// 创建保存要上传的图像文件内容的字节数组
		byte[] buffer = new byte[(int) file.length()];
		// 将图像文件的内容读取buffer数组中
		int n = fis.read(buffer);
		System.out.println("文件长度:" + file.length());
		Object[] opAddEntryArgs = new Object[] { buffer,n };
		Class[] classes = new Class[] { Boolean.class };
		QName opAddEntry = new QName("http://ws.apache.org/axis2","uploadImageWithByte");
		fis.close();
		// 开始上传图像文件,并输出uploadImageWithByte方法的返回传
		System.out.println(serviceClient.invokeBlocking(opAddEntry,opAddEntryArgs,classes)[0]);

		// 下面的代码调用了getArray方法,并返回一维String数组
		opAddEntry = new QName("http://ws.apache.org/axis2","getArray");
		String[] strArray = (String[]) serviceClient.invokeBlocking(opAddEntry,new Object[] {},new Class[] { String[].class })[0];
		for (String s : strArray)
			System.out.print(s + "  ");
		System.out.println();

		// 下面的代码调用了getMDArray方法,并返回一维String数组
		opAddEntry = new QName("http://ws.apache.org/axis2","getMDArray");
		strArray = (String[]) serviceClient.invokeBlocking(opAddEntry,new Class[] { String[].class })[0];
		for (String s : strArray) {
			String[] array = s.split(",");
			for (String ss : array)
				System.out.print("<" + ss + "> ");
			System.out.println();
		}
		System.out.println();


		// 下面的代码调用了getDataForm方法,并返回DataForm对象实例
		opAddEntry = new QName("http://ws.apache.org/axis2","getDataForm");
		data.DataForm df = (data.DataForm) serviceClient.invokeBlocking(
				opAddEntry,new Class[] { data.DataForm.class })[0];
		System.out.println(df.getAge());


		// 下面的代码调用了getDataFormBytes方法,并返回字节数组,最后将返回的字节数组反序列化后,转换成DataForm对象实例
		opAddEntry = new QName("http://ws.apache.org/axis2","getDataFormBytes");
		buffer = (byte[]) serviceClient.invokeBlocking(opAddEntry,new Class[] { byte[].class })[0];
		java.io.ObjectInputStream ois = new java.io.ObjectInputStream(
				new java.io.ByteArrayInputStream(buffer));
		df = (data.DataForm) ois.readObject();
		System.out.println(df.getName());
	}
}


?

运行上面的程序,将输出如下的内容:

文件长度:3617

true

自行车?飞机?火箭
?

<
自行车>?<飞机>?<火箭
>

<
中国>?<美国>?<德国
>

<
超人>?<蜘蛛侠>?<钢铁侠
>

20

?

如果读者要上传大文件,应尽量使用FTP的方式来传递,而只通过WebService方法来传递文件名等信息。这样有助于提高传输效率。

?

????? 以上的就是教程上的,照猫画虎,没什么技术含量,几分钟搞定,唯一需要的就是对java的io包,及java的输入输出要熟悉,不然就比较麻烦了。虽说自己懂了,但是看着客户端代码,我不禁问自己,调用webservice难道就这么复杂吗,有着现成的wsdl2java.bat我们为什么不用呢,难道教程上没有的我们就不学了吗?教程上的就一定是最好的吗?带着这些问题我开始了探索之旅,废话少说,看招!

????? 生成stub类的方法我就不多讲了,不懂得朋友可以去看我的上一篇文章点击打开链接,引入生成的stub类,这个类是通过wsdl文件转化而来的,它把发布到webservice的方法封装成了类,把方法的参数封装成了方法(就像javabean一样的set方法一样),但是用当前类的对象去访问这个stub类的时候又是我们平常所熟悉的那样,没变,估计这么说也不明白,直接上代码。

?

package client;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.rmi.RemoteException;

import javax.activation.DataHandler;
import javax.activation.DataSource;

import data.DataForm;

public class ComplexStubClient {
	public static void main(String[] args) throws Exception  
    {
        ComplexTypeServiceStub stub = new ComplexTypeServiceStub();
        ComplexTypeServiceStub.GetArray ga = new ComplexTypeServiceStub.GetArray();
        ComplexTypeServiceStub.GetDataForm gdf = new ComplexTypeServiceStub.GetDataForm();
        ComplexTypeServiceStub.GetDataFormBytes gdfb = new ComplexTypeServiceStub.GetDataFormBytes();
        ComplexTypeServiceStub.GetMDArray gmda = new ComplexTypeServiceStub.GetMDArray();
        ComplexTypeServiceStub.UploadImageWithByte uiwb = new ComplexTypeServiceStub.UploadImageWithByte();
        
		upload(stub,uiwb);
		arrayOD(stub,ga);
		arrayMD(stub,gmda);
		dataForm(stub,gdf);
		dataFormByte(stub,gdfb);
    }

	public static void dataFormByte(ComplexTypeServiceStub stub,ComplexTypeServiceStub.GetDataFormBytes gdfb)
			throws RemoteException,ComplexTypeServiceExceptionException,IOException,ClassNotFoundException {
		DataHandler dh = stub.getDataFormBytes(gdfb).get_return();
		//System.out.println(dh.getContent().getClass());
		DataSource ds = dh.getDataSource();
		java.io.ObjectInputStream ois = new java.io.ObjectInputStream(ds.getInputStream());
		DataForm df = (data.DataForm) ois.readObject();
		System.out.println(df.getName());
	}

	public static void dataForm(ComplexTypeServiceStub stub,ComplexTypeServiceStub.GetDataForm gdf) throws RemoteException {
		client.ComplexTypeServiceStub.DataForm df = stub.getDataForm(gdf).get_return();//对象实例
		System.out.println(df.getAge()+"  "+df.getName());//变量
	}

	public static void arrayMD(ComplexTypeServiceStub stub,ComplexTypeServiceStub.GetMDArray gmda) throws RemoteException {
		String[] strArry = stub.getMDArray(gmda).get_return();
		for(String s:strArry){
			String[] str = s.split(",");
			for(String s2:str){
				System.out.print(s2+" ");
			}
			System.out.print("   ");
		}
		System.out.println();
	}

	public static void arrayOD(ComplexTypeServiceStub stub,ComplexTypeServiceStub.GetArray ga) throws RemoteException {
		String[] strArry = stub.getArray(ga).get_return();
		for(String s:strArry){
			System.out.print(s+" ");
		}
		System.out.println();
	}

	public static void upload(ComplexTypeServiceStub stub,ComplexTypeServiceStub.UploadImageWithByte uiwb)
			throws FileNotFoundException,RemoteException {
		File file = new File("f:images.jpg");
		FileInputStream fis = new FileInputStream("f:images.jpg");
		// 创建保存要上传的图像文件内容的字节数组
		final byte[] buffer = new byte[(int) file.length()];
		int n = fis.read(buffer);
		System.out.println("文件长度:" + file.length());
		uiwb.setLength(n);
        uiwb.setImageByte(new DataHandler(new DataSource() {  
            public InputStream getInputStream() {  
                return new ByteArrayInputStream(buffer);  
            }  
            public OutputStream getOutputStream() {  
                return null;  
            }  
            public String getContentType() {  
                return "";  
            }  
            public String getName() {  
                return "";  
            }  
        }));  
        System.out.println(stub.uploadImageWithByte(uiwb).get_return());
	} 
	
}


??????? 在这个方法里应该着重强调的是upload(stub,uiwb);和?dataFormByte(stub,gdfb);

?????? upload(stub,uiwb);中setImageByte()方法中的参数在服务器端是字节数组类型的,但是到了stub类中奇迹般的变成了DataHandler类型,而这个类型是jdk1.6才有的,如下式API文档的介绍

DataHandler 类为在多种不同源和格式下可用的数据提供一致的接口。它使用 DataContentHandler 管理简单流到字符串的转换以及相关操作。它提供对能够操作数据的命令的访问。使用 CommandMap 可以找到这些命令。

有兴趣的可以自己去查一下,为了把字节数组转换成这种类型,我花了九牛二虎之力才达到,居然是要通过两层转化,还是内部类,哎,坑爹啊。如下图所示


??????? 最坑爹的还不是这个,到了dataFormByte(stub,gdfb);方法中又需要把DataHandler类型转化成字节数组类型,你说这不是耍我吗,就是这一耍,搞了我两个小时,不过从结果来看被耍的还是值的,哈哈,人怎么就这么贱呢。

                  DataHandler dh = stub.getDataFormBytes(gdfb).get_return();//我唯一写对的就是这一句,之后的就是全错
		DataSource ds = dh.getDataSource();//
		java.io.ObjectInputStream ois = new java.io.ObjectInputStream(ds.getInputStream());
		DataForm df = (data.DataForm) ois.readObject();
		System.out.println(df.getName());

?????? 自己转化了一个多小时,没转换出来,还是报类型转换出错。实在是有点恶心了,就问了公司里一牛人(我是实习生哈),我把我的程序的来龙去脉讲了一遍,人间设断点调试了一下,查了一下API文档,写了几条转化一句,靠,立马好了,悲剧啊,这就是人与人的差别,哥搞了两小时都没出来,人家两分钟就好了,唉,木有办法!

如下就是大牛的调试过程

????????? 上图的内容我看了好几遍,居然都没发现要生成DataHandler实例需要DataSource的实例,于是大牛写了一句话DataSource ds = dh.getDataSource();

?????? 得到了对象的数据源,要想打印出对象来,就必须得到它的输入流,而因为自己是对象,所以就不是普通的输入流了而是对象输入流,但是怎样把DataSource里的数据转换成对象数据流呢,大牛估计好久没写底层的代码了,有点忘了,他差了一下API文档,如下

大牛看到这,又写了两句:

                  java.io.ObjectInputStream ois = new java.io.ObjectInputStream(ds.getInputStream());
		DataForm df = (data.DataForm) ois.readObject();

短短的三句话,就OK了,如下是输出截图


??

????? 看来自己要成为大牛,还有很长的路要走哈,不过今天也值了。

????? 以后编程的时候有两点用来警醒自己吧

????? 第一:常用断点,尤其要看变量的变化,空值与否

??? ? 第二:常查API文档

????? 第三:多请教大牛

总之,今天就是这样过来的,快下班了,明天继续!加油!

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读