看完再也不擔(dān)心不會文件的上傳與下載了!(建議收藏)
一、文件的上傳
將用戶本地磁盤中的文件提交保存到服務(wù)器中的磁盤上。
1.1、存在的問題.
我們要做文件上傳,一般的步驟是:
要有一個(gè) form 標(biāo)簽,method=post 請求。因?yàn)間et請求里面限制了大小。
form 標(biāo)簽的 encType 屬性值必須為 multipart/form-data 值。
在 form 標(biāo)簽中使用 input type=file 添加上傳的文件。
編寫服務(wù)器代碼(Servlet 程序)接收,處理上傳的數(shù)據(jù)。
encType=multipart/form-data 表示提交的數(shù)據(jù),以多段(每一個(gè)表單項(xiàng)一個(gè)數(shù)據(jù)段)的形式進(jìn)行拼
接,然后以二進(jìn)制流的形式發(fā)送給服務(wù)器。
我們通過寫代碼可以發(fā)現(xiàn),enctype=“multipart/form-data” 提交的數(shù)據(jù),getParameter() 無法獲取到。
1.2、Servlet3.0 文件上傳
既然文件上傳如此頭疼,那么總該有人挺身而出幫我們解決這個(gè)難題。Servlet 3.0 提供了文件上傳操作功能,而且使用也非常簡單。
我們只需要給 Servlet 貼一個(gè)注解 @MultipartConfig然后使用getPart()獲取請求中指定 name 的文件到 Part 對象,就可以使用它的API來進(jìn)行操作文件了。
1.3、API
HttpServletRequest 提供了兩個(gè)方法用于從請求中解析上傳的文件。
Part中常用的方法:
1.4、代碼
package com.servlet; import java.io.IOException; import java.net.http.HttpClient; import javax.servlet.ServletException; import javax.servlet.annotation.MultipartConfig; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.Part; /** * @author Xiao_Lin * @date 2021/1/20 9:26 */ @WebServlet("/fileUpload") @MultipartConfig public class FileUploadServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 普通的參數(shù)還是使用原來的接收方式 String username = req.getParameter("username"); // 文件數(shù)據(jù)的獲取 Part part = req.getPart("headImg"); //保存到磁盤,參數(shù)名稱為盤符+文件名+后綴名(自己命名) part.write("d:/headimg.jpg");
<%@page contentType="text/html; UTF-8" pageEncoding="UTF-8" isELIgnored="false" %>
Hello World!
二、文件上傳拓展
2.1、獲取上傳文件名
我們可以使用可使用 Part對象的API來獲取。
package com.servlet; import java.io.IOException; import java.net.http.HttpClient; import javax.servlet.ServletException; import javax.servlet.annotation.MultipartConfig; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.Part; /** * @author Xiao_Lin * @date 2021/1/20 9:26 */ @WebServlet("/fileUpload") @MultipartConfig public class FileUploadServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 普通的參數(shù)還是使用原來的接收方式 String username = req.getParameter("username"); // 文件數(shù)據(jù)的獲取 Part part = req.getPart("headImg"); // 保存到磁盤,參數(shù)名稱為盤符+文件名+后綴名(自動獲取文件名) part.write("d:/"+part.getSubmittedFileName()); } }
2.2、使用UUID生成文件名
若上傳得文件名相同會導(dǎo)致覆蓋服務(wù)器之前已上傳的的文件,我們的解決方法就是自己給文件起一個(gè)唯
一的名稱,確保不被覆蓋,這里我們使用的是 UUID。
package com.servlet; import java.io.IOException; import java.net.http.HttpClient; import java.util.UUID; import javax.servlet.ServletException; import javax.servlet.annotation.MultipartConfig; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.Part; /** * @author Xiao_Lin * @date 2021/1/20 9:26 */ @WebServlet("/fileUpload") @MultipartConfig public class FileUploadServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 文件數(shù)據(jù)的獲取 Part part = req.getPart("headImg"); //獲取上傳的文件名 String realName = part.getSubmittedFileName(); //拿到文件的拓展名 String ext = realName.substring(realName.lastIndexOf(".")); //生成唯一的UUID,保證不會重復(fù) String fileNewName = UUID.randomUUID().toString()+ext; part.write("d://"+fileNewName); } }
注意:在tomcat7 的環(huán)境下就沒有part.getSubmittedFileName()這一方法,無法直接獲取文件名,如果使用的是Tomcat7插件或者是Tomcat8以下的版本,需要換方法。不然會報(bào)錯(cuò)。
String cd = part.getHeader("Content-Disposition"); //截取不同類型的文件需要自行判斷 String filename = cd.substring(cd.lastIndexOf("=")+2, cd.length()-1);
2.3、文件保存位置問題
文件在磁盤某個(gè)位置,不在項(xiàng)目下,無法使用 HTTP 協(xié)議訪問,所以要把用戶上傳的文件存放到項(xiàng)目中
才可通過 HTTP 協(xié)議來訪問,且保存的位置路徑不可以寫絕對路徑,那么我們該如何進(jìn)行訪問呢?
我們可以通過ServletContext 對象的 getRealPath("項(xiàng)目中保存上傳文件的文件夾的相對路徑") 來獲取其的絕對路徑。
我們在webapps目錄下新建一個(gè)upload用來存放文件。
package com.servlet; import java.io.IOException; import java.net.http.HttpClient; import java.util.UUID; import javax.servlet.ServletException; import javax.servlet.annotation.MultipartConfig; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.Part; /** * @author Xiao_Lin * @date 2021/1/20 9:26 */ @WebServlet("/fileUpload") @MultipartConfig public class FileUploadServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 文件數(shù)據(jù)的獲取 Part part = req.getPart("headImg"); String cd = part.getHeader("Content-Disposition"); //獲取上傳的文件名 String realName = cd.substring(cd.lastIndexOf("=")+2, cd.length()-1); //拿到文件的拓展名 String ext = realName.substring(realName.lastIndexOf(".")); //生成唯一的UUID,保證不會重復(fù) String fileNewName = UUID.randomUUID().toString()+ext; // 獲取項(xiàng)目下的 upload 目錄的絕對路徑,拼接成文件的保存路徑(maven項(xiàng)目需要用tomcat7才可以) String realPath = req.getServletContext().getRealPath("/upload") +"/"+ fileNewName; part.write(realPath); } }
2.4、文件類型的約束
限制用戶惡意上傳文件,比如要讓用戶上傳頭像,而用戶卻上傳一個(gè)非圖片文件,比如 JSP 文件。
package com.servlet; import java.io.IOException; import java.net.http.HttpClient; import java.util.UUID; import javax.servlet.ServletException; import javax.servlet.annotation.MultipartConfig; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.Part; /** * @author Xiao_Lin * @date 2021/1/20 9:26 */ @WebServlet("/fileUpload") @MultipartConfig public class FileUploadServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 文件數(shù)據(jù)的獲取 Part part = req.getPart("headImg"); System.out.println(part.getContentType()); // 如果上傳的文件不是圖片(文件擴(kuò)展名不是以image開頭的就不是圖片) if (!part.getContentType().startsWith("image/")) { req.setAttribute("msg","請上傳圖片"); req.getRequestDispatcher("/index.jsp").forward(req, resp); return; } } }
2.5、文件的大小約束
文件上傳限制大小可提高服務(wù)器硬盤的使用率,防止用戶惡意上傳文件造成服務(wù)器磁盤資源緊張。我們可以通過設(shè)置 @MutipartConfig的屬性做限制,他有兩個(gè)屬性:
maxFileSize:單個(gè)上傳文件大小限制,單位:bytes。
·maxRequestSize·:顯示請求中數(shù)據(jù)的大小,單位:bytes。
@MultipartConfig(maxFileSize = 80000, maxRequestSize = 140000)
三、文件的下載
3.1、代碼
package com.servlet; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author Xiao_Lin * @date 2021/1/21 10:58 */ @WebServlet(urlPatterns = "/download") public class DownloadServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 獲取用戶需要下載的文件名稱 String fileName = req.getParameter("fileName"); // 獲取文件所在的根路徑 String realPath = req.getServletContext().getRealPath("/WEB-INF/upload/"); // 使用工具類Files的copy方法獲取一個(gè)文件輸出流,響應(yīng)給瀏覽器 Files.copy(Paths.get(realPath,fileName),resp.getOutputStream()); } }
3.2、下載文件的名稱問題
默認(rèn)情況下,Tomcat 服務(wù)器未告知瀏覽器文件的名稱,所以需要手動設(shè)置響應(yīng)頭來告知瀏覽器文件名
稱。
// 給瀏覽器一個(gè)推薦名稱 resp.setHeader("Content-Disposition", "attachment;filename=文件名稱");
如果文件中有中文的話還涉及到需要處理中文亂碼的問題,這里分為兩個(gè)流派:
IE 使用 URL 編碼方式:URLEncoder.encode(fileName, “UTF-8”)
非 IE使用 ISO-8859-1 編碼:new String (fileName.getBytes(“UTF-8”), “ISO-8859-1”)
package com.servlet; import java.io.IOException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author Xiao_Lin * @date 2021/1/21 10:58 */ @WebServlet(urlPatterns = "/download") public class DownloadServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 獲取用戶需要下載的文件名稱 String fileName = req.getParameter("fileName"); // 獲取瀏覽器的類型 String header = req.getHeader("User-Agent"); // 如果包含MSIE說明是微軟的瀏覽器(非IE),否則就不是IE String name = header.contains("MSIE") ? URLEncoder.encode(fileName, StandardCharsets.UTF_8) : new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1); // 設(shè)置文件的下載名 resp.setHeader("Content-Disposition","attachment;filename=" + name); // 獲取文件所在的根路徑 String realPath = req.getServletContext().getRealPath("/WEB-INF/upload/"); // 使用工具類Files的copy方法獲取一個(gè)文件輸出流,響應(yīng)給瀏覽器 Files.copy(Paths.get(realPath,fileName),resp.getOutputStream()); } }
Servlet
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。