javaWeb中文件上傳和下載

註明:以下都是本人自己測試的,能夠實現文件上傳和下載,代碼中也有較爲詳細的標註,如果有興趣的話,可以自己也測試一下

一、前提摘要

1.需要用到的

  • idea
  • jsp頁面
  • servlet組件
  • tomcat容器
  • commons-fileupload-1.3.1.jar和commons-io-2.4.jar兩個jar包(因爲文件要上傳,上傳到服務器,服務器進行接收讀取就需要流的操作)

2.Servlet運行過程

  • 瀏覽器發送請求服務器(tomcat)
  • 服務器(tomcat)將請求信息(請求頭,請求參數)進行封裝,變成HttpServletRequest對象
  • 同時根據請求信息創建響應對象HttpServletResponse
  • 根據請求地址,找到對應的資源或者對應Servlet類(根據web.xml配置或註解等配置)
    • 匹配成功,響應對應的資源或者執行對應Servlet的方法
    • 匹配失敗,返回404
  • 將響應結果返回給瀏覽器

二、文件上傳和下載測試代碼

1.測試模塊目錄結構圖示

  • 馬賽克部分是沒有用到的代碼,不需要寫
    模塊目錄結構

2.測試代碼

  • 訪問請求路徑這裏使用的是註解版
  • UploadServlet類裏的方法包含了文件上傳下載的方法
  • 這裏重寫service方法後,不能重寫doGet、doPost方法。service能處理所有類型的請求。如果你要重寫doGet、doPost方法來測試文件上傳和下載,該測試案例你要修改一下。因爲特定的方法處理特定的請求類型,doGet處理GET請求,doPost處理POST請求
package com.huming.servlet;


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

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.List;
import java.lang.String;

@WebServlet("*.file")
public class UploadServlet extends HttpServlet {
    //重寫了service方法後,不能重寫doGet、doPost方法
    //service處理所有類型的請求
    //重寫特定的方法處理特定的請求類型,doGet處理GET請求,doPost處理POST請求
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //獲取當前servlet的路徑
        String servletPath = req.getServletPath();
        System.out.println("servletPath="+servletPath);  //servletPath=/upload.file
        if ("/upload.file".equals(servletPath)){
            upload(req,resp);
        }
        if ("/download.file".equals(servletPath)){
            download(req,resp);
        }

    }


    /**
     * 用來處理上傳的數據
     * @param req
     * @param resp
     */
    private void upload(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        System.out.println("文件上傳過來了");

        /**
         * 自己解析太麻煩,所以使用第三方解析工具,第三方工具解析請求流
         */
        //1.先判斷上傳的數據是否是多段數據(只要是多段的數據,纔是文件上傳)
        if (ServletFileUpload.isMultipartContent(req)){
            //1.創建FileItemFactory工廠實現類,磁盤文件項的工廠
            FileItemFactory fileItemFactory = new DiskFileItemFactory();
            //2.創建Servlet文件上傳對象,用於解析上傳數據的工具類servletFileUpload
            ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);
            //解析上傳的數據,得到每一個表單項FileItem
            try {
                //3.解析請求流
                //會把每個參數封裝成一個FileItem對象
                List<FileItem> list = servletFileUpload.parseRequest(req);
                //業務操作,獲取參數
                for (FileItem fileItem : list){
                    if (fileItem.isFormField()){
                        //普通表單項
                        System.out.println("表單項的name屬性值:"+fileItem.getFieldName());
                        //如果是中文,參數utf-8解決亂碼問題,就是input標籤輸入框的值
                        System.out.println("表單項的value屬性值:"+fileItem.getString("UTF-8"));
                    }else{
                        //上傳的文件
                        System.out.println("表單項的name屬性值:"+fileItem.getFieldName());
                        System.out.println("上傳文件類型爲:"+fileItem.getContentType());


                        //保存在應用對象獲取應用所在的絕對路徑
                        //如果有參數,表示獲取,應用根目錄下的該文件夾的絕對路徑
                        String fileName = fileItem.getName();
                        System.out.println("上傳的文件名:" + fileName);
                        String newName = System.currentTimeMillis() + fileName;
                        //取得應用絕對路徑
                        String addPath = req.getServletContext().getRealPath("");
                        System.out.println("addPath=" + addPath);   //D:\Document\JavaExample\MyWeb1\out\artifacts\servlet_war_exploded\
                        String filePath = addPath + "/imgs";
                        File parent = new File(filePath);
                        parent.mkdirs();

                        File file = new File(parent, newName);
                        //將文件保存到指定的地方
                        fileItem.write(file);

                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 用來處理下載數據的操作
     * @param req
     * @param resp
     */
    private void download(HttpServletRequest req, HttpServletResponse resp) throws IOException {

        //1.獲取要下載的文件名
        String downloadFileName = "風景.jpg";

        //4.設置響應類型application/octet-stream  二進制流
        //在回傳前,通過響應頭告訴客戶端返回的數據類型
        resp.setContentType("application/octet-stream");

        //5:告訴客戶端收到的數據是用於下載使用
        //Content-Disposition響應頭   表示收到的數據怎麼處理
        //attachment   表示附件,表示下載使用
        //filename=  表示指定下載的文件名,可以改任何名字,爲了相同就寫原資源的文件名
        String cd = "attachment;filename=" + downloadFileName;
        String d = new String(cd.getBytes("UTF-8"), "ISO-8859-1");
        resp.addHeader("Content-Disposition", d);

        //通過應用對象獲取應用所在的絕對路徑
        //如果有參數,表示獲取應用根目錄下的該文件夾的絕對路徑
        String addPath = req.getServletContext().getRealPath("");
        System.out.println("addPath=" + addPath);
        //2.讀取輸入流中全部的數據
        FileInputStream fileInputStream = new FileInputStream(new File(addPath + "/images/" + downloadFileName));

        try {
            //獲取響應的輸出流
            ServletOutputStream outputStream = resp.getOutputStream();
            //3.把下載的文件內容回傳給客戶端
            //讀取輸入流中全部的數據,複製給輸出流。輸出給客戶端
            IOUtils.copy(fileInputStream,outputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

  • upload.jsp(前端頁面代碼)
<%--
  Created by IntelliJ IDEA.
  User: 11602
  Date: 2020/3/8
  Time: 11:24
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/upload.file" method="post" enctype="multipart/form-data">
    用戶名:<input type="text" name="username">
    <br>
    頭像:<input type="file" name="photo">
    <br>
    <input type="submit" value="上傳">
    <br>
    <a href="${pageContext.request.contextPath}/download.file">下載圖片</a>
</form>
</body>
</html>

三、文件上傳(upload)

1.實現文件上傳的要求

  • jsp前端頁面中,要有一個form標籤,method必須爲post請求(get請求在URL中傳遞的參數是有長度限制的,而POST沒有長度限制)
  • form標籤的encType屬性值必須multipart/form-data值,不然實現不了文件上傳(enctype="multipart/form-data" 表示提交的數據,以多段的形式進行拼接,然後以二進制流的形式發送給服務器)
  • 在form標籤中使用input type=file添加上傳的文件
  • 編寫服務器代碼來進行接收(Servlet程序編寫),處理上傳的數據

2.文件上傳實際操作及展示效果

  • 在瀏覽器中訪問 http://localhost:8080/servlet/upload.jsp 該路徑
  • 填入用戶名tom
  • 選擇一張圖片(實際選擇文本也行,什麼格式的都可以,因爲它會識別上傳的是什麼類型的文件格式)
  • 點擊上傳按鈕

  • 前端頁面展示:
    前端頁面展示
  • 點擊上傳時,idea控制檯輸出情況:
    控制檯輸出信息
  • 上傳資源到的路徑:
    文件上傳到的路徑

3.文件上傳的流程

  • 點擊前端頁面上傳按鈕,跳轉到servlet中的upload方法
  • 判斷上傳的數據是否是多段數據(只要是多段的數據,纔是文件上傳,標誌:enctype="multipart/form-data"
  • 創建磁盤文件項的工廠
  • 創建Servlet文件上傳對象,用於解析上傳數據的工具類servletFileUpload
  • 解析請求流,解析上傳的數據,會把每個參數(例如這裏的用戶名和用戶頭像)封裝成一個FileItem對象
  • 集合進行遍歷,獲取參數,如果是普通表單項(這裏是用戶名),獲取屬性值(這裏是你輸入的用戶名)。如果是上傳的文件,獲取應用根目錄下的該文件夾的絕對路徑(war包裏的路徑),將上傳的文件寫入到絕對路徑中的再下一級imgs文件夾中(沒有則自動創建)
  • 操作執行完成,可以在war包裏看到自動創建的imgs文件夾,還有上傳的圖片資源

四、文件下載(download)

1.文件下載操作及展示效果

2.文件下載的流程

  • 首先我們要知道,我們是通過Servlet,以二進制流的方式向頁面輸出文件,進行的下載操作
  • 首先獲取要下載的文件名(這裏比如我們放入在項目裏images文件夾裏的圖片資源)
  • 讀取要下載的文件內容(輸入流中全部的數據),文件內容在war包裏的images路徑下。我的理解就是將本地的文件內容通過輸入流的操作,將資源寫入到tomcat服務器中,不知道對不對。
  • 把下載的文件內容回傳給客戶端(瀏覽器),將輸入流中的全部的數據,複製給輸出流,從而輸出給客戶端(瀏覽器)
  • 把下載的文件內容回傳給客戶端(瀏覽器)之前,要通過響應頭告訴客戶端返回的數據類型(我這裏統一設置成流的類型,這裏瀏覽器界面顯示下載文件的內容,但是沒有進行下載操作,比如圖片只是顯示在界面上,沒有下載)
  • 要在瀏覽器中進行下載下來,還要告訴客戶端(瀏覽器)收到的數據是用於下載使用設置響應頭,這裏要注意的是,文件名我做了些處理,各種瀏覽器都能支持中文名的下載操作)

如果對你有幫助,不如點個贊,也算是支持一下0.0
若有不正之處,請多多諒解並歡迎批評指正,不甚感激

參考資料

文件上傳與下載

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章