簡介:文件上傳和下載是java web中常見的操作,文件上傳主要是將文件通過IO流傳放到服務器的某一個特定的文件夾下,而文件下載則是與文件上傳相反,將文件從服務器的特定的文件夾下的文件通過IO流下載到本地。對於文件上傳,瀏覽器在上傳的過程中是將文件以流的形式提交到服務器端的,如果直接使用Servlet獲取上傳文件的輸入流然后再解析里面的請求參數是比較麻煩,所以一般選擇采用apache的開源工具common-fileupload這個文件上傳組件。這個common-fileupload上傳組件的jar包可以去apache官網上面下載,也可以在struts的lib文件夾下面找到,struts上傳的功能就是基於這個實現的。common-fileupload是依賴於common-io這個包的,所以還需要下載這個包。
文件上傳
(1)文件上傳前端界面(fileupload.jsp)
1 <%@ page language="java" contentType="text/html; charset=UTF-8" 2 pageEncoding="UTF-8"%> 3 <!DOCTYPE html> 4 <html> 5 <head> 6 <meta charset="UTF-8"> 7 <title>文件上傳</title> 8 </head> 9 <body> 10 <form action="FileUpload" method="post" enctype="multipart/form-data"> 11 <p><label>用戶名:<input type="text" name="username"></label></p> 12 <p><label>密 碼:<input type="password" name="pwd"></label></p> 13 <p><input type="file" name="upfile"></p> 14 <input type="submit" value="提交"> 15 </form> 16 </body> 17 </html>
[注]:在文件上傳的頁面要用enctype="multipart/form-data" method="post"來表示進行文件上傳
(2)文件上傳細節
上述的代碼雖然可以成功將文件上傳到服務器上面的指定目錄當中,但是文件上傳功能有許多需要注意的小細節問題,以下列出的幾點需要特別注意的:
(2.1)、為保證服務器安全,上傳文件應該放在外界無法直接訪問的目錄下,比如放於WEB-INF目錄下。
(2.2)、為防止文件覆蓋的現象發生,要為上傳文件產生一個唯一的文件名。
(2.3)、為防止一個目錄下面出現太多文件,要使用hash算法打散存儲。
(2.4)、要限制上傳文件的最大值。
(2.5)、要限制上傳文件的類型,在收到上傳文件名時,判斷后綴名是否合法。
(3)處理文件上傳的servlet
1 package com.etc.utils; 2 3 import java.io.File; 4 import java.io.IOException; 5 import java.io.PrintWriter; 6 import java.util.List; 7 import java.util.UUID; 8 9 import javax.servlet.ServletException; 10 import javax.servlet.annotation.WebServlet; 11 import javax.servlet.http.HttpServlet; 12 import javax.servlet.http.HttpServletRequest; 13 import javax.servlet.http.HttpServletResponse; 14 15 import org.apache.commons.fileupload.FileItem; 16 import org.apache.commons.fileupload.disk.DiskFileItemFactory; 17 import org.apache.commons.fileupload.servlet.ServletFileUpload; 18 19 @WebServlet("/FileUpload") 20 public class FileUpload extends HttpServlet { 21 private static final long serialVersionUID = 1L; 22 23 public FileUpload() { 24 super(); 25 } 26 27 protected void doGet(HttpServletRequest request, HttpServletResponse response) 28 throws ServletException, IOException { 29 request.setCharacterEncoding("UTF-8"); 30 response.setCharacterEncoding("UTF-8"); 31 response.setContentType("text/html;charset=UTF-8"); 32 PrintWriter out = response.getWriter(); 33 String filedName = ""; 34 35 // 1、創建工廠類:DiskFileItemFactory factory=new DiskFileItemFactory(); 36 DiskFileItemFactory factory = new DiskFileItemFactory(); 37 // 2、創建解析器:ServletFileUpload upload=new ServletFileUpload(factory); 38 ServletFileUpload upload = new ServletFileUpload(factory); 39 upload.setHeaderEncoding("UTF-8"); 40 41 // 設置緩沖區大小與臨時文件目錄 42 factory.setSizeThreshold(1024 * 1024 * 10); 43 File fileDir = new File("e:\\upload"); 44 if (!fileDir.exists()) 45 fileDir.mkdirs(); 46 // 設置文件存儲倉庫 47 factory.setRepository(fileDir); 48 // 設置單個文件大小限制 49 upload.setFileSizeMax(1024 * 1024 * 10); 50 // 設置所有文件總和大小限制 51 upload.setSizeMax(1024 * 1024 * 100); 52 53 // 3、使用解析器解析request對象:List<FileItem> list=upload.parseRequest(request); 54 /** 55 * FileItem 56 * String getFieldName():獲取表單項的name的屬性值。 57 * String getName():獲取文件字段的文件名。如果是普通字段,則返回null 58 * String getString():獲取字段的內容。如果是普通字段,則是它的value值;如果是文件字段,則是文件內容。 59 * String getContentType():獲取上傳的文件類型,例如text/plain、image。如果是普通字段,則返回null。 60 * long getSize():獲取字段內容的大小,單位是字節。 61 * boolean isFormField():判斷是否是普通表單字段,若是,返回true,否則返回false。 62 * InputStream getInputStream():獲得文件內容的輸入流。如果是普通字段,則返回value值的輸入流 63 */ 64 try { 65 List<FileItem> list = upload.parseRequest(request); 66 System.out.println(list); 67 for (FileItem fileItem : list) { 68 /* 69 * 對文件進行處理 70 */ 71 if (!fileItem.isFormField() && fileItem.getName() != null && !"".equals(fileItem.getName())) { 72 String fileName = fileItem.getName(); 73 String uuid = UUID.randomUUID().toString(); 74 //獲取文件的后綴名 75 //String suffix = fileName.substring(fileName.lastIndexOf(".")); 76 //獲取文件上傳目錄路徑,在項目部署路徑下的upload目錄里。若想讓瀏覽器不能直接訪問到圖片,可以放在WEB-INF下 77 String uploadPath = request.getSession().getServletContext().getRealPath("/upload"); 78 File file = new File(uploadPath); 79 file.mkdirs(); 80 //將文件寫入對應路徑,並對文件進行重命名 81 fileItem.write(new File(uploadPath, uuid + "_"+ fileName)); 82 } 83 /* 84 * 對表中的普通字段進行處理 85 */ 86 if(fileItem.isFormField()) { 87 filedName = fileItem.getFieldName(); 88 String username = null; 89 String pwd = null; 90 if("username".equals(filedName)) { 91 username = fileItem.getString("UTF-8"); 92 out.println("用戶名:" + username); 93 } 94 if("pwd".equals(filedName)) { 95 pwd = fileItem.getString("UTF-8"); 96 out.println("\t密碼:" + pwd); 97 } 98 } 99 } 100 } catch (Exception e) { 101 // TODO Auto-generated catch block 102 e.printStackTrace(); 103 } 104 105 } 106 protected void doPost(HttpServletRequest request, HttpServletResponse response) 107 throws ServletException, IOException { 108 doGet(request, response); 109 } 110 }
文件下載
(1)列出提供下載的文件資源
要將Web應用系統中的文件資源提供給用戶進行下載,首先我們要有一個頁面列出上傳文件目錄下的所有文件,當用戶點擊文件下載超鏈接時就進行下載操作,編寫一個ListFileServlet,用於列出Web應用系統中所有下載文件。
1 package com.etc.utils; 2 3 import java.io.File; 4 import java.io.IOException; 5 import java.util.HashMap; 6 import java.util.Map; 7 8 import javax.servlet.ServletException; 9 import javax.servlet.annotation.WebServlet; 10 import javax.servlet.http.HttpServlet; 11 import javax.servlet.http.HttpServletRequest; 12 import javax.servlet.http.HttpServletResponse; 13 14 @WebServlet("/FileDownLoad") 15 public class FileDownLoad extends HttpServlet { 16 private static final long serialVersionUID = 1L; 17 public FileDownLoad() { 18 super(); 19 } 20 21 protected void doGet(HttpServletRequest request, HttpServletResponse response) 22 throws ServletException, IOException { 23 response.getWriter().append("Served at: ").append(request.getContextPath()); 24 // 獲取上傳文件的目錄 25 String uploadFilePath = this.getServletContext().getRealPath("/upload"); 26 // 儲存要下載的文件名 27 Map<String, String> fileMap = new HashMap<String, String>(); 28 // 遞歸遍歷fileMap目錄下的所有文件和目錄,將文件儲存到map集合中 29 fileList(new File(uploadFilePath),fileMap); 30 //將Map集合發送到listfile.jsp頁面進行顯示 31 request.setAttribute("fileMap", fileMap); 32 request.getRequestDispatcher("/listfile.jsp").forward(request, response); 33 } 34 35 public void fileList(File file, Map<String,String> fileMap) { 36 // 如果file代表的不是一個文件而是一個目錄 37 if (!file.isFile()) { 38 File[] files = file.listFiles(); 39 for (File file2 : files) { 40 fileList(file2, fileMap); 41 } 42 } else { 43 /** 44 * 處理文件名,上傳后的文件是以uuid_文件名的形式去重新命名的,去除文件名的uuid_部分 45 * file.getName().indexOf("_")檢索字符串中第一次出現"_"字符的位置,如果文件名類似於:9349249849-88343-8344_timer.avi 46 * 那么file.getName().substring(file.getName().indexOf("_")+1)處理之后就可以得到timer.avi部分 47 */ 48 String realName = file.getName().substring(file.getName().lastIndexOf("_")+1); 49 System.out.println(realName); 50 fileMap.put(file.getName(), realName); 51 } 52 } 53 54 protected void doPost(HttpServletRequest request, HttpServletResponse response) 55 throws ServletException, IOException { 56 doGet(request, response); 57 } 58 }
(2)創建顯示文件列表的jsp界面(listfile.jsp)
1 <%@ page language="java" contentType="text/html; charset=UTF-8" 2 pageEncoding="UTF-8"%> 3 <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> 4 <!DOCTYPE html> 5 <html> 6 <head> 7 <meta charset="UTF-8"> 8 <link href="css/bootstrap.css" rel="stylesheet"> 9 <title>下載文件顯示界面</title> 10 </head> 11 <body> 12 <div class="container"> 13 <table class="table table-bordered"> 14 <caption>文件下載列表</caption> 15 <c:forEach var="me" items="${requestScope.fileMap}"> 16 <tr> 17 <c:url value="DownLoadServlet" var="downurl"> 18 <c:param name="filename" value="${me.key}"></c:param> 19 </c:url> 20 21 <td>${me.value}</td><td><a href="${downurl}">下載</a></td> 22 </tr> 23 </c:forEach> 24 </table> 25 </div> 26 </body> 27 </html>
(3)實現文件下載的servlet
DownLoadServlet的代碼如下:
1 package com.etc.utils; 2 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.io.IOException; 6 import java.io.InputStream; 7 import java.io.OutputStream; 8 import java.net.URLEncoder; 9 10 import javax.servlet.ServletException; 11 import javax.servlet.annotation.WebServlet; 12 import javax.servlet.http.HttpServlet; 13 import javax.servlet.http.HttpServletRequest; 14 import javax.servlet.http.HttpServletResponse; 15 16 import org.apache.commons.io.IOUtils; 17 18 @WebServlet("/DownLoadServlet") 19 public class DownLoadServlet extends HttpServlet { 20 private static final long serialVersionUID = 1L; 21 22 public DownLoadServlet() { 23 super(); 24 // TODO Auto-generated constructor stub 25 } 26 27 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 28 String fileName = request.getParameter("filename"); 29 //獲取文件路徑 30 String fileSaveRootPath = this.getServletContext().getRealPath("/upload"); 31 //獲取真實的文件名 32 String realname = fileName.substring(fileName.indexOf("_")+1); 33 //得到要下載的文件 34 File file = new File(fileSaveRootPath+File.separator+fileName); 35 //如果文件不存在 36 if(!file.exists()) { 37 request.setAttribute("msg", "您要下載的文件已被刪除!"); 38 request.getRequestDispatcher("/message.jsp").forward(request, response); 39 return; 40 } 41 //設置響應頭,控制瀏覽器下載該文件 可通過URLEncoder.encode(realname, "UTF-8")實現對下載的文件進行重命名 42 response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(realname, "UTF-8")); 43 //獲取輸入輸出流 44 InputStream is = new FileInputStream(file); 45 OutputStream os = response.getOutputStream(); 46 //調用common-io下面的靜態方法,用於實現文件復制(從服務器端復制到本地) 47 IOUtils.copy(is, os); 48 is.close(); 49 } 50 51 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 52 doGet(request, response); 53 } 54 }
文件上傳下載還能進行很多優化,可參考博文