欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaEE組件commons-fileupload實(shí)現(xiàn)文件上傳、下載

 更新時(shí)間:2016年10月14日 15:10:42   作者:rocomp  
這篇文章主要介紹了JavaEE組件commons-fileupload實(shí)現(xiàn)文件上傳、下載,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

一、文件上傳概述

實(shí)現(xiàn)Web開(kāi)發(fā)中的文件上傳功能,需要兩步操作:

1、在Web頁(yè)面中添加上傳輸入項(xiàng)

    <form action="#" method="post" enctype="multipart/form-data">
      <input type="file" name="filename1"/><br>
      <input type="file" name="filename2"/><br>
      <input type="submit" value="上傳"/>
    <form>
    <!-- 1、表單方式必須是post
      2、必須設(shè)置encType屬性為 multipart/form-data.設(shè)置該值后,瀏覽器在上傳文件時(shí),將會(huì)把文件數(shù)據(jù)附帶在http請(qǐng)求消息體中,
        并使用MIME協(xié)議對(duì)上傳的文件進(jìn)行描述,以方便接收方對(duì)上傳數(shù)據(jù)進(jìn)行解析和處理。
      3、必須要設(shè)置input的name屬性,否則瀏覽器將不會(huì)發(fā)送上傳文件的數(shù)據(jù)。
    -->

2、在Servlet中讀取文件上傳數(shù)據(jù),并保存到服務(wù)器硬盤

Request對(duì)象提供了一個(gè)getInputStream方法,通過(guò)這個(gè)方法可以讀取到客戶端提交過(guò)來(lái)的數(shù)據(jù)。但由于用戶可能會(huì)同時(shí)上傳多個(gè)文件,在Servlet端編程直接讀取上傳數(shù)據(jù),并分別解析出相應(yīng)的文件數(shù)據(jù)是一項(xiàng)非常麻煩的工作。

比如下面是截取的瀏覽器上傳文件時(shí)發(fā)送的請(qǐng)求的HTTP協(xié)議中的部分內(nèi)容:        

Accept-Language: zh-Hans-CN,zh-Hans;q=0.5
Content-Type: multipart/form-data; boundary=---------------------------7dfa01d1908a4
UA-CPU: AMD64
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.2; Win64; x64; Trident/7.0; rv:11.0) like Gecko
Content-Length: 653
Host: localhost:8080
Connection: Keep-Alive
Pragma: no-cache
Cookie: JSESSIONID=11CEFF8E271AB62CE676B5A87B746B5F
-----------------------------7dfa01d1908a4
Content-Disposition: form-data; name="username"
zhangsan
-----------------------------7dfa01d1908a4
Content-Disposition: form-data; name="userpass"
1234
-----------------------------7dfa01d1908a4
Content-Disposition: form-data; name="filename1"; filename="C:\Users\ASUS\Desktop\upload.txt"
Content-Type: text/plain
this is first file content!
-----------------------------7dfa01d1908a4
Content-Disposition: form-data; name="filename1"; filename="C:\Users\ASUS\Desktop\upload2.txt"
Content-Type: text/plain
this is Second file content!
hello
-----------------------------7dfa01d1908a4--

 從上面的數(shù)據(jù)中也可以看出,如果自己手工的去分割讀取數(shù)據(jù)很難寫(xiě)出健壯穩(wěn)定的程序。所以,為方便用戶處理上傳數(shù)據(jù),Apache開(kāi)源組織提供了一個(gè)用來(lái)處理表單文件上傳的一個(gè)開(kāi)源組件(Commons-fileupload),該組件性能優(yōu)異,并且其API使用極其簡(jiǎn)單,可以讓開(kāi)發(fā)人員輕松實(shí)現(xiàn)web文件上傳功能,因此在web開(kāi)發(fā)中實(shí)現(xiàn)文件上傳功能,通常使用Commons-fileupload組件實(shí)現(xiàn)。

 需要導(dǎo)入兩個(gè)jar包:Commons-fileupload、commons-io

response.setContentType("text/html;charset=utf-8");//設(shè)置響應(yīng)編碼
    request.setCharacterEncoding("utf-8");
    PrintWriter writer = response.getWriter();//獲取響應(yīng)輸出流
    
    ServletInputStream inputStream = request.getInputStream();//獲取請(qǐng)求輸入流
    
    /*
     * 1、創(chuàng)建DiskFileItemFactory對(duì)象,設(shè)置緩沖區(qū)大小和臨時(shí)文件目錄
     *  該類有兩個(gè)構(gòu)造方法一個(gè)是無(wú)參的構(gòu)造方法,
     *  另一個(gè)是帶兩個(gè)參數(shù)的構(gòu)造方法
     * @param int sizeThreshold,該參數(shù)設(shè)置內(nèi)存緩沖區(qū)的大小,默認(rèn)值為10K。當(dāng)上傳文件大于緩沖區(qū)大小時(shí),fileupload組件將使用臨時(shí)文件緩存上傳文件
     * @param java.io.File repository,該參數(shù)指定臨時(shí)文件目錄,默認(rèn)值為System.getProperty("java.io.tmpdir");
     * 
     *  如果使用了無(wú)參的構(gòu)造方法,則使用setSizeThreshold(int sizeThreshold),setRepository(java.io.File repository)
     *  方法手動(dòng)進(jìn)行設(shè)置 
     */
    DiskFileItemFactory factory = new DiskFileItemFactory();
    
    int sizeThreshold=1024*1024;
    factory.setSizeThreshold(sizeThreshold);
    
    File repository = new File(request.getSession().getServletContext().getRealPath("temp"));
//    System.out.println(request.getSession().getServletContext().getRealPath("temp"));
//    System.out.println(request.getRealPath("temp"));
    factory.setRepository(repository);
    
    /*
     * 2、使用DiskFileItemFactory對(duì)象創(chuàng)建ServletFileUpload對(duì)象,并設(shè)置上傳文件的大小
     *  
     *  ServletFileUpload對(duì)象負(fù)責(zé)處理上傳的文件數(shù)據(jù),并將表單中每個(gè)輸入項(xiàng)封裝成一個(gè)FileItem
     *  該對(duì)象的常用方法有:
     *      boolean isMultipartContent(request);判斷上傳表單是否為multipart/form-data類型
     *      List parseRequest(request);解析request對(duì)象,并把表單中的每一個(gè)輸入項(xiàng)包裝成一個(gè)fileItem 對(duì)象,并返回一個(gè)保存了所有FileItem的list集合
     *      void setFileSizeMax(long filesizeMax);設(shè)置單個(gè)上傳文件的最大值
     *      void setSizeMax(long sizeMax);設(shè)置上傳溫江總量的最大值
     *      void setHeaderEncoding();設(shè)置編碼格式,解決上傳文件名亂碼問(wèn)題
     */
    ServletFileUpload upload = new ServletFileUpload(factory);
    
    upload.setHeaderEncoding("utf-8");//設(shè)置編碼格式,解決上傳文件名亂碼問(wèn)題
    /*
     * 3、調(diào)用ServletFileUpload.parseRequest方法解析request對(duì)象,得到一個(gè)保存了所有上傳內(nèi)容的List對(duì)象
     */
    List<FileItem> parseRequest=null;
    try {
       parseRequest = upload.parseRequest(request);
    } catch (FileUploadException e) {
      e.printStackTrace();
    }
    /*
     * 4、對(duì)list進(jìn)行迭代,每迭代一個(gè)FileItem對(duì)象,調(diào)用其isFormField方法判斷是否是文件上傳
     *  true表示是普通表單字段,則調(diào)用getFieldName、getString方法得到字段名和字段值
     *  false為上傳文件,則調(diào)用getInputStream方法得到數(shù)據(jù)輸入流,從而讀取上傳數(shù)據(jù)
     *  
     *  FileItem用來(lái)表示文件上傳表單中的一個(gè)上傳文件對(duì)象或者普通的表單對(duì)象
     *  該對(duì)象常用方法有:
     *     boolean isFormField();判斷FileItem是一個(gè)文件上傳對(duì)象還是普通表單對(duì)象
     *     true表示是普通表單字段,
     *         則調(diào)用getFieldName、getString方法得到字段名和字段值
     *     false為上傳文件,
     *         則調(diào)用getName()獲得上傳文件的文件名,注意:有些瀏覽器會(huì)攜帶客戶端路徑,需要自己減除
     *         調(diào)用getInputStream()方法得到數(shù)據(jù)輸入流,從而讀取上傳數(shù)據(jù)
     *         delete(); 表示在關(guān)閉FileItem輸入流后,刪除臨時(shí)文件。
     */
    
    for (FileItem fileItem : parseRequest) {
      if (fileItem.isFormField()) {//表示普通字段
        if ("username".equals(fileItem.getFieldName())) {
          String username = fileItem.getString();
          writer.write("您的用戶名:"+username+"<br>");
        }
        if ("userpass".equals(fileItem.getFieldName())) {
          String userpass = fileItem.getString();
          writer.write("您的密碼:"+userpass+"<br>");
        }
        
      }else {//表示是上傳的文件
        //不同瀏覽器上傳的文件可能帶有路徑名,需要自己切割
        String clientName = fileItem.getName();
        String filename = "";
        if (clientName.contains("\\")) {//如果包含"\"表示是一個(gè)帶路徑的名字,則截取最后的文件名
          filename = clientName.substring(clientName.lastIndexOf("\\")).substring(1);
        }else {
          filename = clientName;
        }
        
        UUID randomUUID = UUID.randomUUID();//生成一個(gè)128位長(zhǎng)的全球唯一標(biāo)識(shí)
        
        filename = randomUUID.toString()+filename;
        
        /*
         * 設(shè)計(jì)一個(gè)目錄生成算法,如果所用用戶上傳的文件總數(shù)是億數(shù)量級(jí)的或更多,放在同一個(gè)目錄下回導(dǎo)致文件索引非常慢,
         * 所以,設(shè)計(jì)一個(gè)目錄結(jié)構(gòu)來(lái)分散存放文件是非常有必要,且合理的
         * 將UUID取哈希算法,散列到更小的范圍,
         * 將UUID的hashcode轉(zhuǎn)換為一個(gè)8位的8進(jìn)制字符串,
         * 從這個(gè)字符串的第一位開(kāi)始,每一個(gè)字符代表一級(jí)目錄,這樣就構(gòu)建了一個(gè)八級(jí)目錄,每一級(jí)目錄中最多有16個(gè)子目錄
         * 這無(wú)論對(duì)于服務(wù)器還是操作系統(tǒng)都是非常高效的目錄結(jié)構(gòu)
         */
        int hashUUID =randomUUID.hashCode();
        String hexUUID = Integer.toHexString(hashUUID);
        //System.out.println(hexUUID);
        //獲取將上傳的文件存存儲(chǔ)在哪個(gè)文件夾下的絕對(duì)路徑
        String filepath=request.getSession().getServletContext().getRealPath("upload");
        for (char c : hexUUID.toCharArray()) {
          filepath = filepath+"/"+c;
        }
        //如果目錄不存在就生成八級(jí)目錄
        File filepathFile = new File(filepath);
        if (!filepathFile.exists()) {
          filepathFile.mkdirs();
        }
        //從Request輸入流中讀取文件,并寫(xiě)入到服務(wù)器
        InputStream inputStream2 = fileItem.getInputStream();
        //在服務(wù)器端創(chuàng)建文件
        File file = new File(filepath+"/"+filename);
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
        
        byte[] buffer = new byte[10*1024];
        int len = 0;
        while ((len= inputStream2.read(buffer, 0, 10*1024))!=-1) {
          bos.write(buffer, 0, len);
        }
        writer.write("您上傳文件"+clientName+"成功<br>");
        //關(guān)閉資源
        bos.close();
        inputStream2.close();
      }
    }
  //注意Eclipse的上傳的文件是保存在項(xiàng)目的運(yùn)行目錄,而不是workspace中的工程目錄里。

 二、文件上傳需要特別注意的問(wèn)題: (這些問(wèn)題在上面的代碼中都提供了簡(jiǎn)單的解決)

1、文件存放的位置

為保證服務(wù)器的安全,上傳文件應(yīng)保存在應(yīng)用程序的WEB-INF目錄下,或者不受WEB服務(wù)器管理的目錄,如果用戶上傳一個(gè)帶有可執(zhí)行代碼的文件,如jsp文件,根據(jù)拼接訪問(wèn)路徑去訪問(wèn)的話,可以在服務(wù)器端做任何事情。

2、為防止多用戶上傳形同文件名的文件,而導(dǎo)致文件覆蓋的情況發(fā)生,文件上傳程序應(yīng)保證上傳文件具有唯一文件名

使用UUID + 用戶上傳文件名的方式重命名

關(guān)于UUID:
UUID(Universally Unique Identifier)全局唯一標(biāo)識(shí)符,是指在一臺(tái)機(jī)器上生成的數(shù)字,它保證對(duì)在同一時(shí)空中的所有機(jī)器都是唯一的。按照開(kāi)放軟件基金會(huì)(OSF)制定的標(biāo)準(zhǔn)計(jì)算,用到了以太網(wǎng)卡地址、納秒級(jí)時(shí)間、芯片ID碼和許多可能的數(shù)字。由以下幾部分的組合:當(dāng)前日期和時(shí)間(UUID的第一個(gè)部分與時(shí)間有關(guān),如果你在生成一個(gè)UUID之后,過(guò)幾秒又生成一個(gè)UUID,則第一個(gè)部分不同,其余相同),時(shí)鐘序列,全局唯一的IEEE機(jī)器識(shí)別號(hào)(如果有網(wǎng)卡,從網(wǎng)卡獲得,沒(méi)有網(wǎng)卡以其他方式獲得),UUID的唯一缺陷在于生成的結(jié)果串會(huì)比較長(zhǎng)。

是一個(gè)128位長(zhǎng)的數(shù)字,一般用16進(jìn)制表示。算法的核心思想是結(jié)合機(jī)器的網(wǎng)卡、當(dāng)?shù)貢r(shí)間、一個(gè)隨即數(shù)來(lái)生成GUID。從理論上講,如果一臺(tái)機(jī)器每秒產(chǎn)生10000000個(gè)GUID,則可以保證(概率意義上)3240年不重復(fù)。

從JDK1.5開(kāi)始,生成UUID變成了一件簡(jiǎn)單的事,以為JDK實(shí)現(xiàn)了UUID:

java.util.UUID,直接調(diào)用即可.
UUID uuid  =  UUID.randomUUID();
String s = UUID.randomUUID().toString();//用來(lái)生成數(shù)據(jù)庫(kù)的主鍵id非常不錯(cuò)。。 
 
UUID是由一個(gè)十六位的數(shù)字組成,表現(xiàn)出來(lái)的形式例如
550E8400-E29B-11D4-A716-446655440000 

3、為防止單個(gè)目錄下文件過(guò)多,影響文件讀寫(xiě)速度,處理上傳文件的程序應(yīng)該應(yīng)根據(jù)可能的上傳總量,選擇合適的目錄結(jié)構(gòu)生成算法,將上傳文件分散存儲(chǔ)。如使用hashcode方法構(gòu)建多級(jí)目錄。

4、如果不同用戶都上傳了相同的文件,那么在服務(wù)器端沒(méi)有必要存儲(chǔ)同一個(gè)文件的很多分拷貝,這樣很浪費(fèi)資源,應(yīng)該設(shè)計(jì)算法解決這種重復(fù)文件的問(wèn)題。

5、JSP技術(shù)原理自動(dòng)實(shí)現(xiàn)了多線程。所以開(kāi)發(fā)者不需要考慮上傳文件的多線程操作 

三、文件下載 

<%
    ArrayList<String> fileNames = new ArrayList<String>();
    fileNames.add("file/aa.txt");
    fileNames.add("file/bb.jpg");
    for(String fileName : fileNames) {
   %>
   
    <form action="DownloadServlet" method="get">
      <input type="hidden" name="fileName" value="<%=fileName %>" />
      <input type="submit" value="下載:<%=fileName %>" />
    </form>
   <%
    }
   %>
 
    request.setCharacterEncoding("utf-8");
    
    String filename = request.getParameter("fileName");
    
    
    String urlname = URLEncoder.encode(filename, "utf-8");//防止文件名中有中文亂碼
    response.setHeader("Content-Disposition","attachment;filename="+urlname);
    
    FileInputStream fis = new FileInputStream(new File(request.getSession().getServletContext().getRealPath(filename)));
    BufferedInputStream bis = new BufferedInputStream(fis);
    ServletOutputStream sos = response.getOutputStream();
    
    byte[] buffer = new byte[1024];
    int len=0;
    while((len=bis.read(buffer, 0, 1024))!=-1){
      sos.write(buffer, 0, len);
    }
    bis.close();
    fis.close();

四、在SSH中使用smartUpload組件簡(jiǎn)化文件上傳下載

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java的BigDecimal在math包中提供的API類場(chǎng)景使用詳解

    Java的BigDecimal在math包中提供的API類場(chǎng)景使用詳解

    這篇文章主要介紹了Java的BigDecimal在math包中提供的API類場(chǎng)景使用詳解,BigDecimal,用來(lái)對(duì)超過(guò)16位有效位的數(shù)進(jìn)行精確的運(yùn)算,雙精度浮點(diǎn)型變量double可以處理16位有效數(shù),在實(shí)際應(yīng)用中,需要對(duì)更大或者更小的數(shù)進(jìn)行運(yùn)算和處理,需要的朋友可以參考下
    2023-12-12
  • IDEA如何實(shí)現(xiàn)批量修改變量名

    IDEA如何實(shí)現(xiàn)批量修改變量名

    這篇文章主要介紹了IDEA如何實(shí)現(xiàn)批量修改變量名問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • JSP代碼實(shí)現(xiàn) 金字塔(倒置)示例

    JSP代碼實(shí)現(xiàn) 金字塔(倒置)示例

    這篇文章主要介紹了JSP代碼實(shí)現(xiàn) 金字塔(倒置)示例,需要的朋友可以參考下
    2014-02-02
  • SpringCloud?OpenFeign概述與使用教程

    SpringCloud?OpenFeign概述與使用教程

    OpenFeign源于Netflix的Feign,是http通信的客戶端。屏蔽了網(wǎng)絡(luò)通信的細(xì)節(jié),直接面向接口的方式開(kāi)發(fā),讓開(kāi)發(fā)者感知不到網(wǎng)絡(luò)通信細(xì)節(jié)。所有遠(yuǎn)程調(diào)用,都像調(diào)用本地方法一樣完成
    2023-02-02
  • SpringCloud讀取Nacos配置中心報(bào)錯(cuò)及遇到的坑:Could?not?resolve?placeholder?‘xxx’?in?value?‘${xxx}

    SpringCloud讀取Nacos配置中心報(bào)錯(cuò)及遇到的坑:Could?not?resolve?placehold

    這篇文章主要介紹了SpringCloud讀取Nacos配置中心報(bào)錯(cuò):Could?not?resolve?placeholder?‘xxx’?in?value?‘${xxx},本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-03-03
  • Spring使用注解進(jìn)行對(duì)象注入的示例詳解

    Spring使用注解進(jìn)行對(duì)象注入的示例詳解

    獲取?Bean?對(duì)象也叫做對(duì)象裝配,就是把對(duì)象取出來(lái)放到某個(gè)類中,有時(shí)候也叫對(duì)象注入,常見(jiàn)有關(guān)對(duì)象注入的注解有兩個(gè),一個(gè)是@Autowired,另外一個(gè)是@Resource,下面就來(lái)講講它們的具體使用吧
    2023-07-07
  • 深入理解注解與自定義注解的一些概念

    深入理解注解與自定義注解的一些概念

    今天給大家?guī)?lái)的文章是注解的相關(guān)知識(shí),本文圍繞著注解與自定義注解的一些概念展開(kāi),文中詳細(xì)介紹了這些知識(shí),需要的朋友可以參考下
    2021-06-06
  • Java Spring框架簡(jiǎn)介與Spring IOC詳解

    Java Spring框架簡(jiǎn)介與Spring IOC詳解

    Spring 框架是一個(gè)輕量級(jí)的解決方案,可以一站式地構(gòu)建企業(yè)級(jí)應(yīng)用。它是為了解決 企業(yè)應(yīng)用開(kāi)發(fā)的復(fù)雜性而創(chuàng)建的。Spring 使用基本的 JavaBean 來(lái)完成以前只可能由 EJB 完成的事情。IOC 是 Inversion of Control 的縮寫(xiě),多數(shù)書(shū)籍翻譯成控制反轉(zhuǎn)
    2021-09-09
  • logback-spring.xml的內(nèi)容格式詳解

    logback-spring.xml的內(nèi)容格式詳解

    這篇文章主要介紹了logback-spring.xml的內(nèi)容格式詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的的朋友參考下吧
    2023-11-11
  • Java異常類型以及處理實(shí)例詳解

    Java異常類型以及處理實(shí)例詳解

    在程序設(shè)計(jì)中,進(jìn)行異常處理是非常關(guān)鍵和重要的一部分,一個(gè)程序的異常處理框架的好壞直接影響到整個(gè)項(xiàng)目的代碼質(zhì)量以及后期維護(hù)成本和難度,這篇文章主要給大家介紹了關(guān)于Java異常類型以及處理的相關(guān)資料,需要的朋友可以參考下
    2021-07-07

最新評(píng)論