註明:以下都是本人自己測試的,能夠實現文件上傳和下載,代碼中也有較爲詳細的標註,如果有興趣的話,可以自己也測試一下
一、前提摘要
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.文件下載操作及展示效果
- 在瀏覽器中訪問 http://localhost:8080/servlet/upload.jsp 該路徑
- 點擊下載圖片鏈接
- 下載圖片成功圖示
2.文件下載的流程
- 首先我們要知道,我們是通過Servlet,以二進制流的方式向頁面輸出文件,進行的下載操作
- 首先獲取要下載的文件名(這裏比如我們放入在項目裏images文件夾裏的圖片資源)
- 讀取要下載的文件內容(輸入流中全部的數據),文件內容在war包裏的images路徑下。我的理解就是將本地的文件內容通過輸入流的操作,將資源寫入到tomcat服務器中,不知道對不對。
- 把下載的文件內容回傳給客戶端(瀏覽器),將輸入流中的全部的數據,複製給輸出流,從而輸出給客戶端(瀏覽器)
- 把下載的文件內容回傳給客戶端(瀏覽器)之前,要通過響應頭告訴客戶端返回的數據類型(我這裏統一設置成流的類型,這裏瀏覽器界面顯示下載文件的內容,但是沒有進行下載操作,比如圖片只是顯示在界面上,沒有下載)
- 要在瀏覽器中進行下載下來,還要告訴客戶端(瀏覽器)收到的數據是用於下載使用(設置響應頭,這裏要注意的是,文件名我做了些處理,各種瀏覽器都能支持中文名的下載操作)
如果對你有幫助,不如點個贊,也算是支持一下0.0
若有不正之處,請多多諒解並歡迎批評指正,不甚感激