在Servlet2.5中,我们要实现文件上传功能时,一般都需要借助第三方开源组件,例如Apache的commons-fileupload组件,在Servlet3.0中提供了对文件上传的原生支持,我们不需要借助任何第三方上传组件,直接使用Servlet3.0提供的API就能够实现文件上传功能了。
实现步骤
1)编写文件上传静态页面upload.html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>Servlet实现文件上传</h1>
<hr>
<form action="upload" enctype="multipart/form-data" method="post">
上传人:<input type="text" name="username">
选择文件:
<input type="file" name="upload">
<input type="submit" value="上传">
</form>
</body>
</html>
2)创建com.utils包,创建FileUtils工具类。
package com.utils;
import java.io.File;
import java.util.Map;
import java.util.UUID;
public class FileUtils {
/**
* 根据hash打散文件,然后获取保存目录
*
* @param filename 文件名称
* @param fileSaveRoot 文件保存根目录
* @return 文件实际保存目录
*/
public static String fileSave(String filename, String fileSaveRoot) {
int hash = filename.hashCode();
int dir1 = hash & 0xf;//0-15
int dir2 = (hash & 0xf0) >> 4;//0-15
String fileSavePath = fileSaveRoot + File.separator + dir1 + File.separator + dir2;
System.out.println(fileSavePath);
File file = new File(fileSavePath);
if (!file.exists()) {
//二级目录需要连续创建两个
file.mkdirs();
}
return fileSavePath;
}
// 防止文件提交上来重复名字,所以加上唯一的UUID
public static String makeFileName(String fileName) {
return UUID.randomUUID().toString() + "_" + fileName;
}
/**
*
* 主要是为了之后展示给用户看,带上UUID不是很难受?
*
* @param fileUUIDName UUID文件名
* @return 截取之后的名字
*/
public static String extractFileName(String fileUUIDName) {
int index = fileUUIDName.indexOf("_");
return fileUUIDName.substring(index + 1);
}
/**
* 递归遍历文件树,将值存进map中便于jsp展示
*
* @param f 文件
* @param map 存放文件的map,键是UUID名字,值是截取UUID后的
*/
public static void putFiles(File f, Map<String, String> map) {
File[] files = f.listFiles();
for (File file : files) {
if (file == null) {
//回溯点
return;
}
if (file.isDirectory()) {
putFiles(file, map);
} else {
String fileUUIDName = file.getName();
String fileName = extractFileName(fileUUIDName);
map.put(fileUUIDName, fileName);
}
}
}
}
3)在com.servlet包下创建FileUploadServlet
package com.servlet;
import com.utils.FileUtils;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.UUID;
@WebServlet(name = "FileUploadServlet", value = "/upload")
@MultipartConfig(maxFileSize = 1000 * 1024 * 1024,
maxRequestSize = 1000 * 1024 * 1024)
public class FileUploadServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//request.setCharacterEncoding("UTF-8");
String username = request.getParameter("username");
System.out.println("上传用户:" + username);
String savePathRoot = this.getServletContext().getRealPath("/WEB-INF/upload");
System.out.println(savePathRoot);
Collection<Part> parts = request.getParts();
for (Part part : parts) {
/*Collection<String> headerNames = part.getHeaderNames();
for (String name : headerNames) {
System.out.println(name);
}*/
//获得提交的名字
String filename = part.getSubmittedFileName();
System.out.println(filename);
//对于不是上传文件的input会传来空值,或者你没有指定上传的文件也是null,这里过滤一下
if (filename == null) {
continue;
}
String fileUUIDName = FileUtils.makeFileName(filename);
String saveDir = FileUtils.fileSave(fileUUIDName, savePathRoot);
/*long size = part.getSize();*/
//File.separator是自适应的windows和linux分隔符就是\\和/
part.write(saveDir + File.separator + fileUUIDName);
//删除临时文件
part.delete();
}
}
}
4)测试上传文件。 启动tomcat服务器,运行upload.html,测试文件上传。

控制台输出效果:
上传用户:张三丰
D:\servlet_course\out\artifacts\helloservlet_war_exploded\WEB-INF\upload
null
Tomcat简介001.png
D:\servlet_course\out\artifacts\helloservlet_war_exploded\WEB-INF\upload\1\5
可以在D:\servlet_course\out\artifacts\helloservlet_war_exploded\WEB-INF\upload\1\5目录下发现上传成功的文件a385e7c8-4fad-43e3-b449-bede79b61102_Tomcat简介001.png