简介:文件上传和下载是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 }
文件上传下载还能进行很多优化,可参考博文