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包來實現數據文件上傳。

具體各類服務端技術請見下回具體介紹。

相關文章
相關標籤/搜索