Webservice传送文件的实现(AXIS2 MTOM)

工作环境:IDE: Eclipse 3.1.2
                    jdk: jdk1.5.0_06
                    Tomcat: apache-tomcat-5.5.15
                    AXIS2:1.0(war版本和bin版本)
 
环境准备:
http://ws.apache.org/axis2/download/1_0/download.cgi去下载AXIS2的 Binary Distribution url: http://apache.justdn.org/ws/axis2/1_0/axis2-std-1.0-bin.zip war
Distribution url: http://apache.justdn.org/ws/axis2/1_0/axis2-1.0-docs.zip 。把这两个文件解压,比如解压缩的后得目录为 C:/axis2-std-1.0-bin C:/axis2.war. Eclipse 下通过菜单 window—preferences…--Java—Build Path—User Libraries 新建一个 user library, 比如名字就叫 axis2 C:/axis2-std-1.0-bin/lib 下的所有 jar 文件包含进来。把 axis2.war 拷贝到 %TOMCAT-HOME%/webapps 下面。
 
                  
实现
   Eclipse 新建一个工程,装了 Eclipse tomcat plugin 的就新建一个 tomcat project 好了, build path 包含上面创建的 user library:axis2. 我的例子的场景是一个语音信箱系统的用户上传下载问候语文件( greeting) 的,每个语音信箱系统的用户拥有一个唯一的 mailbox number, 问候语有不同的类型,比如忙的时候问候语,出差时候问候语,不同时段的问候语,问候语文件支持的类型有 wav,mp3 等等。
 
所以我的 webservice 要实现的 2 个功能就是 upload, download.
 
AXIS2 webservice 发布的时候是打包成 xxx.aar 发布的, xxx.aar 展开后的目录结构为
 --
    --META-INF
       services.xml
    -- 包含 server 端实现的 class(  目录跟 package 是一样的结构 )
           
 
新建 2 个类: FileTransferClient.java, interopService.java. 两个类内容如下:
 
 
FileTransferClient( 调用 webservice 的客户端代码 )
 
package sample.mtom.interop.client;
 
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.axiom.om.OMText;
import org.apache.axiom.soap.SOAP11Constants;
import org.apache.axiom.soap.SOAP12Constants;
import org.apache.axis2.Constants;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
 
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.xml.namespace.QName;
import java.io.File;
import java.io.InputStream;
 
public class FileTransferClient {
   private static EndpointReference targetEPR = new EndpointReference("http://127.0.0.1:8080/axis2/services/interop");
  
   public static boolean upload(String mailboxnum, short greetingType, File file, String fileType) {
     try {
      OMElement data = buildUploadEnvelope(mailboxnum, greetingType, file, fileType);
      Options options = buildOptions();
      ServiceClient sender = new ServiceClient();
      sender.setOptions(options);
      System.out.println(data);
      OMElement ome = sender.sendReceive(data);
      System.out.println(ome);
      String b = ome.getText();
      return Boolean.parseBoolean(b);
     }
     catch(Exception e) {
      
     }
     return false;
   }
   public static InputStream download(String mailboxnum, short greetingType, String FileType) {
     try {
       OMElement data = buildDownloadEnvelope(mailboxnum, greetingType, FileType);
       Options options = buildOptions();
       ServiceClient sender = new ServiceClient();
       sender.setOptions(options);
       System.out.println(data);
       OMElement ome = sender.sendReceive(data);
       System.out.println(ome);
       OMText binaryNode = (OMText) ome.getFirstOMChild();
       DataHandler actualDH = (DataHandler) binaryNode.getDataHandler();
       return actualDH.getInputStream();
      }
      catch(Exception e) {
       
      }
     return null;
   }
  
   private static OMElement buildUploadEnvelope(String mailboxnum, short greetingType, File file, String FileType) {
     DataHandler expectedDH;
     OMFactory fac = OMAbstractFactory.getOMFactory();
     OMNamespace omNs = fac.createOMNamespace("http://example.org/mtom/data", "x");
     OMElement data = fac.createOMElement("upload", omNs);
     OMElement fileContent = fac.createOMElement("fileContent", omNs);
     FileDataSource dataSource = new FileDataSource(file);
     expectedDH = new DataHandler(dataSource);
     OMText textData = fac.createOMText(expectedDH, true);
     fileContent.addChild(textData);
     OMElement mboxnum = fac.createOMElement("mailboxnum", omNs);
     mboxnum.setText(mailboxnum);
     OMElement gtType = fac.createOMElement("greetingType", omNs);
     gtType.setText(greetingType+"");
     OMElement fileType=fac.createOMElement("fileType", omNs);
     fileType.setText(FileType);
  
     data.addChild(mboxnum);
     data.addChild(gtType);
     data.addChild(fileType);
     data.addChild(fileContent);
     return data;
   }
   private static OMElement buildDownloadEnvelope(String mailboxnum, short greetingType, String FileType) {
     OMFactory fac = OMAbstractFactory.getOMFactory();
     OMNamespace omNs = fac.createOMNamespace("http://example.org/mtom/data", "x");
     OMElement data = fac.createOMElement("download", omNs);
     OMElement mboxnum = fac.createOMElement("mailboxnum", omNs);
     mboxnum.setText(mailboxnum);
     OMElement gtType = fac.createOMElement("greetingType", omNs);
     gtType.setText(greetingType+"");
     OMElement fileType=fac.createOMElement("fileType", omNs);
     fileType.setText(FileType);
     data.addChild(mboxnum);
     data.addChild(gtType);
     data.addChild(fileType);
     return data;
   }
   private static Options buildOptions() {
     Options options = new Options();
     options.setSoapVersionURI(SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI);
     options.setTo(targetEPR);
     // enabling MTOM in the client side
     options.setProperty(Constants.Configuration.ENABLE_MTOM, Constants.VALUE_TRUE);
     options.setTransportInProtocol(Constants.TRANSPORT_HTTP);
     return options;
   }
   public static void main(String agrs[]) {
     String file = "C:/deploy.wsdd";
     short gt = 1;
     String mn = "20060405";
     String ft="wsdd";
     boolean rtv = upload(mn,gt,new File(file),ft);
     System.out.println(rtv);
     InputStream is = download(mn,gt,ft);
   }
}
 
interopService(webservice server 端实现代码 )
 
package sample.mtom.interop.service;
 
import org.apache.axiom.attachments.utils.IOUtils;
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.axiom.om.OMText;
import org.apache.axis2.AxisFault;
import java.io.FileOutputStream;
import java.io.*;
import java.util.Iterator;
 
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
 
public class interopService {
 public static final String TMP_PATH = "c:/tmp";
 public OMElement upload(OMElement element) throws Exception {
    OMElement _fileContent = null;
    OMElement _mailboxnum = null;
    OMElement _greetingType = null;
    OMElement _fileType = null;
    System.out.println(element);
    for (Iterator _iterator = element.getChildElements(); _iterator.hasNext();) {
      OMElement _ele = (OMElement) _iterator.next();
      if (_ele.getLocalName().equalsIgnoreCase("fileContent")) {
        _fileContent = _ele;
      }
      if (_ele.getLocalName().equalsIgnoreCase("mailboxnum")) {
        _mailboxnum = _ele;
      }
      if (_ele.getLocalName().equalsIgnoreCase("greetingType")) {
        _greetingType = _ele;
      }
      if (_ele.getLocalName().equalsIgnoreCase("fileType")) {
        _fileType = _ele;
      }
    }
 
    if (_fileContent == null || _mailboxnum == null || _greetingType== null || _fileType==null) {
      throw new AxisFault("Either Image or FileName is null");
    }
 
    OMText binaryNode = (OMText) _fileContent.getFirstOMChild();
 
    String mboxNum = _mailboxnum.getText();
    String greetingType = _greetingType.getText();
    String fileType = _fileType.getText();
 
    String greetingstoreDir = TMP_PATH+"/"+mboxNum;
    File dir = new File(greetingstoreDir);
    if(!dir.exists()) {
      dir.mkdir();
    }
    String filePath = greetingstoreDir+"/"+greetingType+"."+fileType;
    File greetingFile = new File(filePath);
    if(greetingFile.exists()) {
      greetingFile.delete();
      greetingFile = new File(filePath);
    }
   
    // Extracting the data and saving
    DataHandler actualDH;
    actualDH = (DataHandler) binaryNode.getDataHandler();
    
    FileOutputStream imageOutStream = new FileOutputStream(greetingFile);
    InputStream is = actualDH.getInputStream();
    imageOutStream.write(IOUtils.getStreamAsByteArray(is));
    // setting response
    OMFactory fac = OMAbstractFactory.getOMFactory();
    OMNamespace ns = fac.createOMNamespace("http://example.org/mtom/data", "x");
    OMElement ele = fac.createOMElement("response", ns);
    ele.setText("true");
   
    return ele;
 }
 
 public OMElement download(OMElement element) throws Exception {
    System.out.println(element);
    OMElement _mailboxnum = null;
    OMElement _greetingType = null;
    OMElement _fileType = null;
    for (Iterator _iterator = element.getChildElements(); _iterator.hasNext();) {
      OMElement _ele = (OMElement) _iterator.next();
      if (_ele.getLocalName().equalsIgnoreCase("mailboxnum")) {
        _mailboxnum = _ele;
      }
      if (_ele.getLocalName().equalsIgnoreCase("greetingType")) {
        _greetingType = _ele;
      }
      if (_ele.getLocalName().equalsIgnoreCase("fileType")) {
        _fileType = _ele;
      }
    }
    String mboxNum = _mailboxnum.getText();
    String greetingType = _greetingType.getText();
    String fileType = _fileType.getText();
    String filePath = TMP_PATH+"/"+mboxNum+"/"+greetingType+"."+fileType;
    FileDataSource dataSource = new FileDataSource(filePath);
    DataHandler expectedDH = new DataHandler(dataSource);
   
    OMFactory fac = OMAbstractFactory.getOMFactory();
   
    OMNamespace ns = fac.createOMNamespace("http://example.org/mtom/data", "x");
    OMText textData = fac.createOMText(expectedDH, true);
    OMElement ele = fac.createOMElement("response", ns);
    ele.addChild(textData);
    return ele;
 }
 
}
 
 
新建一个 services.xml, 内容如下 :
 
name= "MTOMService" >
   
        This is a sample Web Service with two operations,echo and ping.
   
    name= "ServiceClass" locked= "false" > sample.mtom.interop.service.interopService
    name= "upload" >
        urn:upload
        class= "org.apache.axis2.receivers.RawXMLINOutMessageReceiver" />
   
      name= "download" >
        urn:download
        class= "org.apache.axis2.receivers.RawXMLINOutMessageReceiver" />
   
 
 
打包
 
  新建一个目录叫 build, 拷贝相应的文件到 build 下面, build 的目录展开如图所示:
 
  
 Webservice传送文件的实现(AXIS2 MTOM)_第1张图片
 
 
 
就像这样的
     --build
        --interop
           --META-INF
              --services.xml
           --sample
              --mtom
                 --interop
                   --service
                       -- interopService.class
 
 
 
windows 环境下 , console 下,更换目录到 build/interop :
 
输入一下命令:
jar –cf interop.aar . , 注意最后一个点代表当前目录。
 
 
  发布
   AXIS2 webservice 的发布是这样的,首先你要先把 AXIS2 war distribution 发到到一个 servlet 容器中,我这里用的是 Tomcat. 发布的方法前面提到了: axis2.war 拷贝到 %TOMCAT-HOME%/webapps
 
启动 tomcat, 然后输入: http://localhost:8080/axis2/axis2-admin/ 输入用户名 admin 密码 axis2 就进入了 axis2    Web Admin Module, 然后在页面左边的菜单的 Tools 下选择 Upload Service, 然后选择前面打好的 interop.aar
upload.
 
还有种手动发布的方式 , 你发布 axis2.war tomcat 的时候, tomcat 会自动展开生成一个 axis2 的目录在
%TOMCAT-HOME%/webapps 下面,进入到目录 %TOMCAT-HOME%/webapps/axis2/WEB-INF/services ,把前面打好包的 interop.aar 拷贝到这里 .
 
 
测试
 
     eclipse 里运行 FileTransferClient
 
 
 
代码分析
 
  利用 Axis2 Mtom 发送附件跟 Sun SAAJ 差不多。用过 javamail 的朋友也会觉得代码似曾相识,应为都应用了 builder 模式。要向一个 webserive 发送请求,首先就要构建一个请求的 Envelope,Axis2 构建 Envelope 的时候是利用的 Axis2 AXIOM api( 就是 axis2 java object xml 的映射处理机制 ), 其编程模式和 DOM 差不多的 . 看这一段 :
 
private static OMElement buildUploadEnvelope(String mailboxnum, short greetingType, File file, String FileType) {
     DataHandler expectedDH;
     OMFactory fac = OMAbstractFactory.getOMFactory();
     OMNamespace omNs = fac.createOMNamespace("http://example.org/mtom/data", "x");
     OMElement data = fac.createOMElement("upload", omNs);
     OMElement fileContent = fac.createOMElement("fileContent", omNs);
     FileDataSource dataSource = new FileDataSource(file);
     expectedDH = new DataHandler(dataSource);
     OMText textData = fac.createOMText(expectedDH, true);
     fileContent.addChild(textData);
     OMElement mboxnum = fac.createOMElement("mailboxnum", omNs);
     mboxnum.setText(mailboxnum);
     OMElement gtType = fac.createOMElement("greetingType", omNs);
     gtType.setText(greetingType+"");
     OMElement fileType=fac.createOMElement("fileType", omNs);
     fileType.setText(FileType);
  
     data.addChild(mboxnum);
     data.addChild(gtType);
     data.addChild(fileType);
     data.addChild(fileContent);
     return data;
   }
这一段其实是构建的 data 对像是这样一段 xml java object 代表:
     xmlns:x= "http://example.org/mtom/data" >
            20060405
            1
            wsdd
           
Dwvc2VydmljZT4NCjwvZGVwbG95bWVudD4NCg0K
           
    
 
其中的 Dwvc2VydmljZT4NCjwvZGVwbG95bWVudD4NCg0K 是要传送的文件的内容代表,至于什么编码,我没有深究。注意这一句 :
     OMElement data = fac.createOMElement("upload", omNs);
这里的“ upload 参数对应的是 webservice 的一个操作的名称,这个操作的名称是跟 webservice server 端实现类的方法名和 services.xml 的所定义的
] name= "upload" >
        urn:upload
   class= "org.apache.axis2.receivers.RawXMLINOutMessageReceiver" />
要一致的。
 
我们再看看这一段,
 
   private static Options buildOptions() {
     Options options = new Options();
     options.setSoapVersionURI(SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI);
     options.setTo(targetEPR);
     // enabling MTOM in the client side
     options.setProperty(Constants.Configuration.ENABLE_MTOM, Constants.VALUE_TRUE);
     options.setTransportInProtocol(Constants.TRANSPORT_HTTP);
     return options;
   }
 
这里构建的 Options 对象,顾名思义就是调用 webservice 的相应的选项:
比如这里就指定了 Soap 协议为 1.1
指定了所请求的 service EPR( 就是地址 )
  声明在 client 应用 MTOM
指定传输协议为 HTTP
 
构建好要传送的 data options , 所执行的代码为:
      ServiceClient sender = new ServiceClient();
      // 设定选项
      sender.setOptions(options);
      // 打印要传送的数据,为一段 xml
      System.out.println(data);
      // 传送数据,得到返回值
      OMElement ome = sender.sendReceive(data);
      // 打印返回值,为一段 xml
      System.out.println(ome);
      // 析取返回值中的数据
      String b = ome.getText();
      // 返回
      return Boolean.parseBoolean(b);
 
 
  大家可以发现, server 端和 client 的中间传递数据都是通过
 
      org.apache.axiom.om.OMElement 对象的,这个对象是一段 xml java 对象映射 .
 
 
疑惑 :
            貌似是 Axis2 bug, 我在 method buildUploadEnvelope 最后是这样写的,
               
                data.addChild(mboxnum);
                data.addChild(gtType);
                data.addChild(fileType);
                data.addChild(fileContent);
                return data;
 
                data.addChild(fileContent);  对应的是
                xmlns:x= "http://example.org/mtom/data" >
            20060405
            1
            wsdd
           
Dwvc2VydmljZT4NCjwvZGVwbG95bWVudD4NCg0K
           
     中红色的部分。
 
     这样没有问题, service 端接受到的 message 的数据跟 client 一致的。
 
     但是如果我这样写 , 就是把要传送的文件内容提前加入
       data.addChild(fileContent);
      data.addChild(mboxnum);
                data.addChild(gtType);
                data.addChild(fileType);
                return data;
 
               Client 端的数据是这样的:
 
      xmlns:x= "http://example.org/mtom/data" >
           
Dwvc2VydmljZT4NCjwvZGVwbG95bWVudD4NCg0K
           
            20060405
            1
            wsdd
           
    
     但是 server 接收到的数据成了
      xmlns:x= "http://example.org/mtom/data" >
           
Dwvc2VydmljZT4NCjwvZGVwbG95bWVudD4NCg0K
           
    
     后面的 3 条数据都没了!!!!!
 
 
参考文献:
     Axis2 user guide
     Axis2 sample(Axis2 binary distribution 自带 )
 
 
友情提醒:
 
      如果大家要用Axis2开发webservice,强烈建议你先看IBMdeveloperWorks
中国
上的一个教程-- Apache Geronimo Axis2 实现在线银行,第 1 部分: 服务:布设框架
URL https://www6.software.ibm.com/developerworks/cn/education/opensource/os-ag-onbank1/index.html ,看这个教程需要注册 developerWorks中国 的账号,免费注册的。
 
这个教程的第 2 ,第 3 部分的 url :
http://www.ibm.com/developerworks/edu/os-dw-os-ag-onbank2.html
http://www.ibm.com/developerworks/edu/os-dw-os-ag-onbank3.html
 
 我从这个教程受益匪浅,相信你也一定会有收获的。
 
Contact:
 
QQ:15520929

你可能感兴趣的:(Webservice传送文件的实现(AXIS2 MTOM))