1. 程式人生 > 實用技巧 >javaweb-檔案的上傳下載

javaweb-檔案的上傳下載

本文用到的jar包:

檔案上傳:commons-fileupload-1.2.1.jar;

commons-io-1.4.jar;

本文需要掌握的知識:html+dom

1檔案的上傳概述;

1.1使用者把本地的檔案儲存到伺服器上,就是檔案的上傳;

1.2實現檔案的上傳(目前而言要使用第三方jar包);

1.2.1 jspSmartupload;

適用範圍:應用在jsp的模型一里(嵌入執行上傳下載操作的JSP檔案中) ;

1.2.2 fileUpload;

來源:Apache commons下面的開源,免費專案(謝謝老闆);

適用範圍:(mvc模式);

1.3要使用檔案的上傳,需要滿足三個要求:

①表單資料提交,提交方式為post提交;

②在表單裡有一個檔案的上傳想<input type=”file”name=”filename”/>

③在form裡面,要設定一個屬性值,enctype,設定為multipart/form-data(必須設定,不然只有一個檔名之類的)

2 檔案上傳的原理分析:

從請求響應資訊可知;

Content-Type:multipart/form-data;

通過請求正文可以得到結論:

①找到分割線;

②根據分割線區別不同的項;

③普通輸入項得到的是值;

④檔案上傳項,得到檔案的內容,把內容寫到伺服器裡面一個檔案中;

⑤使用輸入流得到檔案上傳的內容,使用輸出流把檔案的內容寫到伺服器上;

3,檔案上傳的程式碼實現的步驟(固定步驟,照著寫就可以了);

3.1 :建立磁碟檔案工廠;

new DiskFileItemFactory();

3.2:建立核心上傳類;

new ServletFileUpload(FileItemFactory fileItemFactory);

3.3:使用核心上傳類解析request物件;

parseRequest(-----request(全類名就不寫了));

返回的是一個List集合,集合中有多個FileItem,泛型為<FileItem>;

3.4:遍歷list集合,得到每個FileItem;

3.5:判斷是普通輸入項還是檔案上傳項;

Boolean isFormField();

3.6:如果是普通輸入項;如果是檔案上傳項編寫檔案上傳的程式碼;

普通輸入項:

getField():得到普通輸入項name的值;

getString():得到普通輸入項裡面輸入的值;

檔案上傳項:

得到通過表單提交的檔案的輸入流,getInputStream;

建立輸出流,寫出檔案到伺服器的相應的位置(輸出位置要帶有碟符,通過

getServletContext().getRealPath(相對路徑)可以獲取.為什麼要這樣做,是因為專案在別的伺服器上真實路徑就不一定一致了,所以要通過相對路徑獲取到真實路徑);

4,核心API的學習(主要是一些重要的方法);

4.1 DiskFileItemFactory(磁碟檔案項工廠)(核心上傳類,重點在於構造);

構造方法;

DiskFileItemFactory(int sizeThreshold,java.io.File repository);

兩個引數:

第一個引數設定上傳檔案緩衝區的大小;

第二個引數.如果上傳檔案超出了緩衝區,產生臨時檔案,設定臨時檔案路徑

(可以看做是先用一個等大小的臨時檔案做佔位,然後資料一步步填充);

DiskFileItemFactory()無參構造,也可以設定緩衝區;

setSizeThreadshold(int sizeThreadshold):設定上傳檔案的緩衝區(單位是位元組byte);

setRepository(java.io.File repository):設定臨時檔案路徑;

4.2 ServletFileUpload:核心上傳類;

構造方法;

ServletFileUpload(FileItemFactory fileItemFactory);

重要方法:;

parseRequest(javax.servlet.HttpServletRequest request):解析request物件;

返回一個list<FileItem>集合,每一個元素都是一個FileItem;

在他的父類中還有一個很重要的方法;

setHeaderEncoding(java.lang.String encoding);設定上傳檔名稱的編碼;

setFileSizeMax(long filesizeMax)”:設定單個檔案的大小;

setSIzeMax(long sizeMax):設定單個檔案的總大小;

4.3 FileItem:檔案項

Boolea isFormField():判斷是否是普通輸入項;

getFieldName():得到普通輸入項.name的屬性值;

getString():得到普通輸入項的文字值;

getString(encoding):設定輸入項中文字的編碼;

getName():得到上傳檔案的名稱(但是有些瀏覽器得到的帶路徑的名稱,所以要進行擷取操作,哭);

getInputStream():得到表單提交的檔案輸入流;

Delete():刪除臨時檔案(要在關閉流之後刪除);

5 JS控制多檔案的上傳

5.1需求:在上傳的表單裡面有兩個按鈕,一個是上傳檔案的按鈕,一個是增加的按鈕,增加上傳項.

點選增加按鈕之後,增加一行,一個上傳輸入項和一個刪除的按鈕

點選刪除按鈕之後,刪除該行

點選上傳按鈕之後,把當前的檔案上傳到伺服器裡面去

5.2使用js增加一行和刪除一行

<script type="text/javascript">

//增加一行

function addFile(){

//在table裡面增加一行

var table = document.getElementsByTagName("table")[0];

table.innerHTML+="<tr><td><input type='file' name='filename'/></td><td><input type='button' value='刪除' onclick='dele(this)'/><td/><tr/> ";

}

//刪除一行

function dele(who){

//獲取當前點選的刪除按鈕所在的tr

var tr=who.parentNode.parentNode;

//拿到爸爸

var table=tr.parentNode;

//通過爸爸刪除兒子

table.removeChild(tr);

}

</script>

5.3使用button提交表單的方法

//通過按鈕提交表單實現上傳

function uploadFile(){

var form =document.getElementsByTagName("form")[0];

form.submit();

}

5.4常見問題的解決:

5.4.1當已經存在名字重複的檔案,再次上傳會新檔案覆蓋原檔案

解決方式:在上傳的檔名稱裡新增一個隨機的唯一的字串,保證每個檔案都是唯一的值(可以通過uuid生成,也可以使用毫秒數,不過推薦用uuid更加保險

//生成一個隨機的唯一的id值

String id = UUID.randomUUID().toString();

JSP頁面(為什麼我沒找到jsp程式碼選擇)

<%@ 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>
    <form action="${pageContext.request.contextPath }/servlet/Upload2" method="post"  enctype="multipart/form-data">
        <input type="button" value="上傳" onclick="uploadFile()"/>
        <input type="button" value="增加" onclick="addFile()"/><hr/>
        <table>
            
        </table>
        <%--
        <input type="file" name="filename"/><input type="button" value="刪除"/> 
        --%></form>
</body>
<script type="text/javascript">
    //通過按鈕提交表單實現上傳
    function uploadFile(){
        var form =document.getElementsByTagName("form")[0];
        form.submit();
    }
    //增加一行
    function addFile(){
        //在table裡面增加一行
        var table = document.getElementsByTagName("table")[0];
        table.innerHTML+="<tr><td><input type='file' name='filename'/></td><td><input type='button' value='刪除' onclick='dele(this)'/><td/><tr/> ";
    }
    //刪除一行
    function dele(who){
        //獲取當前點選的刪除按鈕所在的tr
        var tr=who.parentNode.parentNode;
        //拿到爸爸
        var table=tr.parentNode;
        //通過爸爸刪除兒子
        table.removeChild(tr);
    }
</script>
</html>

servlet處理頁面(對應的圖片檔案就不放上來了)

package com.zzx.upload;

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.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

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

public class Upload2 extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try {
            //1,建立磁碟檔案工廠
            DiskFileItemFactory dff = new DiskFileItemFactory();
            //2,建立核心上傳類
            ServletFileUpload fileupload = new ServletFileUpload(dff);
            fileupload.setHeaderEncoding("utf-8");
            //3,解析對應的請求資料
            List<FileItem> fl = fileupload.parseRequest(request);
            for (FileItem fileItem : fl) {
                 //判斷是否是普通輸入項
                if(fileItem.isFormField()){
                    //如果是普通輸入項,就得到普通輸入項name的屬性值,和輸入的值
                    String name = fileItem.getFieldName();
                    String value = fileItem.getString();
                    System.out.println(name + ":" + value);
                }else{
                    //如果是檔案上傳項
                    //獲取上傳的檔名稱,但是有的瀏覽器裡面帶的是帶路徑的名稱
                    String filename = fileItem.getName();
                    //優化,判斷是否帶/,如果帶"/"就進行擷取,否則就直接用
                    int lens=filename.lastIndexOf("/");
                    if(lens!=-1){
                        filename=filename.substring(lens+1);
                    }
                    //獲取檔案上傳的輸入流
                    InputStream is =fileItem.getInputStream();
                    //得到資料夾帶碟符的路徑
                    String path = getServletContext().getRealPath("/upload");
                    //輸出流
                    OutputStream os =new FileOutputStream(path + "/" + filename);
                    //流對接
                    int len=0;
                    byte[]arr =new byte[1024*8];
                    while((len = is.read(arr))!=-1){
                        os.write(arr,0,len);
                    }
                    //關流
                    is.close();
                    os.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

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

        doGet(request, response);
    }

}

6檔案的下載:

6.1把伺服器上檔案儲存到本地硬碟,這個過程稱為檔案的下載

6.2檔案下載的實現方式:

6.2.1: 實現超連結的檔案下載

弊端:有的檔案無法實現下載,而是顯示在頁面上(比如圖片)

6.2.2: 通過程式碼實現檔案下載

無論什麼格式的檔案都可以下載

實現步驟:

第0步:設定要下載的檔案MIME型別(可選)

第一步:設定頭資訊,Content-Disposition,無論什麼格式,都是以下載的方法開啟

第二步:伺服器得到檔案的輸入流

第三步:建立輸出流,寫出到瀏覽器

第四步:流對接

具體程式碼:

6.3常見問題:

6.3.1當檔名攜帶中文的時候(中文名稱會亂碼,不顯示之類的問題)

6.3.2原因:不同瀏覽器編碼不同

ie瀏覽器採用的是url編碼,

火狐瀏覽器採用的是base64編碼,

6.3. 3 ① 區分不同的瀏覽器

通過請求頭User-Agent,得到當前瀏覽器的請求型別

②根據不同的瀏覽器設定不同的編碼(IE,谷歌解決方式一致)

這裡是檔案下載的頁面

package com.zzx.down;

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.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import sun.misc.BASE64Encoder;

import com.sun.xml.internal.messaging.saaj.util.Base64;
/*
 * 這個頁面是實現檔案的下載
 */
public class DownServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
            //0,得到檔案的路徑
        String path = getServletContext().getRealPath("/down/圖片.jpg");
            //得到檔名
            //這裡尋找"/"要注意使用"\\"才能正確的擷取
        String filename = path.substring(path.lastIndexOf("\\")+1);
        //得到請求的瀏覽器型別
        String agent = request.getHeader("User-Agent");
        //判斷瀏覽器型別
        System.out.println(agent);
        if(agent.contains("Firefox")){
            //如果是火狐,進行base64編碼
            filename = "=?UTF-8?B?"+new BASE64Encoder().encode(filename.getBytes("utf-8")) + "?=";
        }else{
            //url編碼,谷歌,IE都可以通過這樣設定
            filename=URLEncoder.encode(filename, "UTF-8");
        }
            //1,設定檔案的mime型別
            //先得到檔案的mime型別
        String type = getServletContext().getMimeType(filename);
            //設定
        response.setContentType(type);
        response.setHeader("Content-Disposition", "attachment;filename=" + filename);
           //得到輸入流
        InputStream is = new FileInputStream(path);
           //得到輸出流
        OutputStream os = response.getOutputStream();
           //2,流對接
        int a=0;
        byte[]arr =new byte[1024*8];
        while((a = is.read(arr))!=-1){
            os.write(arr,0,a);
        }
        //3,關流
        os.close();    //會自動關閉,不過要養成關流的習慣
        is.close();
        
    }

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

        doGet(request, response);
    }

}