文件上传
web应用中,经常会使用到文件的上传功能,其中有一些约束条件:
- 上传文件大小、格式的限制,一般前台js进行限制后,后台同样也需要限制
- 保证短之间内不让用户上传太多的文件
- 服务器端对文件结构的管理,不能暴露文件目录
- 防止文件被同名覆盖
- 有条件的情况下会和杀毒软件厂家对接,防止用户上传病毒或者恶意代码,比如CKnife
只需要commons-fileupload-1.3.2.jar和commons-io-2.5.jar
直接上代码
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>fileupload_mhm</display-name>
<servlet>
<servlet-name>upload</servlet-name>
<servlet-class>com.mhm.upload.FileUploadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>upload</servlet-name>
<url-pattern>/upload</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
/**
* 不用缓冲区的上传
*
* @author MHm
* @time 2017年8月10日下午5:15:39
*/
public class FileUploadServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException {
String message = "";
String savePath = this.getServletContext().getRealPath("/WEB-INF/upload");
File srcFile = new File(savePath);
if (!srcFile.exists() && !srcFile.isDirectory()) {
srcFile.mkdir();
}
// 使用commonFile
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setHeaderEncoding("utf-8");
if (!ServletFileUpload.isMultipartContent(req)) {
return;
}
InputStream in = null;
FileOutputStream fos = null;
try {
List<FileItem> list = upload.parseRequest(req);
for (FileItem it : list) {
if (it.isFormField()) {
String name = it.getFieldName();
String value = it.getString("utf-8");
System.out.println(name + ":" + value);
} else {
String filename = it.getName();
System.out.println(filename);
if (filename == null || filename.trim().equals("")) {
continue;
}
filename = filename.substring(filename.lastIndexOf("\\") + 1);
in = it.getInputStream();
fos = new FileOutputStream(savePath + "\\" + filename);
byte[] buffer = new byte[1024];
int len = 0;
while ((len = in.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
//
// 关闭输入流
// in.close();
// // 关闭输出流
// fos.close();
// 删除处理文件上传时生成的临时文件,关闭流之后再删除临时文件
it.delete();
message = message + filename + ":文件上传成功!" + File.separator;
}
}
} catch (FileUploadException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
in.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
req.setAttribute("message", message);
req.getRequestDispatcher("/pages/message.jsp").forward(req, resp);
} catch (IOException e) {
e.printStackTrace();
}
}
}
uploadFile.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>Insert title here</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/upload" 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>Insert title here</title>
</head>
<body>
${message }
</body>
</html>
使用临时文件管理的方式上传
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.UUID;
import javax.servlet.ServletException;
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.FileUploadException;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
/**
* 带临时目录缓冲区
*
* @author MHm
* @time 2017年8月10日下午5:15:39
*/
public class FileUploadTempServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException {
String message = "";
String fileTypeStr = "doc,docx,pdf,txt";
String savePath = this.getServletContext().getRealPath("/WEB-INF/upload");
String tempPath = this.getServletContext().getRealPath("/WEB-INF/temp");
File tempFile = new File(tempPath);
if (!tempFile.exists() && !tempFile.isDirectory()) {
tempFile.mkdir();
}
// 使用commonFile
// 1、创建一个DiskFileItemFactory工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
// 100KB缓冲区
factory.setSizeThreshold(1024 * 100);
// 设置上传时生成的临时文件的保存目录
factory.setRepository(tempFile);
// 2、创建一个文件上传解析器
ServletFileUpload upload = new ServletFileUpload(factory);
// 进度监听器
upload.setProgressListener(new ProgressListener() {
@Override
public void update(long byteRead, long contentLength, int arg2) {
System.out.println("文件大小为:" + contentLength + ",当前已处理:" + byteRead);
}
});
upload.setHeaderEncoding("utf-8");
// 是否普通表单提交
if (!ServletFileUpload.isMultipartContent(req)) {
return;
}
// 设置上传单个文件的大小的最大值,目前是设置为10MB
int fileSizeMax = 1024 * 1024 * 10;
upload.setFileSizeMax(fileSizeMax);
// 设置上传文件总量的最大值,最大值=同时上传的多个文件的大小的最大值的和,目前设置为10MB
int sizeMax = 1024 * 1024 * 10;
upload.setSizeMax(sizeMax);
InputStream in = null;
FileOutputStream fos = null;
try {
List<FileItem> list = upload.parseRequest(req);
for (FileItem it : list) {
if (it.isFormField()) {
String name = it.getFieldName();
String value = it.getString("utf-8");
System.out.println(name + ":" + value);
} else {
String filename = it.getName();
if (filename == null || filename.trim().equals("")) {
continue;
}
filename = filename.substring(filename.lastIndexOf("\\") + 1);
// 扩展名
String fileExtName = filename.substring(filename.lastIndexOf(".") + 1);
if (fileTypeStr.indexOf(fileExtName) == -1) {
System.out.println("上传的文件的扩展名是:" + fileExtName);
continue;
}
String saveFileName = UUID.randomUUID().toString() + "_" + filename;
String saveFilePathName = buildPath(saveFileName, savePath);
in = it.getInputStream();
fos = new FileOutputStream(saveFilePathName + "\\" + saveFileName);
byte[] buffer = new byte[1024];
int len = 0;
while ((len = in.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
//
in.close();
fos.close();
it.delete();
message = message + filename + ":文件上传成功!" + File.separator;
}
}
req.setAttribute("message", message);
req.getRequestDispatcher("/pages/message.jsp").forward(req, resp);
} catch (FileUploadException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
in.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* @param saveFileName
* @param savePath
* @return
*/
private String buildPath(String saveFileName, String savePath) {
int hashcode = saveFileName.hashCode();
int dir1 = hashcode & 0xf;
int dir2 = (hashcode & 0xf0) >> 4;
String dir = savePath + "\\" + dir1 + "\\" + dir2;
File file = new File(dir);
if (!file.exists()) {
// 创建目录
file.mkdirs();
}
return dir;
}
}
看看效果
2.文件下载
文件列表
<servlet>
<servlet-name>fileList</servlet-name>
<servlet-class>com.mhm.upload.FileListServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>fileList</servlet-name>
<url-pattern>/fileList</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>download</servlet-name>
<servlet-class>com.mhm.upload.DownloadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>download</servlet-name>
<url-pattern>/download</url-pattern>
</servlet-mapping>
jsp页面代码
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!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>Insert title here</title>
</head>
<body>
<!-- 遍历Map集合 -->
<c:forEach var="me" items="${fileNameMap}">
<c:url value="/download" var="downurl">
<c:param name="filename" value="${me.key}"></c:param>
</c:url>
${me.value}<a href="${downurl}">下载</a>
<br/>
</c:forEach>
</form>
</body>
</html>
文件列表查询:
/**
* @author MHm
* @time 2017年8月11日上午11:27:18
*/
public class FileListServlet extends HttpServlet{
/**
*
*/
private static final long serialVersionUID = 2692787517286234116L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String uploadFilePath = this.getServletContext().getRealPath("/WEB-INF/upload");
Map<String,String> fileNameMap = new HashMap<String,String>();
listFile(new File(uploadFilePath),fileNameMap);
req.setAttribute("fileNameMap", fileNameMap);
req.getRequestDispatcher("/pages/uploadFile.jsp").forward(req, resp);
}
private void listFile(File file,Map<String,String> map){
if(!file.isFile()){
File[] files = file.listFiles();
for(File f :files){
listFile(f,map);
}
}else{
String real_name = file.getName().substring(file.getName().indexOf("_")+1);
map.put(file.getName(), real_name);
}
}
}
文件下载:
package com.mhm.upload;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author MHm
* @time 2017年8月11日上午11:36:17
*/
public class DownloadServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException {
FileInputStream in = null;
OutputStream out = null;
try {
String fileName = req.getParameter("filename");
fileName = new String(fileName.getBytes("iso-8859-1"), "utf-8");
String realPath = this.getServletContext().getRealPath("/WEB-INF/upload");
String fileRealPath = buildPath(fileName, realPath);
// 得到要下载的文件
File file = new File(fileRealPath + "\\" + fileName);
// 如果文件不存在
if (!file.exists()) {
req.setAttribute("message", "您要下载的资源已被删除!!");
req.getRequestDispatcher("/pages/message.jsp").forward(req, resp);
return;
}
// 处理文件名
String realname = fileName.substring(fileName.indexOf("_") + 1);
// 设置响应头,控制浏览器下载该文件
resp.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(realname, "UTF-8"));
// 读取要下载的文件,保存到文件输入流
in = new FileInputStream(fileRealPath + "\\" + fileName);
// 创建输出流
out = resp.getOutputStream();
// 创建缓冲区
byte buffer[] = new byte[1024];
int len = 0;
// 循环将输入流中的内容读取到缓冲区当中
while ((len = in.read(buffer)) > 0) {
// 输出缓冲区的内容到浏览器,实现文件下载
out.write(buffer, 0, len);
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
// 关闭文件输入流
in.close();
// 关闭输出流
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* @param saveFileName
* @param savePath
* @return
*/
private String buildPath(String saveFileName, String savePath) {
int hashcode = saveFileName.hashCode();
int dir1 = hashcode & 0xf;
int dir2 = (hashcode & 0xf0) >> 4;
String dir = savePath + "\\" + dir1 + "\\" + dir2;
File file = new File(dir);
if (!file.exists()) {
// 创建目录
file.mkdirs();
}
return dir;
}
}