一. 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 ????@Override65 ????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实现文件上传(1)
原文地址:https://www.cnblogs.com/shaohsiung/p/9536901.html