狂神說Java【網頁文件上傳案例】——不使用javaweb框架實現網頁文件上傳功能(五) —— 編寫JSP&servlet


5、編寫servlet

文件上傳JSP

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%--通過表單上傳文件--%>
    <%--注意:文件一般比較大,所以上傳文件都是使用post方式提交
                get方式只能提交4-5kb的數據,而post沒有限制
                ${pageContext.request.contextPath}:獲取到webapp路徑--%>
    <form action="${pageContext.request.contextPath}/upload.do" method="post" enctype="multipart/form-data">
        <p>上傳用戶:<input type="text" name="username"><br/></p>
        <p>上傳文件1:<input type="file" name="file1"></p>
        <p>上傳文件2:<input type="file" name="file2"></p>
        <p><input type="submit" value="點擊上傳"> | <input type="reset" value="重置"></p>


    </form>
</body>
</html>

顯示文件上傳成功的跳轉JSP頁面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>提示信息</title>
</head>
<body>
    ${msg}
</body>
</html>

servlet編寫

//這個版本將每個重要的操作都封裝成了方法,只是在doGet里面調用,層次更加清楚

package com.thhh.servlet;

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 javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.List;
import java.util.UUID;

public class FileServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {


    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("===============進入servlet================");
        //1、判斷提交的表單是普通表單還是帶上傳文件的表單
        if (!ServletFileUpload.isMultipartContent(req)){//ServletFileUpload.isMultipartContent(req)用於判斷這份表單提交的數據是不是包含文件
            return;//結束方法調用,說明這是一個普通的表單,沒有包含文件的<input>,直接返回
        }

        //2、文件存儲空間創建:創建上傳文件的路徑,建議在WEB-INF路徑下,安全,用戶無法直接訪問上傳的文件
        String uploadPath = this.getServletContext().getRealPath("/WEB-INF/upload");//獲取/WEB-INF下的/upload路徑
        File uploadFile = new File(uploadPath);//創建一個文件對象
        if (!uploadFile.exists()){
            uploadFile.mkdir();//如果這個路徑不存在,就創建這份路徑
        }

        //3、緩存空間創建:臨時路徑,假如文件超過了預期的大小,我們就把他放在一個臨時文件中,過幾天自動刪除,或者提醒用戶轉為永久
        String tmpPath = this.getServletContext().getRealPath("WEB-INF/tmp");
        File file = new File(tmpPath);
        if (!file.exists()) {
            file.mkdir();
        }
        System.out.println("===============通過了3個if================");


        DiskFileItemFactory factory = getDiskFileItemFactory(file);
        System.out.println("===============getDiskFileItemFactory================");

        ServletFileUpload upload = getServletFileUpload(factory);
        System.out.println("===============getServletFileUpload================");

        String msg = uploadParasRequest(upload, req, uploadPath);
        System.out.println("===============uploadParasRequest================");

        req.setAttribute("msg",msg);
        req.getRequestDispatcher("info.jsp").forward(req,resp);
    }

    public  DiskFileItemFactory getDiskFileItemFactory(File file){
        //直接使用我們所學的流的概念來上傳文件很低效,且我們的開發成倍很高,所以我們可以直接使用開源的包,比如Apache的文件上傳組件來實現,common-fileupload,他需要依賴於commons-io組件

        /*使用規則:
            ①ServletFileUpload負責處理上傳的文件數據,並將表單中每個輸入項封裝成一個FileItem對象, 在使用ServletFileUpload
        對象解析請求時需要DiskFileItemFactory對象。
            ②我們需要在進行解析工作前構造好DiskFileItemFactory對象,通過ServletFileUpload對象的構造方法或setFileItemFactory()
            方法設置ServletFileUpload對象的fileItemFactory屬性。*/

        //1、創建DiskFileItemFactory對象,獲取磁盤對象
        DiskFileItemFactory factory = new DiskFileItemFactory(1024*1024,file);
        return factory;
    }
    public  ServletFileUpload getServletFileUpload(DiskFileItemFactory factory){
        //2、創建ServletFileUpload對象,獲取上傳文件的解析對象
        ServletFileUpload upload = new ServletFileUpload(factory);//DiskFileItemFactory對象作為參數傳入ServletFileUpload的構造中
        return upload;
    }
    public  String uploadParasRequest(ServletFileUpload upload,HttpServletRequest req,String uploadPath) throws UnsupportedEncodingException {
        String msg = null;
        //3、正式解析表單中上傳的文件,並將其存儲在服務器上指定的位置
        try {
            List<FileItem> fileItems = upload.parseRequest(req);
            //使用文件解析對象的parseRequest()(解析request),這個方法就會將req中的表單項按照一個<input>一個FileItem對象來進行封裝
            //parseRequest(HttpServletRequest) 方法可以將通過表單中每一個HTML標簽提交的數據封裝成一個FileItem對象,然后以List列表的形式返回

            for (FileItem fileItem : fileItems) {//遍歷,找到表單中每一個文件對應的<input>上傳的文件數據
                if (fileItem.isFormField()) { //這個<input>中的數據不是文件
                    String name = fileItem.getFieldName();//獲取非文件<input>的name屬性
                    String value = fileItem.getString("utf-8");//獲取非文件<input>的value屬性
                    System.out.println(name + ":" + value);//輸出顯示
                }else { //這個<input>中的數據是文件

                    //===============1、處理文件:獲取文上傳的文件的文件名+文件類型===============

                    String uploadFileName = fileItem.getName();//獲取這個文件的名稱
                    System.out.println("上傳的文件名:" + uploadFileName);
                    if (uploadFileName.trim().equals("") || uploadFileName == null) {//如果文件上傳的名字為空
                        continue;//跳過本次循環繼續下一個List元素的遍歷
                    }
                    //精妙點:獲取文件的名稱
                    //獲得上傳的文件名 /images/girl/paojie.jpg
                    String fileName = uploadFileName.substring(uploadFileName.lastIndexOf("/") + 1);//獲取最后一個/后面的所有字符串,獲取結果 = 文件名.文件類型
                    String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".") + 1);//最后一個"."后面的字符串,獲取結果 = 文件類型
                    System.out.println("文件信息[文件名:" + fileName + "----文件類型" + fileExtName+"]");//打印輸出對文件進行查看


                    //=====================2、處理文件存放地址:/WEB-INF/upload + 文件上傳時生成的唯一的UUID===============

                    //可以使用UUID(可以唯一識別的通用碼),保證文件名唯一;UUID.randomUUID(),隨機生成一個唯一的識別通用碼;
                    String uuidPath = UUID.randomUUID().toString() ;

                    //存到哪?uploadPath
                    //文件真正要存儲在服務器上的存在的路徑realPath = /WEB-INF/upload + 文件上傳時生成的唯一的UUID
                    String realPath = uploadPath + "/" + uuidPath;
                    //給每個文件創建一個對應的文件夾
                    File realPathFile = new File(realPath);
                    if (!realPathFile.exists()) {
                        realPathFile.mkdir();   //一般這個文件存儲的文件夾都是不存在的,所以一定會為我們的上傳文件創建一個新的文件夾來存儲它
                    }

                    //============================3、文件傳輸:配合工具類fileName+文件IO操作就可以實現文件存儲在服務器上============================

                    InputStream in = null;//每次遍歷到的都是一個獨立的、完整的文件對應的fileItem對象,所以我們只需要從它里面獲取數據流再存儲下來即可
                    try {
                        in = fileItem.getInputStream();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    //創建一個文件輸入流
                    FileOutputStream fos = new FileOutputStream(realPath + "/" + fileName);//獲取文件輸入流
                    //文件名還是和原來保持不變,只是文件存儲的上一級文件夾的名稱是我們通過/WEB-INF/upload + 文件上傳時生成的唯一的UUID生成的不重復的
                    byte[] buffer = new byte[1024];//創建一個緩沖區
                    int len = 0;//定義一個變量存儲一次讀到的實際數據量
                    while ((len = in.read(buffer)) > 0) {//通過判斷實際讀取的數據量是不是>0就可以判斷文件是不是讀完了
                        fos.write(buffer, 0, len);//將文件流寫到這個文件中 ——“realPath + "/" + fileName”
                    }
                    //關閉流
                    in.close();
                    fos.close();

                    msg="文件上傳成功!";
                    fileItem.delete();//上傳成功,清除臨時文件
                }

            }
        } catch (FileUploadException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return msg;
    }
}

6、測試




注意:上面的目錄只是我們編寫代碼的文件目錄,而我們點擊項目發布之后,IDEA會產生一個target文件夾

功能完成!
為了進一步驗證可以去對應的文件夾中查看


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM