20160420javaweb之檔案上傳和下載

破玉發表於2016-04-20

一、檔案上傳
1.提供表單允許使用者通過表單選擇檔案進行上傳
表單必須是POST提交
檔案輸入框必須有name屬性,只有有name屬性的輸入項瀏覽器才會進行提交
需要設定enctype屬性值為multipart/form-data

POST /Day15/upload.jsp HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Referer: http://localhost/Day15/upload.jsp
Accept-Language: zh-CN
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
Content-Type: multipart/form-data; boundary=---------------------------7de1e62806e0
Accept-Encoding: gzip, deflate
Host: localhost
Content-Length: 394
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: JSESSIONID=818C14110CA7BFD1FC90610866A220E8

-----------------------------7de1e62806e0
Content-Disposition: form-data; name="description1"

xxxx
-----------------------------7de1e62806e0
Content-Disposition: form-data; name="description2"

zzzz
-----------------------------7de1e62806e0
Content-Disposition: form-data; name="file1"; filename="ip.txt"
Content-Type: text/plain

192
-----------------------------7de1e62806e0--

2.在Servlet中將上傳的檔案儲存在伺服器的硬碟中
DiskFileItemFactory
public DiskFileItemFactory(int sizeThreshold, java.io.File repository)

public DiskFileItemFactory()
public void setSizeThreshold(int sizeThreshold) --用來設定記憶體緩衝區的大小,預設是10k
public void setRepository(java.io.File repository) --設定臨時資料夾的大小

ServletFileUpload
boolean isMultipartContent(HttpServletRequest request) 判斷上傳表單是否為multipart/form-data型別
List parseRequest(HttpServletRequest request) 解析request物件,並把表單中的每一個輸入項包裝成一個fileItem 物件,並返回一個儲存了所有FileItem的list集合。
setFileSizeMax(long fileSizeMax) 設定單個上傳檔案的最大值
setSizeMax(long sizeMax) 設定上傳檔案總量的最大值
setHeaderEncoding(java.lang.String encoding) 設定編碼格式,解決上傳檔名亂碼問題
setProgressListener(ProgressListener pListener) 實時監聽檔案上傳狀態

FileItem
boolean isFormField() 判斷FileItem是一個檔案上傳物件還是普通表單物件
示例程式碼:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>檔案上傳</h1><hr>
<form action="${pageContext.request.contextPath }/UploadFileServlet" method="post" enctype="multipart/form-data">
     描述資訊1:<input type="text" name="description1"/>
       描述資訊2:<input type="text" name="description2"/>
       <input type="file" name="file1"/>
       <input type="submit" value="上傳"/>
</form>
</body>
</html>
package com.dzq.web;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import com.dzq.utils.IOUtils;


@WebServlet("/UploadFileServlet")
public class UploadFileServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
   
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        /*InputStream is=request.getInputStream();
        byte[] bs=new byte[1024];
        int i=0;
        while((i=is.read(bs))!=-1){
            System.out.write(bs,0,i);
        }
        is.close();*/
        
        try {
            //1.建立工廠
            DiskFileItemFactory factory =new DiskFileItemFactory();
            //2.生產檔案上傳核心類
            ServletFileUpload fileupload=new ServletFileUpload(factory);
            //3.利用檔案上傳核心類解析request
            List<FileItem> list=fileupload.parseRequest(request);
            //4.遍歷所有的fileitem
            for(FileItem item:list){
                if(item.isFormField()){
                    //當前是普通欄位項
                    String name=item.getFieldName();
                    String value=item.getString();
                    System.out.println(name+":"+value);
                }else{
                    //當前是一個檔案上傳項
                    String filename=item.getName();
                    InputStream in=item.getInputStream();
                    OutputStream out=new FileOutputStream(this.getServletContext().getRealPath("/upload"+filename));
                    IOUtils.In2Out(in, out);
                    IOUtils.close(in, out);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}
package com.dzq.utils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class IOUtils {
   private IOUtils(){
       
   }
   
   public static void In2Out(InputStream in,OutputStream out) throws IOException{
       byte[] bs=new byte[1024];
       int i=0;
       while ((i=in.read(bs))!=-1) {
        out.write(bs,0,i);
    }
   }
   
   public static void close(InputStream in,OutputStream out){
       if(in!=null){
           try {
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            in=null;
        }
       }
       
       if(out!=null){
           try {
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            out=null;
        }
       }
   }
}

 


如果是一個普通欄位項可以呼叫:
String getFieldName() 獲得普通表單物件的name屬性
String getString(String encoding) 獲得普通表單物件的value屬性,可以用encoding進行編碼設定

如果是一個檔案上傳項:
String getName() 獲得上傳檔案的檔名(有些瀏覽器會攜帶客戶端路徑)
InputStream getInputStream() 獲得上傳檔案的輸入流
delete() 在關閉FileItem輸入流後,刪除臨時檔案



檔案存放應該注意的問題:
1.upload資料夾和temp資料夾都要放在web-inf目錄下保護起來,防止上傳入侵和訪問其他使用者上傳資源的問題
2.檔名要拼接uuid保證唯一
3.檔案要分目錄儲存保證同一目錄下不要有過多的檔案,分目錄的演算法有很多,介紹了一種根據hash值分目錄演算法

 

檔案上傳的一些細節:

package com.itheima.web;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.util.List;
import java.util.UUID;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import com.itheima.util.IOUtils;

public class UploadServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        try{
            //1.建立工廠
            DiskFileItemFactory factory = new DiskFileItemFactory();
            factory.setSizeThreshold(100*1024);
            factory.setRepository(new File(this.getServletContext().getRealPath("WEB-INF/temp")));
            //2.生產檔案上傳核心類
            ServletFileUpload fileUpload = new ServletFileUpload(factory);
            
            //--檢查是否是正確的檔案上傳表單
            if(!fileUpload.isMultipartContent(request)){
                throw new RuntimeException("請用正確的表單進行上傳!");
            }
            //--設定檔案上傳的大小限制
//            fileUpload.setFileSizeMax(1024*1024*100);//單個檔案不大於10M
//            fileUpload.setSizeMax(1024*1024*100);//總大小不大於100M
            
            //--設定編碼集,解決上傳檔名的亂碼問題
            fileUpload.setHeaderEncoding("utf-8");
            
            //--設定檔案上傳監聽
            fileUpload.setProgressListener(new ProgressListener(){
                Long beginTime = System.currentTimeMillis();
                public void update(long bytesRead, long contentLength, int items) {
                    BigDecimal br = new BigDecimal(bytesRead).divide(new BigDecimal(1024),2,BigDecimal.ROUND_HALF_UP);
                    BigDecimal cl = new BigDecimal(contentLength).divide(new BigDecimal(1024),2,BigDecimal.ROUND_HALF_UP);
                    System.out.print("當前讀取的是第"+items+"個上傳項,總大小"+cl+"KB,已經讀取"+br+"KB");
                    //剩餘位元組數
                    BigDecimal ll = cl.subtract(br);
                    System.out.print("剩餘"+ll+"KB");
                    //上傳百分比
                    BigDecimal per = br.multiply(new BigDecimal(100)).divide(cl,2,BigDecimal.ROUND_HALF_UP);
                    System.out.print("已經完成"+per+"%");
                    //上傳用時
                    Long nowTime = System.currentTimeMillis();
                    Long useTime = (nowTime - beginTime)/1000;
                    System.out.print("已經用時"+useTime+"秒");
                    //上傳速度
                    BigDecimal speed = new BigDecimal(0);
                    if(useTime!=0){
                        speed = br.divide(new BigDecimal(useTime),2,BigDecimal.ROUND_HALF_UP);
                    }
                    System.out.print("上傳速度為"+speed+"KB/S");
                    //大致剩餘時間
                    BigDecimal ltime = new BigDecimal(0);
                    if(!speed.equals(new BigDecimal(0))){
                        ltime = ll.divide(speed,0,BigDecimal.ROUND_HALF_UP);
                    }
                    System.out.print("大致剩餘時間為"+ltime+"秒");
                    
                    System.out.println();
                }
                
            });
            
            //3.利用檔案上傳核心類解析request
            List<FileItem> list = fileUpload.parseRequest(request);
            //4.遍歷所有的FileItem
            for(FileItem item : list){
                if(item.isFormField()){
                    //當前是一個普通的欄位項
                    String name = item.getFieldName();
                    String value = item.getString("utf-8");
                    System.out.println(name+":"+value);
                }else{
                    //當前是一個檔案上傳項
                    String filename = item.getName();
                    String uuidName = UUID.randomUUID().toString()+"_"+filename;
                    
                    int hash = uuidName.hashCode();
                    String hashStr = Integer.toHexString(hash);
                    char [] hss = hashStr.toCharArray();
                    String path = this.getServletContext().getRealPath("WEB-INF/upload");
                    for(char c : hss){
                        path+="/"+c;
                    }
                    new File(path).mkdirs();
                    
                    InputStream in = item.getInputStream();
                    OutputStream out = new FileOutputStream(new File(path,uuidName));
                    
                    IOUtils.In2Out(in, out);
                    IOUtils.close(in, out);
                    
                    //--刪除臨時檔案
                    item.delete();
                }
            }
        }catch (FileSizeLimitExceededException e) {
            response.getWriter().write("單個檔案不超過10M,總大小不超過100M!");
            return;
        }catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

}

二、檔案下載
response.setHeader("Content-Disposition", "attachment;filename="+URLEncoder.encode(filename,"utf-8"));
response.setContentType(this.getServletContext().getMimeType(filename));//MIME型別

 

下載示例原始碼:

package com.dzq.web;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.dzq.utils.IOUtils;


@WebServlet("/DownServlet")
public class DownServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
   
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.獲取要下載的資源的名稱
    
         String filename = request.getParameter("file");
        response.setHeader("Content-Disposition", "attachment;filename="+URLEncoder.encode(filename,"utf-8"));
        response.setContentType(this.getServletContext().getMimeType(filename));//MIME型別
        
        InputStream in = new FileInputStream(this.getServletContext().getRealPath("/"+filename));
        OutputStream out = response.getOutputStream();
        IOUtils.In2Out(in, out);
        IOUtils.close(in, null);
        //2.讀取資源
        
    }

    
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

 

相關文章