文件上传
一、表单页面限制
1、method=”post”
2、enctype=”multipart/form-data”
3、表单中添加
二、服务端限制
request.getParametere(“xxx”);这个方法在表单为enctype=”multipart/form-data”时,它作废了,永远返回null
ServletInputStream request.getInputStream(); 包含整个请求体
服务端解析数据:
为了简化开发,使用commons-fileupload框架解析数据
commons-fileupload开发
一、创建工厂
二、创建解析器
三、获取表单每项数据
1、上传文件保存路径必须是WEB-INF目录,一般在WEB-INF目录下建个files用于存放
2、上传文件名称为绝对路径时,进行转换拿到文件名
int index = fileName.lastIndexOf("\\");
if (index != -1) {
fileName = fileName.substring(index + 1);
}
3、文件名称乱码,在所有的操作前设置request.setCharacterEncoding("UTF-8");
4、文件名同名问题
public static String getUUID() {
return UUID.randomUUID().toString().replace("-", "").toUpperCase();
}
fileName = CommonUtils.getUUID() + "_" + fileName;
5、上传目录打散(哈希打散)
//目录打散
int hCode = fileName.hashCode();// 得到哈希整型
String hex = Integer.toHexString(hCode);// 转成十六进制
// 获取十六进制前2位
String realPath = this.getServletContext().getRealPath("/WEB-INF/files");
File dir = new File(realPath, hex.charAt(0) + File.separator + hex.charAt(1));
dir.mkdirs();
File desFile = new File(dir, fileName);
//\WEB-INF\files\a\b\686E7ACDC900406A83679BC25BD2930A_ab.png
6、上传文件的大小限制
fileUpload.setSizeMax(fileSizeMax);设置上传文件大小4M
fileUpload.setFileSizeMax(sizeMax);设置请求总文件大小4M
以上设置在tomcat7.0.39没问题,但是在其他后续版本的tomcat版本就出问题了,也不知道是那个问题
所以没办法用以上办法来限制用户的上传
为了解决,我尝试了一个方法,就是自己来判断文件的大小,超出限制了就抛出同样的异常就可以了,
同样我们捕获异常提醒用户上传的文件大了
7、上传之缓存大小与临时目录
// 创建DiskFileItemFactory工厂,构造函数可以直接设置缓冲区和目录,也可以调用方法来设置
//创建是直接设置
DiskFileItemFactory factory = new DiskFileItemFactory(2 * 1024, new File("D:\\temp"));
//创建好再调用方法设置
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(2 * 1024);// 设置缓冲区大小,这里是2kb
factory.setRepository(new File("D:\\temp"));// 设置缓冲临时目录
代码:web
${msg }
<h1>上传</h1>
<form action="${pageContext.request.contextPath }/FileServlet" method="post" enctype="multipart/form-data">
用户名:<input type="text" name="username"><br/>
照 片:<input type="file" name="zhaoPian"><br/>
照 片:<input type="file" name="zhaoPian1"><br/>
照 片:<input type="file" name="zhaoPian2"><br/>
<input type="submit" value="上传">
服务器端代码:
request.setCharacterEncoding("UTF-8");
// 检测request中是否包含有multipart内容,就是文件上传的意思
if (ServletFileUpload.isMultipartContent(request)) {
try {
// 创建DiskFileItemFactory工厂,构造函数可以直接设置缓冲区和目录,也可以调用方法来设置
DiskFileItemFactory factory = new DiskFileItemFactory(2 * 1024, new File("D:\\temp"));
factory.setSizeThreshold(2 * 1024);// 设置缓冲区大小,这里是2kb
factory.setRepository(new File("D:\\temp"));// 设置缓冲临时目录
// 创建上传ServletFileUpload类,并将DiskFileFactory工厂传给它
ServletFileUpload fileUpload = new ServletFileUpload(factory);
// 设置编码,防止中文乱码
fileUpload.setHeaderEncoding("UTF-8");
// 定义好文件大小的限制和总大小的限制
long fileSizeMax = 4 * 1024 * 1024;
long sizeMax = 10 * 1024 * 1024;
// fileUpload.setSizeMax(fileSizeMax);设置上传文件大小4M
// fileUpload.setFileSizeMax(sizeMax);设置请求总文件大小4M
// 从request得到上传的文件列表
List<FileItem> list = fileUpload.parseRequest(request);
// 由于使用setSizeMax方法和setFileSizeMax方法设置限制上传文件大小会出现问题,所以自己写判断了,还是用抛出异常FileSizeLimitExceededException
// 这个for循环是为了校验文件大小限制的
long sizeCount = 0;
for (FileItem fileItem : list) {
long fileSize = fileItem.getSize();
sizeCount += fileSize;
if (!fileItem.isFormField() && fileSize > fileSizeMax) {
throw new FileSizeLimitExceededException(
fileItem.getName() + "文件大小" + fileSize + " ,超出了限制" + fileSizeMax, fileSize,
fileSizeMax);
}
if (sizeCount > sizeMax) {
throw new SizeLimitExceededException("文件总大小" + sizeCount + " ,超出了限制" + sizeCount, sizeCount,
sizeMax);
}
}
// 这个for循环是开始解析保存数据
for (FileItem fileItem : list) {
// FileItem fileItem = list.get(1);
if (fileItem.isFormField()) {// 判断是否是文件field,当是表单域时,进行的处理
String fieldName = fileItem.getFieldName();// 得到元素的name属性的值
String fieldValue = fileItem.getString("utf-8");// 得到元素的value的值
String fileName = fileItem.getName();// 这里是表单域,所以得到的是null
System.out.println(
"fieldName:" + fieldName + " fieldValue:" + fieldValue + " fileName:" + fileName);
} else {// 当是文件域时,将文件保存到硬盘中
String fileName = fileItem.getName();// 得到文件名
// 判断文件名是否是空的,空的就是没有文件数据,不用处理,跳过本条目
if (fileName == null || fileName.trim().isEmpty()) {
continue;
}
// 提取文件名,防止有的浏览器是全路径,如eclipse自带浏览器就是C:\Users\HC\Downloads\88107.rar
int index = fileName.lastIndexOf("\\");
if (index != -1) {
fileName = fileName.substring(index + 1);
}
// 根据文件名获取哈希值,转成十六进制,为目录打散做准备
int hCode = fileName.hashCode();
String hex = Integer.toHexString(hCode);
// 为了防止文件重名,加入uuid_前缀
fileName = UUID.randomUUID().toString().replace("-", "").toUpperCase() + "_" + fileName;
// 得到服务器保存路径
String savePath = this.getServletContext().getRealPath("/WEB-INF/files");
// 目录打散,加入哈希十六进制前2位,一位一目录名,上下关系,目录打散是为了打开没那么卡,所以文件都放同一个文件夹肯定卡的
File dir = new File(savePath, hex.charAt(0) + File.separator + hex.charAt(1));
dir.mkdirs();// 如果目录不存在就自动创建,存在就什么都不做
System.out.println(dir.getAbsolutePath());
// 得到最终的包含文件名的文件路径
File desFile = new File(dir, fileName);
// 创建输出流,用于保存文件
FileOutputStream fos = new FileOutputStream(desFile);
IOUtils.copy(fileItem.getInputStream(), fos);
fos.close();
}
}
request.setAttribute("msg", "上传成功");
request.getRequestDispatcher("/form2.jsp").forward(request, response);
} catch (FileSizeLimitExceededException e) {
// response.sendRedirect(this.getServletContext().getContextPath()+"/form1.jsp");
request.setAttribute("msg", e.getMessage());
request.getRequestDispatcher("/form2.jsp").forward(request, response);
e.printStackTrace();
} catch (SizeLimitExceededException e) {
request.setAttribute("msg", e.getMessage());
request.getRequestDispatcher("/form2.jsp").forward(request, response);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
文件上传限制问题解决方法参考:https://blog.csdn.net/adsl624153/article/details/72803626
https://blog.csdn.net/w47_csdn/article/details/76422357