1. 程式人生 > >檔案上傳和下載

檔案上傳和下載

檔案的上傳和下載

檔案上傳

檔案上傳的三要素

  • 提供form表單,method必須是post
  • form表單的enctype必須是multipart/form-data
  • 提供 input type = “file” 型別輸入

檔案上傳注意的細節

  1. 為保證伺服器安全,上傳檔案應該放在外界無法直接訪問的目錄下,比如放在WEB-INF下。
  2. 為了防止檔案覆蓋的現象發生,要為上傳的檔案產生一個唯一的檔名。
  3. 為防止一個目錄下出現太多檔案,要使用hash打亂演算法儲存
  4. 要限制上傳檔案的最大值
  5. 要限制上傳檔案的型別,在收到上傳檔名時,判斷後綴名是否合法

實現檔案上傳

1.編寫上傳頁面form表單

<form id="form1" action="${pageContext.request.contextPath }/upfileservlet" method="post" enctype="multipart/form-data">
        使用者名稱:<input type="text" name="username" /><br>
        電話:<input type="text" name="telphone" /><br>
        檔案:<input type="file" name="file"
/>
<br> <input type="button" value="再新增一張圖片" onclick="addfile(this)"><br/> <input type="submit" value="提交" /> </form> <script type="text/javascript"> var num=2; function addfile(obj){ //alert("xxx"); //dom操作 //新增div
var div1=document.createElement("div"); //新增input標籤 var inputfile=document.createElement("input"); inputfile.type="file"; inputfile.name="myfile"+num; num++; //新增刪除按鈕 var del=document.createElement("input"); del.type="button"; del.value="刪除"; del.onclick=function(){ this.parentNode.remove(); }; div1.append(inputfile); div1.append(del); var form1=document.getElementById("form1"); form1.insertBefore(div1,obj); }
</script>

2.編寫servlet處理介面

    /**
     * 處理檔案上傳的方法
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");

        // 得到上傳路徑,將上傳的路徑放入WEB-INF下,不予許外界訪問,保證上傳檔案的安全性
        String path = request.getServletContext().getRealPath("WEB-INF//upload");

        File file = new File(path);
        // 如果檔案不存在就建立
        if (!file.exists()) {
            file.mkdirs();
        }

        // 建立DiskFileItemFactory工廠
        DiskFileItemFactory factory = new DiskFileItemFactory();

        // 設定工廠緩衝大小
        factory.setSizeThreshold(1024 * 100);// 預設為10K
        // 設定上傳檔案的快取目錄
        // factory.setRepository(repository);

        // 建立一個檔案解析器
        ServletFileUpload upload = new ServletFileUpload(factory);

        // 解決中文亂碼問題
        upload.setHeaderEncoding("utf-8");
        // 監聽上傳檔案的進度
        upload.setProgressListener(new ProgressListener() {

            @Override
            public void update(long arg0, long arg1, int arg2) {
                System.out.println("檔案大小為:" + arg1 + ",當前已處理:" + arg0 + ",序號:" + arg2);

            }
        });

        // 判斷提交的資料是不是表單資料
        if (ServletFileUpload.isMultipartContent(request)) {
            try {
                // 設定上傳單個檔案的大小
                upload.setFileSizeMax(1024 * 100);// 大小為100KB
                // 設定所有檔案總量的最大值
                upload.setSizeMax(1024 * 1024 * 10);// 大小為10M

                // 解析資料,放回一個list集合,存放資料項
                List<FileItem> fileItems = upload.parseRequest(request);
                for (FileItem fileItem : fileItems) {

                    // 判斷是不是普通輸入項的資料
                    if (fileItem.isFormField()) {
                        // 獲得資料項的名字
                        String name = fileItem.getFieldName();
                        String value = fileItem.getString("utf-8");
                        System.out.println(name + "..." + value);
                    } else {// 封裝的是檔案

                        // 得到上傳檔案的名字
                        String name = fileItem.getName();

                        // 如果檔名為空
                        if (name == null || name.trim().equals("")) {
                            continue;
                        }

                        // 不同的瀏覽器傳入的名字可能存在路徑,解決檔名帶有路徑問題
                        String filename = name.substring(name.lastIndexOf("\\") + 1);
//控制檔案傳的型別
                        String ext = filename.substring(filename.lastIndexOf(".")+1);
                        if (!UUIDUtils.exts.contains(ext)) {
                            response.getWriter().write("檔案型別不支援");
                            return;
                        }

                        // 呼叫工具類,得到唯一標識
                        String fileName = UUIDUtils.getFileName(filename);
                        // 呼叫工具類,得到目錄
                        String newPath = UUIDUtils.makeFilePath(filename, path);

                        // 獲得輸入流
                        InputStream is = fileItem.getInputStream();
                        FileOutputStream fos = new FileOutputStream(newPath + "\\" + fileName);
                        // 寫入硬碟
                        byte[] bs = new byte[1024];
                        int len = 0;
                        while ((len = is.read(bs)) != -1) {
                            fos.write(bs, 0, len);
                        }
                        // 關流
                        fos.close();
                        is.close();
                        // 刪除檔案上傳時生成的臨時檔案
                        fileItem.delete();
                        System.out.println("檔案上傳成功");
                    }
                }

            } catch (FileUploadException e) {

                e.printStackTrace();
                System.out.println("檔案上傳失敗");
            }

        } else {
            // 正常處理
            // request.getParameter("username");
        }

    }

3.編寫工具類

/**
 * uuid工具類
 * @author 15216
 *
 */
public class UUIDUtils {
    //建立集合儲存檔案的型別
    public static List<String> exts;
    //靜態程式碼塊初始化檔案的型別
    static {
        exts = new ArrayList<String>();
        //exts.add(".jpg");
        exts.add(".png");
        exts.add(".zip");
    }

    public static String getFileName(String filename) {

        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        return uuid+"_"+filename;
    }

    public static String makeFilePath(String filename,String filepath) {
        //得到字串的hascode值
        int code = filename.hashCode();

        //0x十六進位制字首
        int  dir1 = code&0xf;//得到後四位二進位制數
        int code1 = code>>4;//右移四位
        int dir2=code1&0xf;//得到後八位的前四位

        String path = filepath+"\\"+dir1+"\\"+dir2;
        File file = new File(path);
        if (!file.exists()) {
            file.mkdirs();
        }
        return path;
    }
}

servlet3.0支援的檔案上傳

程式碼實現


//註解配置檔案上傳的最大值
@MultipartConfig(fileSizeThreshold=1024*1024,maxFileSize=1024*100,maxRequestSize=1024*1024 )

/**
 * servlet3.0
 */ 
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //設定編碼
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");
        //獲取路徑
        String path = request.getServletContext().getRealPath("WEB-INF//upload");
        File file = new File(path);
        if (!file.exists()) {
            file.mkdirs();
        }

        //接收資料
        Collection<Part> parts = request.getParts();
        if (parts!=null) {
            for (Part part : parts) {
                //獲取檔名
                String fileName = part.getSubmittedFileName();
                //如果為空不是檔案
                if (fileName!=null) {//是檔案
                    if (fileName.trim().equals("")) {
                    continue;
                    }

                    //form-data; name="myfile1"; filename="D:\圖片\timg.jpg"
                    String header = part.getHeader("content-disposition");
                    System.out.println(header);
                    String name1 = header.split("; ")[2];//filename="D:\圖片\timg.jpg"
                    System.out.println(name1);//"D:\圖片\timg.jpg"
                    String name2 = name1.substring(name1.indexOf("\"")+1, name1.length()-1);
                    fileName = name2.substring(name2.lastIndexOf("\\")+1);

                    System.out.println(fileName);

                    //為檔名產生一個唯一標識
                    String filename = UUIDUtils.getFileName(fileName);
                    String filepath = UUIDUtils.makeFilePath(filename, path);

                    part.write(filepath+"\\"+filename);
                    System.out.println("檔案上傳成功");

                }else {
                    //獲取普通資料的名字
                    String name = part.getName();
                    String value = request.getParameter(name);
                    System.out.println(name+"..."+value);
                }
            }
        }
    }

檔案下載

思想:首先需要編寫一個ListFileServleDt列出檔案目錄下的所有的檔案,在jsp檔案中提供超連結的方式給使用者進行下載操作,然後編寫DownServlet實現下載操作。

編寫ListFileServlet



protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //獲取檔案路徑
        String path = request.getServletContext().getRealPath("WEB-INF//upload");
        File file = new File(path);
        Map<String, String> map = new HashMap<String, String>();
        listFile(file, map);

        //將集合放入request中
        request.setAttribute("map", map);
        //轉發到列表jsp,資料不會丟失
        request.getRequestDispatcher("/listfile.jsp").forward(request, response);

    }
    /**
     * 通過遞迴將目標目錄下的檔案全部存到map集合中
     * @param dir
     * @param map
     */
    public void listFile(File dir,Map<String, String> map) {
        File[] files = dir.listFiles();
        if (files!=null) {
            for (File file : files) {
                //判斷是不是目錄
                if (file.isDirectory()) {
                    listFile(file, map);
                }else {
                    //得到檔案的名字
                    String uuid_name = file.getName();//uuid_xxx.jpg
                    //擷取檔案的名字
                    String realname = uuid_name.substring(uuid_name.indexOf("_")+1);
                    //將得到檔案的名字作為key值,將realname作為值存入集合
                    map.put(uuid_name, realname);
                }

            }
        }
    }

編寫listfile.jsp頁面

<body>  
    <h2>下載</h2>
    <c:forEach items="${map }" var="entry">
    <!-- 建立一個地址,並放入域中 1、URL重寫2、中文編碼 -->
        <c:url var="myurl" value="/downfileservlet">
            <c:param name="filename" value="${entry.key }"></c:param>
        </c:url>
        ${entry.value } <a href="${myurl }">下載</a>
    </c:forEach>
</body>

編寫downFileServlet


    /**
     * 檔案下載
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //設定編碼
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");

        //接收要下載的檔名
        String filename = request.getParameter("filename");

        //得到路徑名
        String path = request.getServletContext().getRealPath("WEB-INF//upload");

        if (filename==null||filename.trim().equals("")) {
            return;

        }


        //獲取檔案在upload中的位置
        String name = filename.substring(filename.indexOf("_")+1);
        //傳入的是包含唯一編碼的檔名
        String filepath = UUIDUtils.makeFilePath(filename, path);

        File file = new File(filepath+"\\"+filename);
        System.out.println(file);
        if (!file.exists()) {
            response.getWriter().write("檔案不存在");
            return;
        }


        //設定頭
        response.setHeader("content-disposition", "attachment;filename"+URLDecoder.decode(name,"utf-8"));
        ServletOutputStream os = response.getOutputStream();
        FileInputStream fis = new FileInputStream(file);

        int len = 0;
        byte[] bs = new byte[1024];
        while((len = fis.read(bs))!=-1) {
            os.write(bs,0,len);
        }
        fis.close();


    }