本来今天的程序应该是最简单的,因为涉及到的流程在上周已经学会了,不同的地方只有代码部分了。但是自己还是大意了,现在总结一下。
WebService类中包含byte[]类型参数的方法在wsdl2java生成的stub类中对应的数据类型不再是byte[]类型,而是javax.activation.DataHandler。DataHandler类是专门用来映射WebService二进制类型的。
在WebService类中除了可以使用byte[]作为传输二进制的数据类型外,也可以使用javax.activation.DataHandler作为数据类型。不管是使用byte[],还是使用javax.activation.DataHandler作为WebService方法的数据类型,使用wsdl2java命令生成的stub类中相应方法的类型都是javax.activation.DataHandler。而象使用.net、delphi生成的stub类的相应方法类型都是byte[]。这是由于javax.activation.DataHandler类是Java特有的,对于其他语言和技术来说,并不认识javax.activation.DataHandler类,因此,也只有使用最原始的byte[]了。
看到这段话的时候,我才知道了为什么在复杂数据类型传递中,我会无缘无故的碰到DataHandler。
下面是一个上传二进制文件的例子,WebService类的代码如下:
package binary;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileOutputStream;
import javax.activation.DataHandler;
public class FileService {
// 使用byte[]类型参数上传二进制文件
public boolean uploadWithByte(byte[] file, String filename) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(filename);
fos.write(file);
fos.close();
} catch (Exception e) {
return false;
} finally {
if (fos != null) {
try {
fos.close();
} catch (Exception e) {
}
}
}
return true;
}
private void writeInputStreamToFile(InputStream is, OutputStream os)
throws Exception {
int n = 0;
byte[] buffer = new byte[8192];
while ((n = is.read(buffer)) > 0) {
os.write(buffer, 0, n);
}
}
// 使用DataHandler类型参数上传文件
public boolean uploadWithDataHandler(DataHandler file, String filename) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(filename);
// 可通过DataHandler类的getInputStream方法读取上传数据
writeInputStreamToFile(file.getInputStream(), fos);
fos.close();
} catch (Exception e) {
return false;
} finally {
if (fos != null) {
try {
fos.close();
} catch (Exception e) {
}
}
}
return true;
}
}
上面代码在services.xml文件的配置代码如下:
文件服务
service.FileService
接下来的事情就好办了,跟之前一样,生成.aar文件和stub类。但是正所谓“家贼难防”,我们往往是死在自己熟悉的人手里的,哈哈,开个玩笑。
在这个地方我至少犯了三个错误:
第一:在生成.aar文件的时候,太机械了,直接用上次的模板,连包名都没有改,上次的是service包,但是这次的是binary包,肯定不一样,生成的aar文件放到tomcat下面不报错才怪呢
第二:刚把包名解决掉,可是又把文件的后缀名写错,直接生成了.arr包,放到tomcat下面之后,tomcat直接不鸟他,然后有些人还大言不惭的再百度里搜“tomcat不识别.arr文件”,坑爹啊,百度里居然有相关的内容,这更是延长路了我找出这个错误的时间。哈哈,现在想来真他妈的搞笑。
这两个问题说白了就是下面的这张图
第三:在用wsdl2java命令生成stub类时,没有明白wsdl文件是哪一个,明明自己在service.xml中写明了
就这三个问题一起出现,排列组合太多,搞得我浪费了两个小时,坑死哥了。
如果使用wsdl2java命令生成调用Java客户端代码,则需要创建DataHandler类的对象实例,代码如下:
DataHandler dh = new DataHandler(new FileDataSource(imagePath));
wsdl2java命令会为每一个方法生成一个封装方法参数的类,类名为方法名(第一个字符大写),如uploadWithByte方法生成的类名为UploadWithByte。如果要设置file参数的值,可以使用UploadWithByte类的setFile方法,代码如下:
UploadWithByte uwb = new UPloadWithByte();
uwb.setFile(dh);
最后是调用uploadWithByte方法,代码如下(FileServiceStub为wsdl2java生成的stub类名):
FileServiceStub fss = new FileServiceStub();
fss.uploadWithByte(uwb);
下面是完整的客户端代码
package binary;
import java.rmi.RemoteException;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import binary.FileServiceStub.UploadWithByteResponse;
public class FileStubClient {
public static void main(String[] args) throws RemoteException {
FileServiceStub fss = new FileServiceStub();
FileServiceStub.UploadWithByte uwb = new FileServiceStub.UploadWithByte();
DataHandler dh = new DataHandler(new FileDataSource("f:\\images.jpg"));
uwb.setFile(dh);
uwb.setFilename("byte上传");
fss.uploadWithByte(uwb);
System.out.println("byte上传?"+uwb.isFileSpecified()+" "+"名字有无命名:"+uwb.isFilenameSpecified());
FileServiceStub.UploadWithDataHandler uwdh = new FileServiceStub.UploadWithDataHandler();
uwdh.setFile(dh);
//uwdh.setFilename("DataHandler上传");
fss.uploadWithDataHandler(uwdh);
System.out.println("DataHandler上传?"+uwdh.isFileSpecified()+" "+"名字有无命名:"+uwdh.isFilenameSpecified());
}
}
运行结果:
与上次的复杂数据类型传递相比,这次的简单多了,不需要byte和DataHandler之间的人工转换,stub类会自动转换。