文件上传下载对于一个网站来说,重要性不言而喻。今天来分享一个JavaWeb方式实现的文件上传下载的小例子。
项目依赖
这个小例子是使用JavaWeb的JSP+Servlet实现的。另外使用了一些第三方的jar包。现列举如下:
以上这些依赖,都很容易获得。当然也可以在我的repository
中直接获取。地址如下:https://github.com/guoruibiao/File_Upload_Download/blob/master/WebContent/WEB-INF/lib。
项目目录
在开始项目之前,给出一个项目目录可以使得我们的思路更加的清晰。

工作流程
对于新手而言。对web.xml的配置可能摸不着头脑,下面给大家画个图吧。
Created with Raphaël 2.1.0URL链接根据url-pattern找到同级的servlet-name根据servlet-name可以获取其父标签servlet-mapping,然后获取到servlet-mapping的兄弟节点servlet根据servlet-mapping的servlet-name就可以获取到与之同名的servlet标签的内容。从servlet标签中获取到servlet-class属性的值,然后通过反射技术在tomcat容器中加载相应的类。进行一系列的业务逻辑操作。将获取到的数据传给jsp页面模板用户获取视图
文件上传
在开始编码之前,我们还需要了解一些比较基础的知识。可能你会觉得有点啰嗦了,但是为了照顾到不了解这些的童鞋,我还是多说几句吧:-)
表单处的设置
如果我们要想做一个上传文件功能,毫无疑问需要通过表单进行。因此,我们需要遵守一点规则。
<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>
以这个表单为例,我们不难发现。
enctype="multipart/form-data"
这行代码,其作用就是告诉服务器,我们的这个表单将用于文件上传处理。
服务器端
通过表单来实现上传固然很方便,但是除了文件项之外的表单项怎么处理呢? 这时我们就需要了解一下,关于apache-commons-fileupload
的文件处理了。
try {
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload uploadparser = new ServletFileUpload(factory);
uploadparser.setHeaderEncoding("UTF-8");
if (!ServletFileUpload.isMultipartContent(request)) {
return;
}
List<FileItem> files = uploadparser.parseRequest(request);
for (FileItem fileitem : files) {
if (fileitem.isFormField()) {
String name = fileitem.getFieldName();
String value = fileitem.getString("UTF-8");
System.out.println(name + " = " + value);
} else {
String filename = fileitem.getName();
System.out.println(fileitem);
if (filename == null || filename.trim().equals("")) {
continue;
}
filename = StringUtils.getFileName(filename);
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();
}
上传功能的实现
好了,下面开始上传功能的实现。
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>
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>
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 {
response.getWriter().append("Served at: ").append(request.getContextPath());
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 {
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload uploadparser = new ServletFileUpload(factory);
uploadparser.setHeaderEncoding("UTF-8");
if (!ServletFileUpload.isMultipartContent(request)) {
return;
}
List<FileItem> files = uploadparser.parseRequest(request);
for (FileItem fileitem : files) {
if (fileitem.isFormField()) {
String name = fileitem.getFieldName();
String value = fileitem.getString("UTF-8");
System.out.println(name + " = " + value);
} else {
String filename = fileitem.getName();
System.out.println(fileitem);
if (filename == null || filename.trim().equals("")) {
continue;
}
filename = StringUtils.getFileName(filename);
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 {
doGet(request, response);
}
}
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>
结果展示


文件浏览
要想实现下载功能,我们需要先给用户一个引导,那就是咱们的网站上有什么。所以我们需要对网站上提供下载的文件夹一个遍历。
思路如下:
Created with Raphaël 2.1.0定位到upload文件夹让业务逻辑在servlet中完成,获得存储了文件信息的Map集合将集合交给JSP页面进行展示用户获得页面视图
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();
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
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>();
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) {
if (!file.isFile()) {
File[] files = file.listFiles();
for (File f : files) {
listFile(f, filenameMap);
}
} else {
String realName = StringUtils.getFileName(file.getName());
try {
filenameMap.put(new String(file.getName().getBytes("iso8859-1"),"UTF-8"), realName);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
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>
<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>
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>
截图结果

注意
这里有几点容易出错的地方,大家需要注意。
路径问题
由于使用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();
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String filename = request.getParameter("filename");
filename = new String(filename.getBytes("iso8859-1"), "UTF-8");
String fileSaveRootPath = "E://Code/jee/File_upload_download/WebContent/WEB-INF/upload";
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;
int dir2 = (hashcode & 0xf0) >> 4;
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 {
doGet(request, response);
}
}
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>
截图展示


总结
最后关于整个项目的总结。使用apache-commons-fileupload
组件确实是很方便,它可以方便的将表单中上传的数据封装到一个List<fileItem>
中,我们只需要对这个集合进行遍历操作,就可以随意的设置自己需要的内容。
最后,希望大家看完之后都能有所收获。让自己的网站的功能更加的丰富。
完整的项目下载地址如下: https://github.com/guoruibiao/File_Upload_Download/。欢迎拍砖 :-)