Java web文件上传下载
[版权申明:本文系作者原创,转载请注明出处]
文章出处:http://blog.csdn.net/sdksdk0/article/details/52048666
作者:朱培 ID:sdksdk0 邮箱: zhupei@tianfang1314.cn
本文主要从javaweb上传文件到服务器中,并且在服务器端进行数据文件存储,主要分享了文件上传原理、使用第三方开源工具进行上传以及一些文件上传时需要注意的地方,文件的优化处理,还有简易分享了从我们刚才上传进去的文件进行下载。需要掌握基本的开发流程,底层实现原理等。
一、文件上传原理
- 提供form表单,method必须是post
- form表单的enctype必须是multipart/form-data
- 提供input type=”file”
Enctype属性
告知服务器请求正文的MIME类型。
application/x-www-form-urlencoded(默认):
正文:name=aa&password=123
服务器获取数据:request.getParameter(“name”);
文件上传原理:
解析请求正文的每部分的内容。
基于html form表单上传的数据都是以类似—————————–7da3c8e180752{0x130x10}这样的分割符来标记一块数据的起止。
文件上传的Content-Type为multipart/form-data; boundary=—-WebKitFormBoundaryhQslmBE7nbTLTJzD,而普通的form表单的Content-Type为application/x-www-form-urlencoded。因此,我们可以利用HttpServletRequest的request.getHeaderNames()方法和request.getHeaders(headName)方法得到请求头Headers中的Content-Type数据,然后根据Content-Type数据中是否包含multipart/form-data来区分请求是否为文件上传请求。其中boundary为文件数据的分隔符,用于区分上传多个文件。
二、使用第三方工具实现文件上传
fileupload组件工作流程:
开发步骤
导入commons-fileupload.jar、commons-io.jar包。
1、界面
我们就是需要一个form表单,为其添加enctype属性和post方法:
<form action="${pageContext.request.contextPath}/servlet/UploadServlet2" method="post" enctype="multipart/form-data" >姓名: <input type="text" name="name" /><br />照片: <input type="file" name="photo" /><br /><input type="submit" value="提交" /></form>
2、逻辑处理
我们在一个servlet中进行处理:
request.setCharacterEncoding("UTF-8");//判断用户的请求内容是不是multipart/form-databoolean isMultipart=ServletFileUpload.isMultipartContent(request);if(!isMultipart){throw new RuntimeException("error!");}
//创建DiskFileItemFactory对象
DiskFileItemFactory factory=new DiskFileItemFactory();
//创建核心解析类ServlertFileUploadServletFileUpload sfu=new ServletFileUpload(factory);//解析请求对象List<FileItem> items=new ArrayList<FileItem>(0);try {items=sfu.parseRequest(request);} catch (FileUploadException e) {// TODO Auto-generated catch blocke.printStackTrace();}for(FileItem item:items){if(item.isFormField()){processFormField(item);}else{processUploadField(item);}}response.getWriter().write("sucess!");
接下来就是分为两种情况了,一种是对普通的表单元素进行处理,另一种是对文件类的数据进行处理,对于第一种情况的话就比较简单,我们直接获取名字就可以了,基本上不用过多的处理。
private void processFormField(FileItem item) {String fieldName=item.getFieldName();String fieldValue=item.getString();System.out.println(fieldValue+"="+fieldName);}
对于第二种情况,需要我们直接对上传文件进行一系列的处理了,我们首先需要在服务器上找一个存放文件的地方,然后截取上传的文件名、构建输出流、关闭流等操作。
private void processUploadField(FileItem item) {try {InputStream in=item.getInputStream();String filename=item.getName();//在服务器上找一个存放文件的地方String storeDirectoryRealPath=getServletContext().getRealPath("/WEB-INF/files");File storeDirectory=new File(storeDirectoryRealPath);if(!storeDirectory.exists()){storeDirectory.mkdirs();}//截取上传的文件名//filename=filename.substring(filename.lastIndexOf(File.separator)+1);if(filename!=null){filename=FilenameUtils.getName(filename);}String guidFilename=GUIDUtil.generateGUID()+"_"+filename;//按日期来区分存储目录// String childDirectory=makeChileDirectory(storeDirectory);String childDirectory=makeChildDirectory(storeDirectory,guidFilename);//构建输出流OutputStream out=new FileOutputStream(new File(storeDirectory,childDirectory+File.separator+guidFilename));int len = -1;byte buf[] = new byte[1024];while((len=in.read(buf))!=-1){out.write(buf, 0, len);}in.close();out.close();} catch (IOException e) {e.printStackTrace();}}
三、文件上传优化处理
1、把保存的文件放在用户无法直接访问到的地方:例如放在:在WEB-INF/files目录中。
String storeDirectoryRealPath=getServletContext().getRealPath("/WEB-INF/files");
2、让文件名唯一。
String guidFilename=GUIDUtil.generateGUID()+"_"+filename;//构建输出流OutputStream out=new FileOutputStream(new File(storeDirectory,guidFilename));
3、避免同一个文件夹中的文件过多。
3.1按照日期进行存储。
String childDirectory=makeChileDirectory(storeDirectory);private String makeChileDirectory(File storeDirectory) {Date now=new Date();DateFormat df=new SimpleDateFormat("yyyy-MM-dd");String sdate=df.format(now);File f=new File(storeDirectory,sdate);if(!f.exists()){f.mkdirs();}return sdate;}
3.2用文件名的hashCode计算需要进行存储的目录,二级目录。
private String makeChildDirectory(File storeDirectory, String guidFilename) {int hashCode = guidFilename.hashCode();int dir1 = hashCode&0xf;// 0~15int dir2 = (hashCode&0xf0)>>4;//0~15String s = dir1+File.separator+dir2;File f = new File(storeDirectory,s);if(!f.exists()){f.mkdirs();}return s;}
4、限制文件的大小。web方式不适合上传大的文件。
4.1单个文件大小:
ServletFileUpload sfu=new ServletFileUpload(factory);sfu.setFileSizeMax(4*1024*1024);//限制不超过4M
4.2总文件大小:多文件上传
ServletFileUpload sfu=new ServletFileUpload(factory);sfu.setSizeMax(8*1024*1024);//总文件大小
5、限制文件的上传类型。
5.1通过文件扩展名来进行限制。
String extensionName=FilenameUtils.getExtension(filename);
5.2通过文件MIME类型来限制。
String mimeType=item.getContentType();
6、空文件上传解决方案。
判断文件名是否为空,当文件名为空时return。
7、临时文件
DiskFileItemFactory的作用是产生FileItem对象。其内部有一个缓存,默认大写拾10kb,如果上传文件超过10kb,则用磁盘作为缓存。存放缓存的目录默认是系统的临时目录。
DiskFileItemFactory factory=new DiskFileItemFactory();//更改临时文件的存放目录factory.setRepository(new File("D:/"));
如果是自己用IO流实现的文件上传,则需要在流关闭后,清理临时文件。
FileItem.delete();
可以使用FileItem.write(File f)实现文件上传的保存。
8、中文编码
request.setCharacterEncoding("UTF-8");//该编码要和jsp页面保持一致String fieldValue=item.getString("UTF-8");
9、动态js控制上传框
<form action="${pageContext.request.contextPath}/servlet/UploadServlet3" method="post" enctype="multipart/form-data">name:<input type="text" name="name"/><br/><div id="d1"><div>photo:<input type="file" name="photo"/><input type="button" value="继续上传" onclick="addFile()"/></div></div><input type="submit" value="上传"/></form><script type="text/javascript">function addFile(){var d1 = document.getElementById("d1");var oldInnerHtml = d1.innerHTML;d1.innerHTML=oldInnerHtml+"<div>photo:<input type='file' name='photo'/><input type='button' value='删除' onclick='deleteOne(this)'/></div>";}function deleteOne(delBtn){delBtn.parentNode.parentNode.removeChild(delBtn.parentNode);}</script>
四、文件的下载
首先我们来看一下页面的处理:
新建一个list.jsp文件:
全部资源如下:<br /><c:forEach items="${map}" var="me"><c:url value="/servlet/DownLoadServlet" var="url"><c:param name="filename" value="${me.key}"></c:param></c:url>${me.value} <a href="${url}">下载</a><br/></c:forEach>
要记得引入jstl的核心包 。
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
接下做界面显示的servlet。
我们之前上传的文件是用GUID做过相应处理的,是一个拼接好的文件名,用来防止文件同名的情况发生,这里用户浏览到的文件当然要和上传的时候的文件名 相同,所以这里我们要进行截取,把GUID拼接的前缀去掉,以“_”分开。一个是在服务器中防同名的文件名以及显示出来的截取后的文件名。这里以前面说过的,防同名文件方法2:用文件名的hashCode计算需要进行存储的目录,二级目录。这里也就需要使用hashCode找到做过文件的路径。
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {//key:GUID文件名 value:old文件名Map<String, String> map = new HashMap<String, String>();//获取/WEB-INF/files的真实路径String rootDirectoryRealPath = getServletContext().getRealPath("/WEB-INF/files");//递归遍历找出所有的文件System.out.println(rootDirectoryRealPath);File rootDirectory = new File(rootDirectoryRealPath);treeWalk(rootDirectory,map);//存到请求范围中,转发给jsp显示request.setAttribute("map", map);request.getRequestDispatcher("/list.jsp").forward(request, response);}//递归遍历找出所有的文件,把文件名高出来public void treeWalk(File file, Map<String, String> map) {if(file.isFile()){String guidFileName = file.getName();String oldFileName = guidFileName.substring(guidFileName.indexOf("_")+1);map.put(guidFileName, oldFileName);}else{//目录File[] childFiles = file.listFiles();for(File f:childFiles){treeWalk(f, map);}}}
接下来就是下载的处理了。
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {String guidFilename = request.getParameter("filename");//get方式提交的guidFilename = new String(guidFilename.getBytes("ISO-8859-1"),"UTF-8");//计算存放路径File storeDirectory = new File(getServletContext().getRealPath("/WEB-INF/files"));String childDirectory = makeChildDirecotry(storeDirectory, guidFilename);// 13/1//构建输入流InputStream in = new FileInputStream(new File(storeDirectory,childDirectory+File.separator+guidFilename));//用响应对象的输出流输出:下载的方式String oldFileName = guidFilename.substring(guidFilename.indexOf("_")+1);response.setHeader("Content-Disposition", "attachment;filename="+URLEncoder.encode(oldFileName,"UTF-8"));//不适用火狐response.setContentType("application/octet-stream");OutputStream out = response.getOutputStream();int len = -1;byte buf[] = new byte[1024];while((len=in.read(buf))!=-1){out.write(buf, 0, len);}in.close();}private String makeChildDirecotry(File storeDirectory, String guidFilename) {int hashCode = guidFilename.hashCode();int dir1 = hashCode&0xf;int dir2 = (hashCode&0xf0)>>4;String s = dir1+File.separator+dir2;File f = new File(storeDirectory,s);if(!f.exists()){f.mkdirs();}return s;}
通过这个网址进行访问
http://localhost:8080/UploadDemo/servlet/ShowAllFilesServlet
源码下载:https://github.com/sdksdk0/UploadDemo
Java web文件上传下载相关推荐
- Java Web 文件上传下载
文章目录 1文件上传概述 1.1文件上传的作用 1.2文件上传对页面的要求 1.3 比对文件上传表单和普通文本表单的区别 1.4 对普通文本表单的测试 1.5 文件上传对Servlet的要求 2 co ...
- centos nfs java_CentOS下安装配置NFS并通过Java进行文件上传下载
1:安装NFS (1)安装 yum install nfs-utils rpcbind (2)启动rpcbind服务 systemctl restart rpcbind.service 查看服务状态 ...
- java web文件上传所需要的commons-fileupload和 commons-io jar包
文章目录 一.官网获取 二.百度网盘分享 三.分享与热爱 一.官网获取 学习java web文件上传时需要用到两个必备的jar包: commons-fileupload commons-io jar ...
- java文件流 m.jb51.net_FasfDFS整合Java实现文件上传下载功能实例详解
今天使用Java代码实现文件的上传和下载.对此作者提供了Java API支持,下载fastdfs-client-java将源码添加到项目中.或者在Maven项目pom.xml文件中添加依赖 org.c ...
- SpringMVC整合fastdfs-client-java实现web文件上传下载
为什么80%的码农都做不了架构师?>>> 版权声明:本文为博主原创文章,转载请标明出处(http://blog.csdn.net/wlwlwlwl015)Thanks. 目录( ...
- 文件上传 java web_JavaWeb 文件上传下载
1. 文件上传下载概述 1.1. 什么是文件上传下载 所谓文件上传下载就是将本地文件上传到服务器端,从服务器端下载文件到本地的过程.例如目前网站需要上传头像.上传下载图片或网盘等功能都是利用文件上传下 ...
- web文件上传下载原理浅析
一.web文件上传浅析 现在有很多Web程序都有上传功能,实现上传功能的组件或框架也很多,如基于java的Commons FileUpload.还有Struts1.x和Struts2中带的上传文件功能 ...
- java web文件上传详解_java web图片上传和文件上传实例详解
java web图片上传和文件上传 图片上传和文件上传本质上是一样的,图片本身也是文件.文件上传就是将图片上传到服务器,方式虽然有很多,但底层的实现都是文件的读写操作. 注意事项 1.form表单一定 ...
- java web 文件上传和下载
在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直 ...
- java web 文件上传_Javaweb学习笔记10—文件上传与下载
今天来讲javaweb的第10阶段学习.文件的上传与下载,今天主要说的是这个功能的实现,不用说了,听名字就是外行人也知道肯定很重要啦. 老规矩,首先先用一张思维导图来展现今天的博客内容. ps:我的思 ...
最新文章
- (Alex note) Create a oracle database
- 网站服务器可以用虚拟主机吗,做网站虚拟主机可以用服务器吗
- python自动化办公入门书籍推荐-好书推荐 | Python 如此神奇,让繁琐工作自动化...
- The Web Audio autoplay policy will be re-enabled in 音频无法播放
- 【黑客帝国数字雨屏保】基于Win32的黑客帝国数字雨屏幕保护程序(附VS工程代码文件和可执行文件)
- Mac安装CentOS7
- jQuery扩展半Lambda表达式 类似Linq的Where
- Julia : 再谈HDF5 的save 和 load
- 精通Javascript+jQuery视频下载地址
- Junit4 安装与使用(IDEA)
- Word文档最后一页总是删除不掉怎么办?
- 2018年总结和计划
- 如何成为一个具有批判性思维的人?
- movieclip_Flash脚本-在Flash中更改Movieclip的颜色
- matlab斯奈尔定律,斯奈尔定律和Zoeppritz方程
- Linux性能调优,从优化思路说起
- [JZOJ5364]史莱姆
- 第九届“图灵杯”NEUQ-ACM部分汇总
- ELv2是一种什么样的存在?StarRocks为何惹众怒?
- VS2010模仿QQ2011登陆界面
热门文章
- 杂谈3G的方方面面及其必然之失败0.9Beta(转)
- 中介公司的故事(二)-Java动态代理
- Windows 上的分屏功能:编程指南
- 怎么看事务有没有开启成功_长春这所学校开启食堂托管项目,您怎么看
- Python | 条形图中的误差线
- 用C++ Builder编程监控打印机队列状态
- Local Solver 超大规模数学优化器/求解器介绍和试用
- WIN10 环境下 Tensorflow 检测不到GPU (GTX1050笔记本版可以安装CUDA)
- 【华为云】云硬盘 EVS 的简单使用
- 裁员四分之一后,爱彼迎的CEO展示了什么是领导力与人性