文件上传
文件上传三要素
- 提供form表单,method必须是post
- form表单的enctype必须是multipart/form-data
- 提供 input type=“file” 类型输入
文件上传的细节
- 为保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如放于WEB-INF目录下
- 为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名
- 为防止一个目录下面出现太多文件,要使用hash算法打散存储
- 要限制上传文件的最大值
- 要限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法
以上传图片为例
从前端获取数据
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>文件上传</title>
</head>
<body>
<h2>文件上传</h2>
<%--条件:1.method必须是post 2.enctype="multipart/form-data" 提供input type="file"类型输入--%>
<form action="${pageContext.request.contextPath}/upload" method="post" enctype="multipart/form-data">
用户名:<input type="text" name="username"><br/>
附件1:<input type="file" name="file1"><br/>
附件2:<input type="file" name="file2"><br/>
<input type="submit" value="提交"><br/>
</form>
</body>
</html>
接收数据的Servlet
/**
*
* 注意:先添加注解
* @MultipartConfig
* maxFileSize 单个文件大小
* maxRequestSize 所有文件大小
*/
@WebServlet(name = "UploadServlet", value = "/upload")
@MultipartConfig(maxFileSize = 5*1024*1024, maxRequestSize = 50*1024*1024)
public class UploadServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//解决乱码
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
//1. 把上传的图片放到安全的目录下 /WEB-INF 这个路径下不能访问,安全问题!!!
String basepath = request.getServletContext().getRealPath("/WEB-INF/upload");
File dir = new File(basepath);
if (!dir.exists()){
dir.mkdirs();
}
//2.遍历文件,获取文件,使用getParts,而不是用getParameter()
Collection<Part> parts = request.getParts();
if (parts != null) {
for (Part part : parts) {
//3.1判断是不是文件
//所有名字 part.getName()
//是文件类型的名字 part.getSubmittedFileName()
if (part.getSubmittedFileName() == null){
//普通字段
System.out.println(part.getName() + " : " + request.getParameter(part.getName()));
} else {
//文件名,不同的浏览器会有问题
//String fileName = part.getSubmittedFileName();
//3.2判断有没有未提交的数据
//如果有不选的,则跳过
String fileName = part.getSubmittedFileName();
if (fileName == ""){
continue;
}
//获取请求头,获取文件名
String header = part.getHeader("content-disposition");
//找到以filename=开头的位置,往后10位开始截取,真的文件名路径在 filename="xxxx",所以往后取10个,截取到倒数第二个
String path = header.substring(header.indexOf("filename=") + 10, header.length() - 1);
//取出真正的文件名
String filename = path.substring(path.lastIndexOf("\\") + 1);
//3.3判断是不是想要的数据类型
//获取文件的后缀
String ext = filename.substring(filename.lastIndexOf(".") + 1);
List<String> allows = Arrays.asList("jpg", "png", "bmp");
//判断是不是想要的图片类型
if (!allows.contains(ext)) {
response.getWriter().write("不支持文件类型" + filename);
return;
}
//存入项目中!!!
part.write(UploadUtils.createNewPath(basepath, filename) + "/" + UploadUtils.createNewFilename(filename));
//删除缓存
part.delete();
System.out.println("上传成功");
//用到向浏览器写数据的时候,设置编码
response.getWriter().write("上传成功" + UploadUtils.createNewFilename(filename));
}
}
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
适用于所有浏览器,谷歌,IE,火狐…获取文件名
//获取请求头,获取文件名
String header = part.getHeader("content-disposition");
//找到以filename=开头的位置,往后10位开始截取,真的文件名路径在 filename="xxxx",所以往后取10个,截取到倒数第二个
String path = header.substring(header.indexOf("filename=") + 10, header.length() - 1);
//取出真正的文件名
String filename = path.substring(path.lastIndexOf("\\") + 1);
public class UploadUtils {
//确定名称是唯一的
public static String createNewFilename(String filename){
//UUID(唯一值) 36位 中间有4个 -
String s = UUID.randomUUID().toString().replace("-", "");
//用于后期拼接
return s + "_" + filename;
}
//用于打乱存储位置
public static String createNewPath(String basepath,String filename){
int hashCode = filename.hashCode();
int dir1 = hashCode & 0xf; //0-15
int dir2 = (hashCode & 0xf0) >> 4; //0-15
String newpath = basepath + "/" + dir1 + "/" + dir2;
File dir = new File(newpath);
if (!dir.exists()){
dir.mkdirs();
}
return newpath;
}
/**
* 把图片(图片中不能有_)的处理过的名字当做key,真正的名字当做值,存入map集合
* @param dir 遍历文件夹,找到所有图片
* @param map 使用key保存带有UUID的文件名,用value保存没有UUID文件名
*/
public static void listFiles(File dir, HashMap<String, String> map){
File[] files = dir.listFiles();
if (files != null) {
for (File file : files) {
if (file.isDirectory()){
listFiles(file, map);
} else {
map.put(file.getName(), file.getName().split("_")[1]);
}
}
}
}
}
下载
@WebServlet(name = "FileListServlet", value = "/filelist")
public class FileListServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String basepath = request.getServletContext().getRealPath("/WEB-INF/upload");
HashMap<String, String> filemaps = new HashMap<>();
UploadUtils.listFiles(new File(basepath), filemaps);
//把集合放入域
request.setAttribute("filemaps", filemaps);
//转发到前端展示
request.getRequestDispatcher("/list.jsp").forward(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
放到页面展示
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>下载列表</title>
</head>
<body>
<h1>下载列表</h1>
<c:forEach var="entry" items="${filemaps}">
${entry.value}<a href="${pageContext.request.contextPath}/down?filename=${entry.key}">下载</a><br/>
</c:forEach>
</body>
</html>
下载
@WebServlet(name = "DownServlet", value = "/down")
public class DownServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
//获取浏览器传来的路径,带uuid
String uuid_filename = request.getParameter("filename");
//获取到相同的参数,找到真实路径【巧妙获取真实路径】
String filename = uuid_filename.split("_")[1];
String basepath = request.getServletContext().getRealPath("/WEB-INF/upload");
//获取路径
String realpath = UploadUtils.createNewPath(basepath, filename);
FileInputStream fis = new FileInputStream(realpath + "/" + uuid_filename);
int len = -1;
byte[] buf = new byte[1024];
ServletOutputStream os = response.getOutputStream();
//设置下载
response.setHeader("content-disposition","attachment;filename" + URLEncoder.encode(filename, "utf-8"));
while ((len = fis.read(buf)) != -1){
os.write(buf, 0 ,len);
}
fis.close();
os.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}