使用fileupload实现文件上传

Posted shaohsiung

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用fileupload实现文件上传相关的知识,希望对你有一定的参考价值。

一. 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作为文件名称















以上是关于使用fileupload实现文件上传的主要内容,如果未能解决你的问题,请参考以下文章

Java使用Commons-FileUpload组件实现文件上传最佳方案

Apache Commons fileUpload实现文件上传之一

利用 Commons-Fileupload 实现文件上传分析(转)

使用Commons FileUpLoad组件实现文件上传功能

使用commons-fileupload-1.2.1.jar等组件实现文件上传

FileUpload