WEB文件上传之apache common upload使用(一)
文件上传一个经常用到的功能,它有许多中实现的方案。
页面表单 + RFC1897规范 + http协议上传
页面控件(flash/html5/activeX/applet) + RFC1897规范 + http协议上传
页面控件(flash/html5/activeX/applet) + 自定义数据规范 + http协议上传
页面控件(flash/html5/activeX/applet) + FTP协议上传
页面控件(flash/html5/activeX/applet) + 自定义协议
用apache common upload组件实际就是采用的“页面表单 + RFC1897规范 + http协议上传”实现方式,需要实现的技术点:
1. 多文件数据的提交
2. 文件数据包接收存储功能
3. 文件数据上传进度
4. WEB页面无刷新异步提交
时序图:
- 文件上传时序图
- 文件上传进度获取时序图
实现思路:
1. 多文件数据的提交
在WEB页面采用多个<input type="file">利用form表单进行文件提交
2. 文件数据包接收存储功能
服务端采用servlet,利用apache common upload组件接收解析数据包,接收解析的过程中保存进度到session, 文件接收完毕后保存到指定目录
3. 文件数据上传进度
在WEB页面在界面写一个定时器,定时访问服务器提供上传进度获取功能的servlet,获取文件上传进度信息
4. WEB页面无刷新异步提交
利用iframe来实现WEB页面无刷新异步上传
关键代码:
UploadFileServlet.java
Java代码
- package com.test.servlet;
- import java.io.File;
- import java.io.IOException;
- import java.io.Writer;
- import java.util.Iterator;
- import java.util.List;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import org.apache.commons.fileupload.FileItem;
- import org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException;
- import org.apache.commons.fileupload.disk.DiskFileItemFactory;
- import org.apache.commons.fileupload.servlet.FileCleanerCleanup;
- import org.apache.commons.fileupload.servlet.ServletFileUpload;
- import org.apache.commons.io.FileCleaningTracker;
- import org.apache.commons.io.FileUtils;
- import org.apache.commons.io.FilenameUtils;
- import org.apache.commons.io.IOUtils;
- import org.apache.commons.lang3.ArrayUtils;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- /**
- * 文件上传数据接收类
- *
- * @author chengqi
- *
- */
- public class UploadFileServlet extends HttpServlet {
- /** 日志对象*/
- private Log logger = LogFactory.getLog(this.getClass());
- private static final long serialVersionUID = 1L;
- /** 上传目录名*/
- private static final String uploadFolderName = "uploadFiles";
- /** 上传临时文件存储目录*/
- private static final String tempFolderName = "tempFiles";
- /** 上传文件最大为30M*/
- private static final Long fileMaxSize = 30000000L;
- /** 允许上传的扩展名*/
- private static final String [] extensionPermit = {"txt", "xls", "zip"};
- /** 统一的编码格式*/
- private static final String encode = "UTF-8";
- @Override
- protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- logger.info("UploadFileServlet#doPost() start");
- try {
- String curProjectPath = this.getServletContext().getRealPath("/");
- String saveDirectoryPath = curProjectPath + "/" + uploadFolderName;
- String tempDirectoryPath = curProjectPath + "/" + tempFolderName;
- File saveDirectory = new File(saveDirectoryPath);
- File tempDirectory = new File(tempDirectoryPath);
- logger.debug("Project real path [" + saveDirectory.getAbsolutePath() + "]");
- //上传时产生的临时文件的默认保存目录
- logger.debug("Temp files default save path [" + System.getProperty("java.io.tmpdir") + "]");
- DiskFileItemFactory factory = new DiskFileItemFactory();
- //DiskFileItemFactory中DEFAULT_SIZE_THRESHOLD=10240表示如果上传文件大于10K则会产生上传临时文件
- //上传临时文件的默认目录为java.io.tmpdir中保存的路径,根据操作系统的不同会有区别
- if(!tempDirectory.exists()) {
- tempDirectory.mkdir();
- }
- //重新设置临时文件保存目录
- factory.setRepository(tempDirectory);
- //设置文件清除追踪器,文件上传过程中产生的临时文件会在
- FileCleaningTracker fileCleaningTracker = FileCleanerCleanup.getFileCleaningTracker(this.getServletContext());
- factory.setFileCleaningTracker(fileCleaningTracker);
- ServletFileUpload upload = new ServletFileUpload(factory);
- //设置文件上传进度监听器
- FileProcessListener processListener = new FileProcessListener(request.getSession());
- upload.setProgressListener(processListener);
- // 设置文件上传的大小限制
- upload.setFileSizeMax(fileMaxSize);
- // 设置文件上传的头编码,如果需要正确接收中文文件路径或者文件名
- // 这里需要设置对应的字符编码,为了通用这里设置为UTF-8
- upload.setHeaderEncoding(encode);
- //解析请求数据包
- List<FileItem> fileItems = upload.parseRequest(request);
- //遍历解析完成后的Form数据和上传文件数据
- for (Iterator<FileItem> iterator = fileItems.iterator(); iterator.hasNext();) {
- FileItem fileItem = iterator.next();
- String fieldName = fileItem.getFieldName();
- String name = fileItem.getName();
- //如果为上传文件数据
- if(!fileItem.isFormField()) {
- logger.debug("fieldName[" + fieldName + "] fileName[" + name + "] ");
- if(fileItem.getSize() > 0) {
- String fileExtension = FilenameUtils.getExtension(name);
- if(!ArrayUtils.contains(extensionPermit, fileExtension)) {
- throw new NoSupportExtensionException("No Support extension.");
- }
- String fileName = FilenameUtils.getName(name);
- FileUtils.copyInputStreamToFile(fileItem.getInputStream(),
- new File(saveDirectory, fileName));
- }
- } else { //Form表单数据
- String value = fileItem.getString(encode);
- logger.debug("fieldName[" + value + "] fieldValue[" + fieldName + "]");
- }
- }
- responseMessage(response, State.OK);
- } catch(FileSizeLimitExceededException e) {
- logger.error(e.getMessage(), e);
- responseMessage(response, State.OVER_FILE_LIMIT);
- } catch(NoSupportExtensionException e) {
- logger.error(e.getMessage(), e);
- responseMessage(response, State.NO_SUPPORT_EXTENSION);
- } catch(Exception e) {
- logger.error(e.getMessage(), e);
- responseMessage(response, State.ERROR);
- } finally {
- //清除上传进度信息
- request.getSession().removeAttribute("fileUploadProcess");
- }
- logger.info("UploadFileServlet#doPost() end");
- }
- public enum State {
- OK(200, "上传成功"),
- ERROR(500, "上传失败"),
- OVER_FILE_LIMIT(501, "超过上传大小限制"),
- NO_SUPPORT_EXTENSION(502, "不支持的扩展名");
- private int code;
- private String message;
- private State(int code, String message) {
- this.code = code;
- this.message = message;
- }
- public int getCode() {
- return code;
- }
- public String getMessage() {
- return message;
- }
- }
- /**
- * 返回结果函数
- * @param response
- * @param state
- */
- private void responseMessage(HttpServletResponse response, State state) {
- response.setCharacterEncoding(encode);
- response.setContentType("text/html; charset=" + encode);
- Writer writer = null;
- try {
- writer = response.getWriter();
- writer.write("<script>");
- writer.write("window.parent.fileUploadCallBack({\"code\":" + state.getCode() +",\"message\":\"" + state.getMessage()+ "\"});");
- writer.write("</script>");
- writer.flush();
- writer.close();
- } catch(Exception e) {
- logger.error(e.getMessage(), e);
- } finally {
- IOUtils.closeQuietly(writer);
- }
- }
- }
GetFileProcessServlet.java
Java代码
- package com.test.servlet;
- import java.io.IOException;
- import java.io.Writer;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import org.apache.commons.io.IOUtils;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- /**
- * 文件上传进度获取Servlet
- *
- * @author chengqi
- *
- */
- public class GetFileProcessServlet extends HttpServlet {
- /** 日志对象*/
- private Log logger = LogFactory.getLog(this.getClass());
- private static final long serialVersionUID = 1L;
- @Override
- protected void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- logger.info("GetFileProcessServlet#doGet start");
- String fileUploadPercent = (String)request.getSession().getAttribute("fileUploadProcess");
- Writer writer = null;
- try {
- writer = response.getWriter();
- logger.info("percent:" + fileUploadPercent);
- IOUtils.write(fileUploadPercent == null ? "0%" : fileUploadPercent, writer);
- writer.flush();
- writer.close();
- } catch(Exception e) {
- logger.error(e.getMessage(), e);
- } finally {
- IOUtils.closeQuietly(writer);
- }
- logger.info("GetFileProcessServlet#doGet end");
- }
- }
FileProcessListener.java
Java代码
- package com.test.servlet;
- import java.text.NumberFormat;
- import javax.servlet.http.HttpSession;
- import org.apache.commons.fileupload.ProgressListener;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- /**
- * 文件进度监听器
- *
- * @author chengqi
- *
- */
- public class FileProcessListener implements ProgressListener{
- /** 日志对象*/
- private Log logger = LogFactory.getLog(this.getClass());
- private HttpSession session;
- public FileProcessListener(HttpSession session) {
- this.session = session;
- }
- public void update(long pBytesRead, long pContentLength, int pItems) {
- double readByte = pBytesRead;
- double totalSize = pContentLength;
- if(pContentLength == -1) {
- logger.debug("item index[" + pItems + "] " + pBytesRead + " bytes have been read.");
- } else {
- logger.debug("item index[" + pItems + "] " + pBytesRead + " of " + pContentLength + " bytes have been read.");
- String p = NumberFormat.getPercentInstance().format(readByte / totalSize);
- session.setAttribute("fileUploadProcess", p);
- }
- }
- }
apacheUploadDemo.html
Html代码
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <title>Apache common实现基本文件上传</title>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <script type="text/javascript" src="js/jquery/jquery-1.9.1.js"></script>
- <script type="text/javascript" src="js/jquery/jquery.form.js"></script>
- <script type="text/javascript">
- //定时器对象
- var uploadProcessTimer = null;
- $(function (){
- //绑定定时器开始操作到提交按钮
- $('input[type=submit]').click(function () {
- //启动上传进度查询定时器
- uploadProcessTimer = window.setInterval(getFileUploadProcess, 20);
- })
- });
- //获取文件上传进度
- function getFileUploadProcess() {
- $.get('/upload/getFileProcessServlet', function(data) {
- $('#fileUploadProcess').html(data);
- });
- }
- //上传完成后,由iframe返回脚本自动调用
- function fileUploadCallBack(res) {
- //清除定时器
- if(uploadProcessTimer) {
- window.clearInterval(uploadProcessTimer);
- }
- var message = res['message'];
- var code = res['code'];
- if(code != 200) {
- $('#fileUploadProcess').html('0%');
- }
- alert(message);
- }
- </script>
- </head>
- <body>
- <h2>上传文件1</h2>
- 用户信息: <br/>
- <form id="testForm" action="/upload/uploadServlet" method="post" enctype="multipart/form-data" target="iframeUpload">
- 姓名:<input name="name" type="text"> <br/>
- 附件1:<input name="file1" type="file" > <br/>
- 附件2:<input name="file2" type="file" > <br/>
- <br><br>
- <input type="submit" value="提交" ><br/>
- </form>
- 上传进度:<label id="fileUploadProcess"></label>
- <iframe name="iframeUpload" src="" width="350" height="35" frameborder=0 SCROLLING="no" style="display:NONE"></iframe>
- </body>
- </html>
总结:
虽然使用apache common upload组件实现了文件上传,但是从上传的效果来看,并不是一个很完美的解决方案。
有如下缺点:
1. 当有多个文件上传时,无法知道单个文件的上传进度,因为文件上传消息中根本就没有关于单个文件大小的信息
文件上传消息
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=UTF-8
Transfer-Encoding: chunked
Date: Tue, 22 Apr 2014 07:45:45 GMT
POST /upload/uploadServlet HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:28.0) Gecko/20100101 Firefox/28.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://localhost:8080/upload/apacheUploadDemo.html
Cookie: JSESSIONID=33498CE814284D67F957CA53D45F0174
Connection: keep-alive
Content-Length 2363
Content-Type multipart/form-data; boundary=---------------------------189163093917262
-----------------------------189163093917262
Content-Disposition: form-data; name="name"
-----------------------------189163093917262
Content-Disposition: form-data; name="file1"; filename="New Text Document.txt" Content-Type: text/plain
文件数据
-----------------------------189163093917262
Content-Disposition: form-data; name="file2"; filename="New Text Document (2).txt" Content-Type: text/plain
文件数据
-----------------------------189163093917262--
2. 浏览器必须将所有文件读取完毕才开始上传,并且是一次性提交所有的数据文件,在互联网环境下,会http连接超时,大文件无法上传成功。
3. 服务端判断是否超过大小限制,是通过计算接收数据的累积字节数和限制大小比较,这种情况下,如果限制大小是30M,那么在服务端已经读取了30M完成后才会抛出异常,多余的消耗的服务器的内存和硬盘空间
所以基于这些原因,页面表单 + RFC1897规范 + http协议上传 + 后台apache common upload组件接收的这种解决方案,不适合解决WEB页面一次多文件上传,大文件上传情况,比较适合一次单个小文件附件的情况,如:博客附件,登记照片上传,预览等情况。
WEB文件上传之apache common upload使用(一)相关推荐
- Java Web——文件上传(Apache Commons FileUpload实现上传图片DEMO)
基本概念 Apache Commons FileUpload :Apache Commons FileUpload组件提供了一种简单而灵活的方法,可以将对多部分文件上传功能的支持添加到Servlet和 ...
- WEB文件上传之JQuery ajaxfileupload插件使用(二)
1.JQuery ajaxfileupload插件使用准备 下载地址: http://www.phpletter.com/DOWNLOAD/ 2.原理分析 ajaxfileupload也是利用ifra ...
- web文件上传-0x00漏洞
文件上传-0x00漏洞 题目:2016全国大学生信息安全竞赛-web文件上传 原理 0x00漏洞:也称为%00阻断漏洞,0x00漏洞常见于Apache服务器后缀名称解析漏洞,不管文件最后后缀为什么,只 ...
- java web 上传附件_JAVA WEB文件上传步骤
JAVA WEB文件上传步骤如下: 实现 Web 开发中的文件上传功能,两个操作:在 Web 页面添加上传输入项,在 Servlet 中读取上传文件的数据并保存在本地硬盘中. 1.Web 端上传文件. ...
- web文件上传下载原理浅析
一.web文件上传浅析 现在有很多Web程序都有上传功能,实现上传功能的组件或框架也很多,如基于java的Commons FileUpload.还有Struts1.x和Struts2中带的上传文件功能 ...
- web文件上传(一)--文件上传与json上传区别及方法
Web文件上传方法总结大全 上传文件与与上传数据区别 上传数据主要指json等简单字符串,上传文件指的是上传word.excel图片等.在上传数据的时候enctype默认为第一个application ...
- 电脑无法上传html文件类型,HTML5 - 限制文件上传(HTML5 - Restrict file upload)
HTML5 - 限制文件上传(HTML5 - Restrict file upload) 上面的代码也允许上传.txt或任何类型的文件. 如何限制 html5中的其他文件类型 ? Above code ...
- java web文件上传所需要的commons-fileupload和 commons-io jar包
文章目录 一.官网获取 二.百度网盘分享 三.分享与热爱 一.官网获取 学习java web文件上传时需要用到两个必备的jar包: commons-fileupload commons-io jar ...
- WEB | 文件上传漏洞
做了一道关于文件上传的webCTF题,就想着系统地把文件上传漏洞的知识点整理一下,方便日后查阅. 一.什么是文件上传? 文件上传包括了上传头像,上传相册,上传附件,添加新闻图片,自定义主题背景,新闻投 ...
最新文章
- object-c 常见问题
- linux文件夹前的描述,Linux对内存结构的描述
- python 实例方法调用时可以忽略第一个参数_盘点Python中易忽略的函数
- delphi TWebBrowser组件使用详解
- Springboot 集成 Swagger
- 懒惰的人有福了——VS代码段编辑器SnippetEditor 可对vs所有代码段进行编辑和创建包括C#\J#\VB.NET等...
- LeetCode 热题 HOT 100 完整题解笔记知识点分类 C++代码实现
- webgl渲染Yuv420P图像
- setTimeout(), nextTick(),setImmediate()区别 ZT~
- java 分词搜索_基于JAVA的小型中文分词系统
- 9款主流图表控件轻松实现数据可视化
- SNP基因数据质控调研
- python运行环境怎么配置_python配置环境 菜鸟教程,python的运行环境怎么配置
- R语言单因素方差分析(附代码)
- 面试题:打印螺旋数字
- Ubuntu中快速打开终端
- 打印银行类,创建银行,实现存钱,取钱,转账
- 纽脉医疗冲刺港交所上市:核心人员从微创医疗出走,创业后被起诉
- 想系统的学习运维有什么需要注意的?
- doraemon的python 字典
热门文章
- 域服务器怎么修改管理员密码,域服务器更改客户端管理员的密码
- c++设置单元格填充色_格式函数text,设置自定义格式的万金油
- mysql 数据库还原 不齐_请教mysql数据库还原问题。
- android 绕过root检测,公主连结怎么绕过root检测 绕过root检测方法一览
- Xcode and Unity missing library ‘lGoogleUtilities‘
- html css animation,css animation是什么?
- Vim删除文件到行首或者行尾
- [T-ARA][그녀를 보면][看着那个女人的话]
- 搜索引擎ElasticSearchV5.4.2系列一之ES介绍
- H5网页播放器播不了服务器上的mp4视频文件