简介:文件上传和下载是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 }
参考文章:http://blog.ncmem.com/wordpress/2023/12/13/common-fileupload%e7%bb%84%e4%bb%b6%e5%ae%9e%e7%8e%b0java%e6%96%87%e4%bb%b6%e4%b8%8a%e4%bc%a0%e5%92%8c%e4%b8%8b%e8%bd%bd/
欢迎入群一起讨论