传输小体积文件(不超过10M)通常采用byte[]来容纳数据内容。开发过程中,通常是以下面给出的代码形式来定义数据类型:

 

public byte[] download(String fileName);
public void upload(String fileName, byte[] content);

 

数据内容即以byte[]的方式来容纳。毕竟字节数组的长度是有限的,大体积的数据流显然不适合用如此方式操作。webservice规范中指出:二进制内容在网络传输过程中还能以soap附件的形式收发。

 

 

本文将要涉及到的内容是:

 


    通过Webservice上载或下载大体积的文件(至少是500M以上)。

    采用annotation的注解方式开启webservice的消息传输优化。

    使用DataHandler操作输入输出流。

 

知识点



Webservice 通过“附件”的形式可把多个二进制内容粘贴到消息的附件部位上。因此在编程的过程中既可以直接操纵webservice的原始消息内容(使用soap的消 息操作API)进行“附件”的读写也能使用客户端存根代码的java代理类进行操作。Web service规范中的一项: MTOM (Message Transmission and Optimization Mechanism)即是进行此项操作的用场。


 

数据内容和JAVA的数据类型


下表列举了在http传输过程中媒体内容的类型和JAVA编程对象的对应关系

MIME Type

Java Type

image/gif

java.awt.Image

image/jpeg

java.awt.Image

text/plain

java.lang.String

text/xml or application/xml

javax.xml.transform.Source

*/*

javax.activation.DataHandler

 


以图片的内容来解释下传输类型的转换过程:

java.awt.Image类型的对象在传输前按照image/gif;image/jpeg的编码规则(HTTP上媒体字节内容的编码规则)进行编码,而后写到soap消息中;从soap消息里还原出媒体内容的时候即还原成java.awt.Image的对象实例。

 

*/*这种类型就是“通吃”了,完全依靠DataHandler的实现提供输入输出流来操作媒体内容。这种类型就是本文要采用的。

 

代码讲解

先来看上载文件的服务端。webservice的实现类用annotation标注以开启MTOM方式

@javax.xml.ws.soap.MTOM
public class MTOMServer {
...
}

上载的功能

public void upload(
        @WebParam(name="fileName")String fileName,
 
         @XmlMimeType("*/*")
        @WebParam(name="fileDataHandler")
        DataHandler dataHandler)throws IOException

用DataHandler充当上载的数据操作的“手柄”,并且明确地使用  @XmlMimeType("*/*")标注以表示采用数据流的方式把媒体内容写到SOAP消息的附件部位。(如果不明确地进行标记,那么客户端存根代码上就不会出现DataHandler,而是byte[])。

 

下载的功能

@WebResult
@XmlMimeType("*/*") 
public DataHandler download(
        @WebParam(name="fileName")String fileName
)throws FileNotFoundException{

同样显示地标注*/*表示客户端将得到DataHandler(如果不明确地进行标记,那么客户端存根代码上就不会出现DataHandler,而是byte[])

 


 

客户端也能开启MTOM。开启的方式可以在获取服务的时候指出:

public MTOMServerService getMTOMServer(WebServiceFeature... features)

实参用MTOMFeature的实例。

 

客户端调用上载方法前还需为请求的上下文环境指定“流操作的块的大小”

Map<String, Object> ctxt = ((BindingProvider)mtomPort).getRequestContext();
ctxt.put(JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, 2048);

 

以下贴出服务端代码



package mtom;
import javax.jws.*;
import javax.xml.bind.annotation.*;
import javax.xml.ws.*;
import javax.activation.*;
import javax.annotation.*;
import java.io.*;
import java.util.*;
/**
 * @author Hardneedl
 */
@javax.xml.ws.soap.MTOM
@WebService(name="MTOMServerService",portName="MTOMServer")
public class MTOMServer {
    private static final int BUFFER_SIZE = 1024*1024*20;
    @Resource
    private WebServiceContext serviceContext;
    /**
     * 下载文件
     * @return 数据句柄
     */
    @WebResult
    @XmlMimeType("*/*")
    public DataHandler download(
        @WebParam(name="fileName")String fileName)throws FileNotFoundException{
        if (fileName==null||fileName.isEmpty())
            throw new FileNotFoundException("file name is empty");

        File dir = getFileDepository();
        File downloadFile = new File(dir.getAbsolutePath()+File.separatorChar+fileName);
        if (!downloadFile.exists())
            throw new FileNotFoundException(fileName + " does not exist");

        return new DataHandler(
            new FileDataSource(downloadFile){
                public String getContentType() {
                    return "application/octet-stream";
                }
            }
        );
    }

    @WebResult
    @XmlMimeType("*/*")
    public DataHandler[] downloadMulti()throws FileNotFoundException{
        final File[] files = getFileDepository().listFiles();
        DataHandler[] handlers = new DataHandler[files.length];

        for (int i = 0,j=files.length; i < j; i++){
            final String fileName = files[i].getName();
            handlers[i]=
                new DataHandler(new FileDataSource(files[i])){
                    public String getName() {return fileName;}
                };
        }
        return handlers;
    }


    /**
     * 上载
     * @param fileName 待上载的文件名
     * @param dataHandler 数据句柄
     * @throws IOException IO异常
     */
    public void upload(
        @WebParam(name="fileName")String fileName,

        @XmlMimeType("*/*")
        @WebParam(name="fileDataHandler")
        DataHandler dataHandler)throws IOException{

        File depository = getFileDepository();

        InputStream in = dataHandler.getInputStream();
        OutputStream out = new FileOutputStream(depository.getAbsolutePath()+File.separatorChar+fileName);

        byte[] buf = new byte[BUFFER_SIZE];
        int read;
        while( (read=in.read(buf))!=-1 ) {
            out.write(buf,0,read);
            out.flush();
        }
        in.close();
        out.close();
    }

    /**
     * 列表文件清单
      * @return 文件清单
     */
    public java.util.List<FileDescription> listFiles(){
        File fileDepository = getFileDepository();
        java.util.List<FileDescription>L=new java.util.ArrayList<FileDescription>(0);

        for (File f : fileDepository.listFiles()) {

            FileDescription fds = new FileDescription();


            Calendar cal = Calendar.getInstance();
            cal.setTimeInMillis(f.lastModified());

            fds.setModifiedDate(cal);
            fds.setFileName(f.getName());
            fds.setLength(f.length());
            L.add(fds);
        }

        return L;
    }

    /**
     * 获取临时上载文件的路径
     * @return 临时文件路径
     */
    private static File getFileDepository(){
        return new File(System.getProperty("java.io.tmpdir"));
    }
}


客户端代码

import stub.*;
import javax.xml.namespace.*;
import javax.xml.ws.soap.*;
import javax.xml.ws.*;
import javax.activation.*;
import java.net.*;
import java.util.*;
import java.text.*;
import java.io.*;
import java.io.IOException;
import com.sun.xml.ws.developer.*;
/**
 * @author Hardneedl
 */
class FileClient {
    final static private int CHUNK_SIZE = 1024*1024*300;
    final static private SimpleDateFormat DATEFORMAT = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
    public static void main(String[] args) throws MalformedURLException, IOException_Exception {

        URL url = new URL(args[0]);
        QName qname = new QName("http://mtom/", "MTOMServerService");
        MTOMServerService_Service service = new MTOMServerService_Service(url,qname);

        MTOMFeature feature = new MTOMFeature();
        MTOMServerService mtomPort = service.getMTOMServer(feature);

        //列文件清单
        for(FileDescription fds : mtomPort.listFiles()){
            System.out.println("file Name : "+fds.getFileName());
            System.out.println("file size : "+fds.getLength());

            Date date = fds.getModifiedDate().toGregorianCalendar().getTime();
            System.out.println("last date : "+ DATEFORMAT.format(date));
            System.out.println("___________________________________________");
        }


        //上载文件
        if(args.length<2){
            System.err.println("no file to be upload.");
            System.err.println("set the file path on the command line for the second argument\ne.g\nFileClient [wsdl-url] [full path]");
        }
        else{
            Map<String, Object> ctxt = ((BindingProvider)mtomPort).getRequestContext();
            ctxt.put(JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, CHUNK_SIZE);
            File uploadFile = new File(args[1]);
            FileDataSource fileDataSource = new FileDataSource(uploadFile);
            DataHandler dataHandler = new DataHandler(fileDataSource);
            mtomPort.upload(uploadFile.getName(),dataHandler);
        }

        //下载指定的单个文件
        //try {
        //    final String fileName = "深海圆疑.rmvb";
        //    OutputStream fileOut = new FileOutputStream(fileName);
        //
        //    DataHandler downloadHandler = mtomPort.download(fileName);
        //    InputStream fileIn = downloadHandler.getInputStream();
        //    byte[] buf = new byte[CHUNK_SIZE];
        //    int read;
        //    while (-1 != (read = fileIn.read(buf))) {
        //        fileOut.write(buf,0,read);
        //        fileOut.flush();
        //    }
        //    fileIn.close();
        //    fileOut.close();
        //} catch(FileNotFoundException_Exception e) {
        //    e.printStackTrace();
        //} catch(IOException e) {
        //    e.printStackTrace();
        //}

        //下载全部文件
        try {
            List<DataHandler> dataHandlers = mtomPort.downloadMulti();
            byte[] buf = new byte[CHUNK_SIZE];
            for (int i = 0,j=dataHandlers.size(); i <j;i++) {
                DataHandler handler = dataHandlers.get(i);
                String fileName = handler.getName();
                fileName = fileName==null||fileName.isEmpty()?Integer.toString(i):fileName;
                InputStream in = handler.getInputStream();
                OutputStream out=new FileOutputStream(fileName);

                int read;
                while((read=in.read(buf))!=-1){
                    out.write(buf,0,read);
                    out.flush();
                }
                in.close();out.close();

            }
        } catch(FileNotFoundException_Exception e) {
            e.printStackTrace();
        } catch(IOException e) {
            e.printStackTrace();
        }
    }
}