WEB文件上传方案探索(一)

在上次对大数据导入功能方案设计中,主要对方案的选择和数据导入的实现进行了分析研究,此次,咱们就对文件如何高效地上传到服务器作一次分析和总结。 web

文件上传并非一份困难的工做,但将它限制于WEB的领域彷佛就有一些探索的价值了。正如上次文章《基于Oracle的大数据导入方案探索》中所言,文件上传受到WEB架构的一些影响,若是是上传几K或者几十K的文件固然不在话下,但若是是几百兆甚至几个G的文件来讲,就应该慎重考虑一下了。WEB文件上传和其余网络应用同样,都是经过一些网络技术将客户端文件上传到服务器上,只不过客户端程序是一个浏览器而已。对于WEB性质的文件上传,无非就在于客户端和服务端技术方案的选择和设计。 apache

1、客户端技术 小程序

客户端技术是WEB文件上传的重点,由于WEB自己是运行于服务端的程序,只不过经过浏览器来让客户端访问,要实如今WEB中访问客户端资源就必须实现web中对本地资源的操做。 浏览器

经过研究和总结,对于web上的客户端应用一般采用的插件嵌入的方式来实现,文件上传也不例外,能够经过如下方式实现: 安全

(1)HTML方式。 服务器

(2)RIA方式。 网络

(3)插件方式。 session

(一)HTML方式 架构

HTML方式是你们使用最多也是最容易使用的方式,它经过<input type=file>的标签打开文件浏览器,经过文件选择和流化,最终将文件以数据流的方式发送到服务端。 并发

支持此方式的开源框架不少,好比struts的文件上传机制等,此处以Struts2为例简单讲解一下。

首先,web页面中应该有一个form表单,其中包括<input type=file>标签。

<form id="upLoadForm" action="${ctx}/dataImport/uploadData.action"

method="post" enctype="multipart/form-data" style="display:none">

<input type="button" value="添加文件" onclick="addFile();"/>

<input type="submit" value="上传" onclick="return checkFile();"/>

<!--对于每一个JSP页面要设置type以及subType-->

<input type="hidden" id="type" name="type" value="airline"/>

<input type="hidden" id="subType" name="subType" value="newAirline" />

<br>

<input id="file" type="file" name="file" size="70" />

<img  src="${ctx}/styles/p_w_picpaths/upload/delete.gif" onclick="removeInput();"/>

<br>

</form>

此处须要注意file标签的name属性须要和后台action中的file文件名称一致,表单须要设定以multipart的方式来封装数据enctype="multipart/form-data"

后台的Action中须要完成对前台传输的文件对象进行拷贝就行,具体的文件对象封装将由Struts框架来实现完成。

……

//上传文件

private List<File> file

……

    public String upload() throws Exception{

//需修改成从session中获取用户名

String uploadUser = "uploadUser";

//获取上传文件数目

int len = file==null?0:file.size();

//遍历上传文件,并上传

for(int i=0;i<len;i++){

File upFile = file.get(i);

fileService.addFile(upFile, fileFileName.get(i), uploadUser, type);

}

return type;

}

方法中能够看出,后台在获取到file对象之后就执行了文件拷贝到服务器目录下的工做。

此方案实现相对简单,对于小文件的上传是一个不错的选择。

(二)RIA方式

RIARich Internet Applications的缩写,翻译成中文为丰富的因特网应用程序,它是集桌面应用程序的最佳用户界面功能与Web应用程序的广泛采用和快速、低成本部署以及互动多媒体通讯的实时快捷于一体的新一代网络应用程序。它能够经过以web结合方式来提供更好的web用户体验和操做。经常使用的RIA方式包括JAVAFXMicrosoftSilverlight等等,在方案中,咱们就能够经过这些方式将本地文件选取集成到RIA程序中,经过其向服务端发起文件上传的请求和数据,从而完成文件上传功能。

Flex为例,Flex中提供了FileRefference类,其中包括了不少文件操做相关的方法和事件,提供了咱们对于文件操做的接口,如图

                     

有了upload方法,上传进度和上传完成事件,能够很容易地实现大文件上传和进度显示任务。Flash上传的文件大小是没有限制的,经测试,能够上传600MB的文件。不过要注意的是,若是该文件须要在Flash播放器中播放,则最大限制为100MB,因此在上传视频文件且须要在浏览中播放时要注意这个题。

         

                     

(三)插件方式

插件方式是指在浏览器中经过embed方式嵌入或者植入插件方式进行数据文件的获取,从而经过web通讯技术将数据流发送到服务端的方式。此方式的实践方案包括ActiveXApplet技术等,前者能够经过VB开发出CAB插件,在浏览器上使用,后者则经过applet标签将applet客户端小程序嵌入到页面来完成。不过applet受限于沙箱的安全策略,要对客户端文件系统操做须要安装数字签名。

以下是一个Applet实现的文件上传客户端代码。

 

   
   
   
   
  1. public class SoonecUpload extends JApplet  
  2.  
  3.   implements ActionListener  
  4.  
  5. {  
  6.  
  7.   JSObject myBrowser;  
  8.  
  9.   JLabel label;  
  10.  
  11.   JLabel inflab;  
  12.  
  13.   JTable table;  
  14.  
  15.   JButton[] btn;  
  16.  
  17.   JPanel panel;  
  18.  
  19.   JPanel subpanel;  
  20.  
  21.   JPanel cur_panel;  
  22.  
  23.   JPanel total_panel;  
  24.  
  25.   JProgressBar cur_jpb;  
  26.  
  27.   JProgressBar total_jpb;  
  28.  
  29.   MSTable mt;  
  30.  
  31.   Thread ft;  
  32.  
  33.   String type;  
  34.  
  35.   long size;  
  36.  
  37.   String path;  
  38.  
  39.   byte rename;  
  40.  
  41.   String server_url;  
  42.  
  43.   String langs;  
  44.  
  45.   Map languages;  
  46.  
  47.  
  48.   public SoonecUpload()  
  49.  
  50.   {  
  51.  
  52.     this.mt = null;  
  53.  
  54.     this.ft = new Thread();  
  55.  
  56.     this.type = "jpeg,jpg,gif,png";  
  57.  
  58.     this.size = 51200L;  
  59.  
  60.     this.path = "uploads";  
  61.  
  62.     this.rename = 1;  
  63.  
  64.     this.server_url = "";  
  65.  
  66.     this.langs = "en";  
  67.  
  68.   }  
  69.  
  70.  
  71.   public void init() {  
  72.  
  73.     super.init();  
  74.  
  75.     this.languages = new HashMap();  
  76.  
  77.     if (getParameter("type") != null) {  
  78.  
  79.       this.type = getParameter("type").toLowerCase();  
  80.  
  81.     }  
  82.  
  83.     if (getParameter("path") != null) {  
  84.  
  85.       this.path = getParameter("path");  
  86.  
  87.     }  
  88.  
  89.     if ((getParameter("language") != null) && (getParameter("language").toLowerCase().equals("cn"))) {  
  90.  
  91.       this.langs = "cn";  
  92.  
  93.     }  
  94.  
  95.     initLanguages();  
  96.  
  97.     if (getParameter("size") != null) {  
  98.  
  99.       this.size = Long.parseLong(getParameter("size"));  
  100.  
  101.     }  
  102.  
  103.     this.server_url = getCodeBase() + "";  
  104.  
  105.     if (!(this.server_url.startsWith("http://"))) {  
  106.  
  107.       JOptionPane.showMessageDialog(null, getLanguage("error_url"), "SOONEC.ZHOU"0);  
  108.  
  109.       stop();  
  110.  
  111.       destroy();  
  112.  
  113.       return;  
  114.  
  115.     }  
  116.  
  117.  
  118.     this.server_url = this.server_url.substring(0this.server_url.toLowerCase().replaceAll("http://""").indexOf("/") + 7) + "/";  
  119.  
  120.     if ((getParameter("virtual_dir") != null) && (!getParameter("virtual_dir").equals("")))  
  121.  
  122.     {  
  123.  
  124.       SoonecUpload tmp275_274 = this; tmp275_274.server_url = tmp275_274.server_url + getParameter("virtual_dir") + "/";  
  125.  
  126.     }  
  127.  
  128.  
  129.     this.myBrowser = JSObject.getWindow(this);  
  130.  
  131.     createUI();  
  132.  
  133.   }  
  134.  
  135. ……  
  136.  
  137.   public void actionPerformed(ActionEvent paramActionEvent)  
  138.  
  139.   {  
  140.  
  141.     String str = paramActionEvent.getActionCommand();  
  142.  
  143.     if ((str.equals("Browser")) || (str.equals("添加文件"))) {  
  144.  
  145.       getFileList();  
  146.  
  147.     }  
  148.  
  149.     else if ((str.equals("Upload")) || (str.equals("上传文件")))  
  150.  
  151.     {  
  152.  
  153.       try 
  154.  
  155.       {  
  156.  
  157.         this.ft = new Thread(new getThread(this));  
  158.  
  159.         this.ft.start();  
  160.  
  161.       }  
  162.  
  163.       catch (Exception localException)  
  164.  
  165.       {  
  166.  
  167.       }  
  168.  
  169.  
  170.     }  
  171.  
  172.     else if ((str.equals("Delete")) || (str.equals("删除所选"))) {  
  173.  
  174.       if ((this.table.getValueAt(this.table.getSelectedRow(), 4).equals("1")) || (this.table.getValueAt(this.table.getSelectedRow(), 4).equals("2"))) {  
  175.  
  176.         return;  
  177.  
  178.       }  
  179.  
  180.       File localFile = new File((String)this.table.getValueAt(this.table.getSelectedRow(), 1));  
  181.  
  182.       this.total_jpb.setMaximum(this.total_jpb.getMaximum() - (int)Math.round(localFile.length() / 1024.0D));  
  183.  
  184.       if (this.table.getValueAt(this.table.getSelectedRow(), 4).equals("1"))  
  185.  
  186.         this.total_jpb.setValue(this.total_jpb.getValue() - (int)Math.round(localFile.length() / 1024.0D));  
  187.  
  188.       this.mt.removeRow(this.table.getSelectedRow());  
  189.  
  190.     }  
  191.  
  192.     else 
  193.  
  194.     {  
  195.  
  196.       if (str.equals("Stop"))  
  197.  
  198.       {  
  199.  
  200.         return;  
  201.  
  202.       }  
  203.  
  204.  
  205.       getAuthor();  
  206.  
  207.     }  
  208.  
  209.   }  
  210.  
  211. ……  

以上代码虽然看上去很长,但核心部分就是经过调用JFileChooser对象来实现对客户端文件进行选取操做,而后经过请求发送到服务端。

建立完Applet,须要将其嵌入到web页面之中。

 <body>

     <APPLET id="filechooser" codebase="." code="com.travelsky.upload.SoonecUpload.class"  width=560 height=200 ">

        <param name="type" value="zip,gz,bmp,jpg,jpeg,gif,txt,cer"/>

          <param name="size" value="500000"/>

           <param name="path" value="uploadss"/>

             <param name="norename" value="0"/>

               <param name="virtual_dir" value=""/>

   <param name="language" value="en"/>

        </APPLET>

  </body>

以上经过applet标签将以前的applet嵌入到页面中,param是向applet中传递的参数,在applet.class中能够经过getParam方法获取。

完成以上固然不够,要打破沙箱策略限制,还须要对applet进行数字签名,具体方法以下:

<1>、生成密匙证书(key certificate),该证书将存储在你的.keystore文件中。Validity指的是密匙的有效期,默认是180,可是这里咱们须要一年的时间,因此咱们设置为365
keytool -genkey -alias FileFtpApplet -validity 365 -keystore FileFtpApplet.keystore
<2>、用咱们的密匙来设计咱们的APPLET
jarsigner -keystore FileFtpApplet.keystore FileFtpApplet.jar FileFtpApplet
<3>、导出证书
keytool -export -keystore FileFtpApplet.keystore -alias FileFtpApplet -file FileFtpApplet.cer

2、服务端技术

客户端的只要功能是完成本地文件的获取并发送请求及文件数据,那么在服务端如何接收请求及如何处理请求又是另外一个问题。

为了配合web客户端实现文件上传,服务端一般能够采用三种技术实现:

(1)Socket通讯技术,利用socket实现服务端和客户端通讯;

(2)URLconnection,经过apachenet包中的Urlconnection模拟通讯;

(3)FTPClient,利用apache实现的ftp包来实现数据文件上传。

具体各类服务端技术请见下回具体介绍。

相关文章
相关标签/搜索