JavaWeb 文件 上传 下载
文件上传下载对于一个网站来说,重要性不言而喻。今天来分享一个JavaWeb方式实现的文件上传下载的小例子。
项目依赖
这个小例子是使用JavaWeb的JSP+Servlet实现的。另外使用了一些第三方的jar包。现列举如下:
-
apache-commons-fileupload.jar
+apache-commons-io.jar
: 开源的一套便于使用的组件 -
jstl.jar
+standard.jar
: 模板语言jsp中将会用到的支持 -
stringutil.jar
: 这个是我自己写的一个对string的简单的操作jar。下载地址https://github.com/guoruibiao/File_Upload_Download/blob/master/WebContent/WEB-INF/lib/stringutils.jar
以上这些依赖,都很容易获得。当然也可以在我的repository
中直接获取。地址如下:https://github.com/guoruibiao/File_Upload_Download/blob/master/WebContent/WEB-INF/lib。
项目目录
在开始项目之前,给出一个项目目录可以使得我们的思路更加的清晰。
工作流程
对于新手而言。对web.xml的配置可能摸不着头脑,下面给大家画个图吧。
文件上传
在开始编码之前,我们还需要了解一些比较基础的知识。可能你会觉得有点啰嗦了,但是为了照顾到不了解这些的童鞋,我还是多说几句吧:-)
表单处的设置
如果我们要想做一个上传文件功能,毫无疑问需要通过表单进行。因此,我们需要遵守一点规则。
<form action="${pageContext.request.contextPath }/servlet/UploadHandleServlet" enctype="multipart/form-data" method="post"> 上传用户:<input type="text" name="username"><br> 上传文件1:<input type="file" name="file1"><br> 上传文件2:<input type="file" name="file2"><br> <input type="submit" value="提交"> </form>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
以这个表单为例,我们不难发现。
enctype="multipart/form-data"
这行代码,其作用就是告诉服务器,我们的这个表单将用于文件上传处理。
服务器端
通过表单来实现上传固然很方便,但是除了文件项之外的表单项怎么处理呢? 这时我们就需要了解一下,关于apache-commons-fileupload
的文件处理了。
try { // 使用Apache上传组件处理文件上传的步骤 // 1、创建一个DIskFileItemFactory工厂 DiskFileItemFactory factory = new DiskFileItemFactory(); // 2、创建一个文件上传解析器 ServletFileUpload uploadparser = new ServletFileUpload(factory); // 3、解决上传文件的中文乱码;判断提交上来的数据是否是上传表单的数据 uploadparser.setHeaderEncoding("UTF-8"); if (!ServletFileUpload.isMultipartContent(request)) { // 不是表单数据,则按照传统方式获取数据 return; } // 4、使用ServletFileUpload解析器解析上传的数据,解析结果返回的是一个List<File>集合,每个Item对应一个表单的输入项 List<FileItem> files = uploadparser.parseRequest(request); for (FileItem fileitem : files) { // 如果fileitem中封装的是普通的输入项的数据 if (fileitem.isFormField()) { String name = fileitem.getFieldName(); // 解决普通输入项的数据的中文乱码问题 String value = fileitem.getString("UTF-8"); System.out.println(name + " = " + value); } else {// 如果fileitem里面封装的是上传的文件,则是用处理文件的方式处理 String filename = fileitem.getName(); System.out.println(fileitem); if (filename == null || filename.trim().equals("")) { continue; } // 注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件是带有其客户端本机路径的,有些则不带。所以我们要对上传文件处理,只得到文件名称即可 filename = StringUtils.getFileName(filename); // 获取fileitem的上传文件的输入流 InputStream is = fileitem.getInputStream(); // 创建一个文件输出流 FileOutputStream fos = new FileOutputStream(savePath + "\\" + filename); // 创建一个缓冲区 byte[] buffer = new byte[1024]; // 判断输入流中的数据是否已经读完的标识 int len = 0; while ((len = is.read(buffer)) > 0) { // 将数据写入到服务器的对应的文件中 fos.write(buffer, 0, len); } is.close(); fos.close(); fileitem.delete(); message = new String("Upload Success!".getBytes(), "UTF-8"); } } } catch (Exception e) { message = new String("Upload Failed!".getBytes(), "UTF-8") + e; e.printStackTrace(); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
上传功能的实现
好了,下面开始上传功能的实现。
upload.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>文件上传</title></head><body> <form action="${pageContext.request.contextPath }/servlet/UploadHandleServlet" enctype="multipart/form-data" method="post"> 上传用户:<input type="text" name="username"><br> 上传文件1:<input type="file" name="file1"><br> 上传文件2:<input type="file" name="file2"><br> <input type="submit" value="提交"> </form></body></html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
message.jsp
在软件使用的过程中,为了给用户一个更加友好的用户体验,我们添加了一个与用户单方面交互(简单的提示作用)的页面。用来传递代码过程的必要信息。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>消息提示</title></head><body>${message }</body></html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
UploadHandleServlet
package controller;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.util.List;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.commons.fileupload.FileItem;import org.apache.commons.fileupload.disk.DiskFileItemFactory;import org.apache.commons.fileupload.servlet.ServletFileUpload;import stringutil.StringUtils;public class UploadHandleServlet extends HttpServlet { private static final long serialVersionUID = 1L; public UploadHandleServlet() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.getWriter().append("Served at: ").append(request.getContextPath()); // 得到上传文件的保存目录,将上传的文件存放到外界不能直接访问的WEB-INF目录下// String savePath = this.getServletContext().getRealPath("/WEB-INF/upload"); String savePath = "E://Code/jee/File_upload_download/WebContent/WEB-INF/upload"; File file = new File(savePath); // 判断上传文件的目录是否存在 if (!file.exists() && !file.isDirectory()) { System.out.println(savePath + " Need to Make Directory named ‘upload’!"); // 开始创建目录 file.mkdir(); } // 消息提示 String message = ""; try { // 使用Apache上传组件处理文件上传的步骤 // 1、创建一个DIskFileItemFactory工厂 DiskFileItemFactory factory = new DiskFileItemFactory(); // 2、创建一个文件上传解析器 ServletFileUpload uploadparser = new ServletFileUpload(factory); // 3、解决上传文件的中文乱码;判断提交上来的数据是否是上传表单的数据 uploadparser.setHeaderEncoding("UTF-8"); if (!ServletFileUpload.isMultipartContent(request)) { // 不是表单数据,则按照传统方式获取数据 return; } // 4、使用ServletFileUpload解析器解析上传的数据,解析结果返回的是一个List<File>集合,每个Item对应一个表单的输入项 List<FileItem> files = uploadparser.parseRequest(request); for (FileItem fileitem : files) { // 如果fileitem中封装的是普通的输入项的数据 if (fileitem.isFormField()) { String name = fileitem.getFieldName(); // 解决普通输入项的数据的中文乱码问题 String value = fileitem.getString("UTF-8"); System.out.println(name + " = " + value); } else {// 如果fileitem里面封装的是上传的文件,则是用处理文件的方式处理 String filename = fileitem.getName(); System.out.println(fileitem); if (filename == null || filename.trim().equals("")) { continue; } // 注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件是带有其客户端本机路径的,有些则不带。所以我们要对上传文件处理,只得到文件名称即可 filename = StringUtils.getFileName(filename); // 获取fileitem的上传文件的输入流 InputStream is = fileitem.getInputStream(); // 创建一个文件输出流 FileOutputStream fos = new FileOutputStream(savePath + "\\" + filename); // 创建一个缓冲区 byte[] buffer = new byte[1024]; // 判断输入流中的数据是否已经读完的标识 int len = 0; while ((len = is.read(buffer)) > 0) { // 将数据写入到服务器的对应的文件中 fos.write(buffer, 0, len); } is.close(); fos.close(); fileitem.delete(); message = new String("Upload Success!".getBytes(), "UTF-8"); } } } catch (Exception e) { message = new String("Upload Failed!".getBytes(), "UTF-8") + e; e.printStackTrace(); } request.setAttribute("message", message); request.getRequestDispatcher("/message.jsp").forward(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
web.xml配置
<servlet> <servlet-name>UploadHandleServlet</servlet-name> <servlet-class>controller.UploadHandleServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>UploadHandleServlet</servlet-name> <url-pattern>/servlet/UploadHandleServlet</url-pattern> </servlet-mapping>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
结果展示
文件浏览
要想实现下载功能,我们需要先给用户一个引导,那就是咱们的网站上有什么。所以我们需要对网站上提供下载的文件夹一个遍历。
思路如下:
ListFileServlet.java
package controller;import java.io.File;import java.io.IOException;import java.io.UnsupportedEncodingException;import java.util.HashMap;import java.util.Map;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import stringutil.StringUtils;/** * Servlet implementation class ListFileServlet */@WebServlet("/ListFileServlet")public class ListFileServlet extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public ListFileServlet() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse * response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.getWriter().append("Served at: ").append(request.getContextPath()); // 获取上传文件的目录 String uploadPath = "E://Code/jee/File_upload_download/WebContent/WEB-INF/upload"; // 存储要下载的文件名 Map<String, String> filenameMap = new HashMap<String, String>(); // 递归遍历filePath下面的所有的文件和目录,将文件的文件名称存储到Map集合中 listFile(new File(uploadPath), filenameMap); // 将集合存入域找那个,方便页面展示层获取数据 request.setAttribute("filenameMap", filenameMap); request.getRequestDispatcher("/listfiles.jsp").forward(request, response); } public void listFile(File file, Map<String, String> filenameMap) { // 如果file代表的不是一个文件,而是一个目录 if (!file.isFile()) { // 列出该目录下面的所有的文件和目录 File[] files = file.listFiles(); // 遍历files[] 数组 for (File f : files) { // 递归 listFile(f, filenameMap); } } else { // 使用自己的那个strigutil来获取文件的名称,而不是路径名称 String realName = StringUtils.getFileName(file.getName()); try { filenameMap.put(new String(file.getName().getBytes("iso8859-1"),"UTF-8"), realName); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse * response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
listfiles.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%><!DOCTYPE HTML><html><head><title>下载文件显示页面</title></head><body> <!-- 遍历Map集合 --> <c:forEach var="me" items="${filenameMap}"> <c:url value="/servlet/DownLoadServlet" var="downurl"> <c:param name="filename" value="${me.key}"></c:param> </c:url> ${me.value}<a href="${downurl}">Download now?</a> <br /> </c:forEach></body></html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
web.xml配置
<servlet> <servlet-name>ListFileServlet</servlet-name> <servlet-class>controller.ListFileServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>ListFileServlet</servlet-name> <url-pattern>/servlet/ListFileServlet</url-pattern> </servlet-mapping>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
截图结果
注意
这里有几点容易出错的地方,大家需要注意。
路径问题
由于使用this.getServletContext().getRealPath("/WEB-INF/upload");
的过程中出现了一些问题,所以我这里使用了绝对路径,大家可以自己的情况随意选择。
JSTL使用
在使用JSTL标签库的时候,千万不要忘记引入相关的jar包。然后在JSP页面上方填写相应的声明。还有就是URI属性不要写错咯。是<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
模板变量
在<c:forEach>
标签内部,使用的<c:param name="filename" value="${me.key}"></c:param>
参数一定不要写错了。因为等会我们会根据这里面的name="filename"
属性来唯一确定我们要下载的文件的信息。
文件下载
文件下载的功能本身并不难,核心就是告诉浏览器header是什么,然后通过一个流操作,将要进行下载的数据发送给客户端浏览器即可。
DownLoadServlet.java
package controller;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.OutputStream;import java.net.URLEncoder;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import stringutil.StringUtils;/** * Servlet implementation class DownLoadServlet */@WebServlet("/DownLoadServlet")public class DownLoadServlet extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public DownLoadServlet() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse * response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub // 得到要下载的文件名 String filename = request.getParameter("filename"); filename = new String(filename.getBytes("iso8859-1"), "UTF-8"); // 上传的文件都是保存在刚才的那个upload的文件夹下. String fileSaveRootPath = "E://Code/jee/File_upload_download/WebContent/WEB-INF/upload"; // 通过文件名找出文件所在的目录 // 由于路径有点问题,这里采用绝对路径来进行处理 // String filePath = // findFileSavePathByFileName(filename,fileSaveRootPath); String filePath = fileSaveRootPath; // 得到要下载的文件 File file = new File(filePath + "\\" + filename); // 如果文件不存在 if (!file.exists()) { request.setAttribute("message", "The File you want to download doesn't exists!"); request.getRequestDispatcher("/message.jsp").forward(request, response); return; } // 处理文件名 String realname = StringUtils.getFileName(filename); // 设置响应头 response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(realname, "UTF-8")); // 读取要下载的文件,保存到文件输入流 FileInputStream fis = new FileInputStream(filePath + "\\" + filename); // 创建输入流 OutputStream os = response.getOutputStream(); // 创建缓冲区 byte[] buffer = new byte[1024]; int len = 0; while ((len = fis.read(buffer)) > 0) { os.write(buffer, 0, len); } fis.close(); os.close(); } private String findFileSavePathByFileName(String filename, String fileSaveRootPath) { int hashcode = filename.hashCode(); int dir1 = hashcode & 0xf; // 0--15 int dir2 = (hashcode & 0xf0) >> 4; // 0--15 String dir = fileSaveRootPath + "\\" + dir1 + "\\" + dir2; File file = new File(dir); if (!file.exists()) { // 创建目录 file.mkdir(); } return dir; } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse * response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
web.xml配置
<servlet> <servlet-name>DownLoadServlet</servlet-name> <servlet-class>controller.DownLoadServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>DownLoadServlet</servlet-name> <url-pattern>/servlet/DownLoadServlet</url-pattern> </servlet-mapping>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
截图展示
总结
最后关于整个项目的总结。使用apache-commons-fileupload
组件确实是很方便,它可以方便的将表单中上传的数据封装到一个List<fileItem>
中,我们只需要对这个集合进行遍历操作,就可以随意的设置自己需要的内容。
最后,希望大家看完之后都能有所收获。让自己的网站的功能更加的丰富。
完整的项目下载地址如下: https://github.com/guoruibiao/File_Upload_Download/。欢迎拍砖 :-)
再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.****.net/jiangjunshow
文件上传下载对于一个网站来说,重要性不言而喻。今天来分享一个JavaWeb方式实现的文件上传下载的小例子。
项目依赖
这个小例子是使用JavaWeb的JSP+Servlet实现的。另外使用了一些第三方的jar包。现列举如下:
-
apache-commons-fileupload.jar
+apache-commons-io.jar
: 开源的一套便于使用的组件 -
jstl.jar
+standard.jar
: 模板语言jsp中将会用到的支持 -
stringutil.jar
: 这个是我自己写的一个对string的简单的操作jar。下载地址https://github.com/guoruibiao/File_Upload_Download/blob/master/WebContent/WEB-INF/lib/stringutils.jar
以上这些依赖,都很容易获得。当然也可以在我的repository
中直接获取。地址如下:https://github.com/guoruibiao/File_Upload_Download/blob/master/WebContent/WEB-INF/lib。
项目目录
在开始项目之前,给出一个项目目录可以使得我们的思路更加的清晰。
工作流程
对于新手而言。对web.xml的配置可能摸不着头脑,下面给大家画个图吧。
文件上传
在开始编码之前,我们还需要了解一些比较基础的知识。可能你会觉得有点啰嗦了,但是为了照顾到不了解这些的童鞋,我还是多说几句吧:-)
表单处的设置
如果我们要想做一个上传文件功能,毫无疑问需要通过表单进行。因此,我们需要遵守一点规则。
<form action="${pageContext.request.contextPath }/servlet/UploadHandleServlet" enctype="multipart/form-data" method="post"> 上传用户:<input type="text" name="username"><br> 上传文件1:<input type="file" name="file1"><br> 上传文件2:<input type="file" name="file2"><br> <input type="submit" value="提交"> </form>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
以这个表单为例,我们不难发现。
enctype="multipart/form-data"
这行代码,其作用就是告诉服务器,我们的这个表单将用于文件上传处理。
服务器端
通过表单来实现上传固然很方便,但是除了文件项之外的表单项怎么处理呢? 这时我们就需要了解一下,关于apache-commons-fileupload
的文件处理了。
try { // 使用Apache上传组件处理文件上传的步骤 // 1、创建一个DIskFileItemFactory工厂 DiskFileItemFactory factory = new DiskFileItemFactory(); // 2、创建一个文件上传解析器 ServletFileUpload uploadparser = new ServletFileUpload(factory); // 3、解决上传文件的中文乱码;判断提交上来的数据是否是上传表单的数据 uploadparser.setHeaderEncoding("UTF-8"); if (!ServletFileUpload.isMultipartContent(request)) { // 不是表单数据,则按照传统方式获取数据 return; } // 4、使用ServletFileUpload解析器解析上传的数据,解析结果返回的是一个List<File>集合,每个Item对应一个表单的输入项 List<FileItem> files = uploadparser.parseRequest(request); for (FileItem fileitem : files) { // 如果fileitem中封装的是普通的输入项的数据 if (fileitem.isFormField()) { String name = fileitem.getFieldName(); // 解决普通输入项的数据的中文乱码问题 String value = fileitem.getString("UTF-8"); System.out.println(name + " = " + value); } else {// 如果fileitem里面封装的是上传的文件,则是用处理文件的方式处理 String filename = fileitem.getName(); System.out.println(fileitem); if (filename == null || filename.trim().equals("")) { continue; } // 注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件是带有其客户端本机路径的,有些则不带。所以我们要对上传文件处理,只得到文件名称即可 filename = StringUtils.getFileName(filename); // 获取fileitem的上传文件的输入流 InputStream is = fileitem.getInputStream(); // 创建一个文件输出流 FileOutputStream fos = new FileOutputStream(savePath + "\\" + filename); // 创建一个缓冲区 byte[] buffer = new byte[1024]; // 判断输入流中的数据是否已经读完的标识 int len = 0; while ((len = is.read(buffer)) > 0) { // 将数据写入到服务器的对应的文件中 fos.write(buffer, 0, len); } is.close(); fos.close(); fileitem.delete(); message = new String("Upload Success!".getBytes(), "UTF-8"); } } } catch (Exception e) { message = new String("Upload Failed!".getBytes(), "UTF-8") + e; e.printStackTrace(); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
上传功能的实现
好了,下面开始上传功能的实现。
upload.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>文件上传</title></head><body> <form action="${pageContext.request.contextPath }/servlet/UploadHandleServlet" enctype="multipart/form-data" method="post"> 上传用户:<input type="text" name="username"><br> 上传文件1:<input type="file" name="file1"><br> 上传文件2:<input type="file" name="file2"><br> <input type="submit" value="提交"> </form></body></html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
message.jsp
在软件使用的过程中,为了给用户一个更加友好的用户体验,我们添加了一个与用户单方面交互(简单的提示作用)的页面。用来传递代码过程的必要信息。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>消息提示</title></head><body>${message }</body></html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
UploadHandleServlet
package controller;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.util.List;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.commons.fileupload.FileItem;import org.apache.commons.fileupload.disk.DiskFileItemFactory;import org.apache.commons.fileupload.servlet.ServletFileUpload;import stringutil.StringUtils;public class UploadHandleServlet extends HttpServlet { private static final long serialVersionUID = 1L; public UploadHandleServlet() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.getWriter().append("Served at: ").append(request.getContextPath()); // 得到上传文件的保存目录,将上传的文件存放到外界不能直接访问的WEB-INF目录下// String savePath = this.getServletContext().getRealPath("/WEB-INF/upload"); String savePath = "E://Code/jee/File_upload_download/WebContent/WEB-INF/upload"; File file = new File(savePath); // 判断上传文件的目录是否存在 if (!file.exists() && !file.isDirectory()) { System.out.println(savePath + " Need to Make Directory named ‘upload’!"); // 开始创建目录 file.mkdir(); } // 消息提示 String message = ""; try { // 使用Apache上传组件处理文件上传的步骤 // 1、创建一个DIskFileItemFactory工厂 DiskFileItemFactory factory = new DiskFileItemFactory(); // 2、创建一个文件上传解析器 ServletFileUpload uploadparser = new ServletFileUpload(factory); // 3、解决上传文件的中文乱码;判断提交上来的数据是否是上传表单的数据 uploadparser.setHeaderEncoding("UTF-8"); if (!ServletFileUpload.isMultipartContent(request)) { // 不是表单数据,则按照传统方式获取数据 return; } // 4、使用ServletFileUpload解析器解析上传的数据,解析结果返回的是一个List<File>集合,每个Item对应一个表单的输入项 List<FileItem> files = uploadparser.parseRequest(request); for (FileItem fileitem : files) { // 如果fileitem中封装的是普通的输入项的数据 if (fileitem.isFormField()) { String name = fileitem.getFieldName(); // 解决普通输入项的数据的中文乱码问题 String value = fileitem.getString("UTF-8"); System.out.println(name + " = " + value); } else {// 如果fileitem里面封装的是上传的文件,则是用处理文件的方式处理 String filename = fileitem.getName(); System.out.println(fileitem); if (filename == null || filename.trim().equals("")) { continue; } // 注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件是带有其客户端本机路径的,有些则不带。所以我们要对上传文件处理,只得到文件名称即可 filename = StringUtils.getFileName(filename); // 获取fileitem的上传文件的输入流 InputStream is = fileitem.getInputStream(); // 创建一个文件输出流 FileOutputStream fos = new FileOutputStream(savePath + "\\" + filename); // 创建一个缓冲区 byte[] buffer = new byte[1024]; // 判断输入流中的数据是否已经读完的标识 int len = 0; while ((len = is.read(buffer)) > 0) { // 将数据写入到服务器的对应的文件中 fos.write(buffer, 0, len); } is.close(); fos.close(); fileitem.delete(); message = new String("Upload Success!".getBytes(), "UTF-8"); } } } catch (Exception e) { message = new String("Upload Failed!".getBytes(), "UTF-8") + e; e.printStackTrace(); } request.setAttribute("message", message); request.getRequestDispatcher("/message.jsp").forward(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
web.xml配置
<servlet> <servlet-name>UploadHandleServlet</servlet-name> <servlet-class>controller.UploadHandleServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>UploadHandleServlet</servlet-name> <url-pattern>/servlet/UploadHandleServlet</url-pattern> </servlet-mapping>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
结果展示
文件浏览
要想实现下载功能,我们需要先给用户一个引导,那就是咱们的网站上有什么。所以我们需要对网站上提供下载的文件夹一个遍历。
思路如下:
ListFileServlet.java
package controller;import java.io.File;import java.io.IOException;import java.io.UnsupportedEncodingException;import java.util.HashMap;import java.util.Map;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import stringutil.StringUtils;/** * Servlet implementation class ListFileServlet */@WebServlet("/ListFileServlet")public class ListFileServlet extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public ListFileServlet() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse * response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.getWriter().append("Served at: ").append(request.getContextPath()); // 获取上传文件的目录 String uploadPath = "E://Code/jee/File_upload_download/WebContent/WEB-INF/upload"; // 存储要下载的文件名 Map<String, String> filenameMap = new HashMap<String, String>(); // 递归遍历filePath下面的所有的文件和目录,将文件的文件名称存储到Map集合中 listFile(new File(uploadPath), filenameMap); // 将集合存入域找那个,方便页面展示层获取数据 request.setAttribute("filenameMap", filenameMap); request.getRequestDispatcher("/listfiles.jsp").forward(request, response); } public void listFile(File file, Map<String, String> filenameMap) { // 如果file代表的不是一个文件,而是一个目录 if (!file.isFile()) { // 列出该目录下面的所有的文件和目录 File[] files = file.listFiles(); // 遍历files[] 数组 for (File f : files) { // 递归 listFile(f, filenameMap); } } else { // 使用自己的那个strigutil来获取文件的名称,而不是路径名称 String realName = StringUtils.getFileName(file.getName()); try { filenameMap.put(new String(file.getName().getBytes("iso8859-1"),"UTF-8"), realName); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse * response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
listfiles.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%><!DOCTYPE HTML><html><head><title>下载文件显示页面</title></head><body> <!-- 遍历Map集合 --> <c:forEach var="me" items="${filenameMap}"> <c:url value="/servlet/DownLoadServlet" var="downurl"> <c:param name="filename" value="${me.key}"></c:param> </c:url> ${me.value}<a href="${downurl}">Download now?</a> <br /> </c:forEach></body></html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
web.xml配置
<servlet> <servlet-name>ListFileServlet</servlet-name> <servlet-class>controller.ListFileServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>ListFileServlet</servlet-name> <url-pattern>/servlet/ListFileServlet</url-pattern> </servlet-mapping>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
截图结果
注意
这里有几点容易出错的地方,大家需要注意。
路径问题
由于使用this.getServletContext().getRealPath("/WEB-INF/upload");
的过程中出现了一些问题,所以我这里使用了绝对路径,大家可以自己的情况随意选择。
JSTL使用
在使用JSTL标签库的时候,千万不要忘记引入相关的jar包。然后在JSP页面上方填写相应的声明。还有就是URI属性不要写错咯。是<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
模板变量
在<c:forEach>
标签内部,使用的<c:param name="filename" value="${me.key}"></c:param>
参数一定不要写错了。因为等会我们会根据这里面的name="filename"
属性来唯一确定我们要下载的文件的信息。
文件下载
文件下载的功能本身并不难,核心就是告诉浏览器header是什么,然后通过一个流操作,将要进行下载的数据发送给客户端浏览器即可。
DownLoadServlet.java
package controller;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.OutputStream;import java.net.URLEncoder;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import stringutil.StringUtils;/** * Servlet implementation class DownLoadServlet */@WebServlet("/DownLoadServlet")public class DownLoadServlet extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public DownLoadServlet() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse * response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub // 得到要下载的文件名 String filename = request.getParameter("filename"); filename = new String(filename.getBytes("iso8859-1"), "UTF-8"); // 上传的文件都是保存在刚才的那个upload的文件夹下. String fileSaveRootPath = "E://Code/jee/File_upload_download/WebContent/WEB-INF/upload"; // 通过文件名找出文件所在的目录 // 由于路径有点问题,这里采用绝对路径来进行处理 // String filePath = // findFileSavePathByFileName(filename,fileSaveRootPath); String filePath = fileSaveRootPath; // 得到要下载的文件 File file = new File(filePath + "\\" + filename); // 如果文件不存在 if (!file.exists()) { request.setAttribute("message", "The File you want to download doesn't exists!"); request.getRequestDispatcher("/message.jsp").forward(request, response); return; } // 处理文件名 String realname = StringUtils.getFileName(filename); // 设置响应头 response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(realname, "UTF-8")); // 读取要下载的文件,保存到文件输入流 FileInputStream fis = new FileInputStream(filePath + "\\" + filename); // 创建输入流 OutputStream os = response.getOutputStream(); // 创建缓冲区 byte[] buffer = new byte[1024]; int len = 0; while ((len = fis.read(buffer)) > 0) { os.write(buffer, 0, len); } fis.close(); os.close(); } private String findFileSavePathByFileName(String filename, String fileSaveRootPath) { int hashcode = filename.hashCode(); int dir1 = hashcode & 0xf; // 0--15 int dir2 = (hashcode & 0xf0) >> 4; // 0--15 String dir = fileSaveRootPath + "\\" + dir1 + "\\" + dir2; File file = new File(dir); if (!file.exists()) { // 创建目录 file.mkdir(); } return dir; } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse * response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
web.xml配置
<servlet> <servlet-name>DownLoadServlet</servlet-name> <servlet-class>controller.DownLoadServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>DownLoadServlet</servlet-name> <url-pattern>/servlet/DownLoadServlet</url-pattern> </servlet-mapping>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
截图展示
总结
最后关于整个项目的总结。使用apache-commons-fileupload
组件确实是很方便,它可以方便的将表单中上传的数据封装到一个List<fileItem>
中,我们只需要对这个集合进行遍历操作,就可以随意的设置自己需要的内容。
最后,希望大家看完之后都能有所收获。让自己的网站的功能更加的丰富。
完整的项目下载地址如下: https://github.com/guoruibiao/File_Upload_Download/。欢迎拍砖 :-)