一. fileupload组件工作原理
先来张图片, 帮助大家理解
fileupload核心API
1. DiskFileItemFactory
构造器
1) DiskFileItemFactory() // 使用默认配置
2) DiskFileItemFactory(int sizeThreshold, File repository)
sizeThreshold 内存缓冲区, 不能设置太大, 否则会导致JVM崩溃
repository 临时文件目录
2. ServletFileUpload
1) isMutipartContent(request) // 判断上传表单是否为multipart/form-data类型 true/false
2) parseRequest(request) // 解析request, 返回值为List<FileItem>类型
3) setFileSizeMax(long) // 上传文件单个最大值
4) setSizeMax(long) // 上传文件总量最大值
5) setHeaderEncoding(String) // 设置编码格式
6) setProgressListener(ProgressListener) // 设置监听器, 可以用于制作进度条
二. 使用fileupload实现文件上传
1. 编写JSP
1 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 <html> 3 <head> 4 <title>演示文件上传</title> 5 </head> 6 <body> 7 <form action="${pageContext.request.contextPath}/servlet/FileUpload1" method="post" enctype="multipart/form-data"> 8 用户名: <input type="text" name="username"/><br/> 9 文件1: <input type="file" name="file1"/><br/> 10 文件2: <input type="file" name="file2"/><br/> 11 <input type="submit"/> 12 </form> 13 </body> 14 </html>
要点:
1) 表单包含file类型输入项时, enctype属性必须设置为multipart/form-data
2) input:file必须指定name属性
3) 表单提交方式为post, 因为get请求无法携带大量数据
4) 若表单的提交方式为multipart/form-data, 那么在Servlet就无法使用getParameter方法获取表单数据, 可以通过获取客户机提交数据的输入流来获取所有上传数据, 然后进行解析.
1 // 获取客户机提交数据的输入流 2 request.getInputStream();
5) 解析数据难度较大, 一般不自己编写程序, 可以使用开源项目解析数据
2. 编写Servlet
1 public class FileUpload1 extends HttpServlet { 2 @Override 3 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 4 5 InputStream in = null; 6 OutputStream out = null; 7 8 try { 9 // 使用默认配置创建解析器工厂 10 DiskFileItemFactory factory = new DiskFileItemFactory(); 11 // 获取解析器 12 ServletFileUpload upload = new ServletFileUpload(factory); 13 // 上传表单是否为multipart/form-data类型 14 if (!upload.isMultipartContent(request)) { 15 return; 16 } 17 // 解析request的输入流 18 List<FileItem> fileItemList = upload.parseRequest(request); 19 // 迭代list集合 20 for (FileItem fileItem : fileItemList) { 21 if (fileItem.isFormField()) { 22 // 普通字段 23 String name = fileItem.getFieldName(); 24 String value = fileItem.getString(); 25 System.out.println(name + "=" + value); 26 } else { 27 // 上传文件 28 // 获取上传文件名 29 String fileName = fileItem.getName(); 30 fileName = fileName.substring(fileName.lastIndexOf("\\")+1); 31 // 获取输入流 32 in = fileItem.getInputStream(); 33 34 // 获取上传文件目录 35 String savePath = this.getServletContext().getRealPath("/WEB-INF/upload"); 36 // 上传文件名若不存在, 则先创建 37 File savePathDir = new File(savePath); 38 if (!savePathDir.exists()) { 39 savePathDir.mkdir(); 40 } 41 42 // 获取输出流 43 out = new FileOutputStream(savePath + "\\" + fileName); 44 int len = 0; 45 byte[] buffer = new byte[1024]; 46 while((len=in.read(buffer)) > 0) { 47 out.write(buffer, 0, len); 48 } 49 } 50 } 51 } catch (Exception e) { 52 e.printStackTrace(); 53 } finally { 54 if (in != null) { 55 in.close(); 56 } 57 if (out != null) { 58 out.close(); 59 } 60 } 61 62 } 63 64 @Override 65 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 66 doGet(req, resp); 67 } 68 }
1) 在WEB-INF中创建upload文件夹时. IDEA不会在out目录的WEB-INF中创建upload文件夹, 需要手动创建, 所以上面先检查upload文件夹是否存在
2) 在finally中关闭流时, 应该先检查流是否为null, 否则当上传表单不为multipart/form-data类型时, 执行return后再执行finally, 程序就会出现NPE
3) 记得在web.xml中配置servlet的映射路径
3. 测试
4. 使用浏览器抓包
三. 禁止别人访问上传文件目录
上传文件目录应该放在WEB-INF目录下, 禁止别人访问上传文件目录, 否则黑客可能通过上传脚本, 然后访问该脚本, 对网站发起攻击
举例:
1. 黑客上传一个JSP文件
test.jsp
1 <% 2 Runtime.getRuntime().exec("shutdown -s -t 200") // 执行Windows命令 3 %>
2. 通过访问该文件, 关闭服务器
http://localhost:8080/upload/test.jsp
备注:
1) Runtime类 // 调用Windows程序
2) Window命令:
shutdown -a
format c:\
四. 待解决的问题
1. 中文文件名乱码问题
2. 上传文件目录, 文件存储个数 -> 使用Hash算法打散
3. 文件覆盖问题 -> 使用UUID作为文件名称
原文地址:https://www.cnblogs.com/shaohsiung/p/9536901.html