我们需要先准备好2个apache的类:

上一个博客文章只讲了最简单的入门,现在来开始慢慢加深。

先过渡一下:只上传一个file项

index.jsp:

  1. <h2>用apache的工具处理文件上传</h2>
  2. <!-- 先过渡一下:只上传一个file项 -->
  3. <form action="<%= request.getContextPath() %>/upload" method="post" enctype="multipart/form-data">
  4. 文件:<input type="file" name="file"/><br/>
  5. <input type="submit" value="提交"/>
  6. </form>

web.xml:

  1. <servlet>
  2. <servlet-name>UploadServlet</servlet-name>
  3. <servlet-class>cn.hncu.servlets.upload.UploadServlet</servlet-class>
  4. </servlet>
  5. <servlet-mapping>
  6. <servlet-name>UploadServlet</servlet-name>
  7. <url-pattern>/upload</url-pattern>
  8. </servlet-mapping>

UploadServlet.java:

  1. package cn.hncu.servlets.upload;
  2. import java.io.File;
  3. import java.io.IOException;
  4. import java.io.PrintWriter;
  5. import java.util.List;
  6. import java.util.UUID;
  7. import javax.servlet.ServletException;
  8. import javax.servlet.http.HttpServlet;
  9. import javax.servlet.http.HttpServletRequest;
  10. import javax.servlet.http.HttpServletResponse;
  11. import org.apache.commons.fileupload.FileItem;
  12. import org.apache.commons.fileupload.FileUploadException;
  13. import org.apache.commons.fileupload.disk.DiskFileItemFactory;
  14. import org.apache.commons.fileupload.servlet.ServletFileUpload;
  15. import org.apache.commons.io.FileUtils;
  16. public class UploadServlet extends HttpServlet {
  17. public void doPost(HttpServletRequest request, HttpServletResponse response)
  18. throws ServletException, IOException {
  19. //下面这句解决上传文件名的中文乱码
  20. //注意。下面这句设置中文,如果是“multipart/form-data”表单,可以设置其中file组件的文件名,但对其中的普通表单组件无效
  21. //如果是"application/x-www-form-urlencoded"表单,可以设置其中的普通表单组件
  22. request.setCharacterEncoding("utf-8");
  23. //先获取所接收文件要保存的路径
  24. String path = getServletContext().getRealPath("/imgs");
  25. //文件上传需要临时目录(如果不指定,那么该目录就是tomcat/temp)
  26. File tempDiv = new File("E:/a");
  27. if(!tempDiv.exists()){
  28. tempDiv.mkdir();
  29. }
  30. DiskFileItemFactory fileFactory = new DiskFileItemFactory(1024*8, tempDiv);
  31. //创建用于解析文件的工厂类,同时设置缓存区的大小和位置
  32. //####思路的入口:
  33. ServletFileUpload upload = new ServletFileUpload(fileFactory);
  34. upload.setFileSizeMax(1024*1024*5);//设置单个文件上传最大为5M
  35. upload.setSizeMax(1024*1024*8);//所有上传文件大小之和的最大值,此处设最多能上传8M
  36. //setSizeMax方法用于设置请求消息实体内容的最大允许大小,以防止客户端故意通过上传特大的文件来塞满服务器端的存储空间,单位为字节。
  37. //以下开始解析:
  38. //parseRequest是从查询字符串和请求体中获取参数赋值到paramMap,然后格式化uri,填充Request对象实例
  39. try {
  40. List<FileItem> list = upload.parseRequest(request);
  41. for(FileItem fi:list){
  42. // isFormField()。isFormField方法用来判断FileItem对象里面封装的数据是一个普通文本表单字段,还是一个文件表单字段。
  43. //如果是普通文本表单字段,返回一个true否则返回一个false。
  44. //因此可以用该方法判断是否是普通表单域还是文件上传表单域。
  45. if(fi.isFormField()){
  46. //普通表单组件,如:<input type="text" name="name"/>
  47. String str = fi.getString("utf-8");//以指定编码的方式获取,来解决普通表单组件的中文乱码问题
  48. //将FileItem对象中保存的数据流内容以一个字符串返回。
  49. System.out.println("普通表单组件:"+str);
  50. }else{//文件组件
  51. String fileName = fi.getName();//获得上传文件的文件名
  52. System.out.println("fileName:"+fileName);
  53. //由于上传的文件“名字”可能会有中文,而服务器目录当中的资源名称不能够用中文(带中文的文件在浏览器中无法访问的),因此要把它转换成非中文的文件名(要考虑文件名不能重复)
  54. //于是,我们用java自带的UUID类,自动生成
  55. String uuid = UUID.randomUUID().toString().replace("-", "");//去掉uuid中的'-'
  56. String ext = fileName.substring(fileName.lastIndexOf("."));//截取文件的扩展名: .*
  57. //System.out.println("ext:"+ext);
  58. String newFileName = uuid+ext;//本地服务器存储的文件名
  59. //System.out.println("newFileName:"+newFileName);
  60. //真正的文件内容在fi.getInputStream() 当中
  61. FileUtils.copyInputStreamToFile(fi.getInputStream(), new File(path+"/"+newFileName));//拷贝的字节从InputStream源文件到目的地(file)。
  62. }
  63. }
  64. } catch (FileUploadException e) {
  65. throw new RuntimeException(e);
  66. }
  67. }
  68. }

演示结果:

在这个上传中,我们并没有把uuid和文件名联系起来,这样是不好的,必须用数据库把uuid和其对应的文件名存起来。以后下载的时候还给客户端一样的名字,而不是给他uuid的名字。

上传二个file项

index.jsp:


  1. <!-- 下面那个=号,代表整个输出request.getContextPath()的值 -->
  2. <form action="<%= request.getContextPath() %>/upload" method="post" enctype="multipart/form-data">
  3. 文件1:<input type="file" name="file"/><br/>
  4. 文件1的说明:<input type="text" name="desc1"/><br/>
  5. 文件2:<input type="file" name="file2"/><br/>
  6. 文件2的说明:<input type="text" name="desc2"/><br/>
  7. <input type="submit" value="提交"/>
  8. </form>

其他的相对前面的都没改动~

演示结果:

上传文件最终版:

index.jsp:

  1. <h2>进一步演示文件上传用法</h2>
  2. <form action="<%= request.getContextPath() %>/upload2" method="post" enctype="multipart/form-data">
  3. 文件1:<input type="file" name="file"/><br/>
  4. 文件1的说明:<input type="text" name="desc1"/><br/>
  5. 文件2:<input type="file" name="file2"/><br/>
  6. 文件2的说明:<input type="text" name="desc2"/><br/>
  7. <input type="submit" value="提交"/>
  8. </form>

web.xml:

  1. <servlet>
  2. <servlet-name>UploadServlet2</servlet-name>
  3. <servlet-class>cn.hncu.servlets.upload.UploadServlet2</servlet-class>
  4. </servlet>
  5. <servlet-mapping>
  6. <servlet-name>UploadServlet2</servlet-name>
  7. <url-pattern>/upload2</url-pattern>
  8. </servlet-mapping>

UploadServlet2.java:

  1. package cn.hncu.servlets.upload;
  2. import java.io.File;
  3. import java.io.IOException;
  4. import java.io.PrintWriter;
  5. import java.util.List;
  6. import java.util.UUID;
  7. import javax.servlet.ServletException;
  8. import javax.servlet.http.HttpServlet;
  9. import javax.servlet.http.HttpServletRequest;
  10. import javax.servlet.http.HttpServletResponse;
  11. import org.apache.commons.fileupload.FileItem;
  12. import org.apache.commons.fileupload.FileUploadException;
  13. import org.apache.commons.fileupload.ProgressListener;
  14. import org.apache.commons.fileupload.disk.DiskFileItemFactory;
  15. import org.apache.commons.fileupload.servlet.ServletFileUpload;
  16. public class UploadServlet2 extends HttpServlet {
  17. //防黑1---在地址栏直接提交的-我们要防住
  18. public void doGet(HttpServletRequest request, HttpServletResponse response)
  19. throws ServletException, IOException {
  20. response.setContentType("text/html;charset=utf-8");
  21. response.getWriter().print("不支持GET方式上传!!!");
  22. }
  23. public void doPost(HttpServletRequest request, HttpServletResponse response)
  24. throws ServletException, IOException {
  25. response.setContentType("text/html;charset=utf-8");
  26. final PrintWriter out = response.getWriter();//等会内部类需要用到这个变量,所以定义成final
  27. //防黑2--非multipart表单提交
  28. //手动方式
  29. String type = request.getContentType();
  30. if(!type.contains("multipart/form-data")){//如果此字符串包含 s,则返回 true,否则返回 false
  31. out.print("不支持普通表单提交");
  32. return;
  33. }
  34. DiskFileItemFactory fiFactory = new DiskFileItemFactory();
  35. fiFactory.setSizeThreshold(1024*8);//8k,缓存区大小
  36. File file = new File("d:/a");
  37. if(!file.exists()){
  38. file.mkdir();
  39. }
  40. fiFactory.setRepository(file);//设置缓存区
  41. /*
  42. ServletFileUpload类是Apache文件上传组件处理文件上传的核心高级类(所谓高级就是不需要管底层实现,暴露给用户的简单易用的接口)。
  43. 使用其 parseRequest(HttpServletRequest) 方法可以将通过表单中每一个HTML标签提交的数据封装成一个FileItem对象,然后以List列表的形式返回。
  44. */
  45. ServletFileUpload upload = new ServletFileUpload(fiFactory);
  46. upload.setHeaderEncoding("utf-8");//用于设置文件名的编码,相当于:request.setCharacterEncoding("utf-8");
  47. String path = getServletContext().getRealPath("/imgs");
  48. //文件上传进度功能---设置监听器
  49. upload.setProgressListener(new ProgressListener() {
  50. private int pre=0;
  51. //参数解析---pBytesRead:已上传字节数 pContentLength:上传的总字节数 pItems:文件序号(从1开始的)
  52. @Override
  53. public void update(long pBytesRead, long pContentLength, int pItems) {
  54. double d = pBytesRead*100.0/pContentLength;//计算百分比
  55. int dd = (int)d;
  56. if(pre!=dd){//防范输出一样的百分比
  57. out.print(dd+"%<br/>");
  58. pre=dd;
  59. }
  60. }
  61. });
  62. FileItem fi=null;
  63. try {
  64. List<FileItem> list = upload.parseRequest(request);
  65. for(FileItem fi2:list){
  66. fi=fi2;//相当于传指针,同一个对象
  67. if(fi.isFormField()){//普通表单组件
  68. String str = fi.getString("utf-8");
  69. System.out.println("普通表单组件提交的内容:"+str);
  70. }else{//表单中的:file组件
  71. //防黑3--在file组件中不选择文件
  72. if(fi.getSize()==0){
  73. continue;
  74. }
  75. //文件名
  76. String fileName = fi.getName();
  77. fileName = fileName.substring( fileName.lastIndexOf("\\")+1 );//这里就是文件名(后缀名也在的)
  78. String ext = fileName.substring( fileName.lastIndexOf(".") );// .* 后缀名
  79. //文件名不能用中文,必须转换成ascii码的格式,而且文件名不能重复(必须保证唯一),因此采用UUID来实现
  80. String newFileName = UUID.randomUUID().toString().replace("-", "");//去掉'-'
  81. newFileName = newFileName+ext;
  82. //打散目录(因为对于普通的机器,一个文件夹如果存储的文件个数超过1000个,性能就会急剧下降!!!)、
  83. String dir1 = Integer.toHexString( fileName.hashCode() & 0xf );
  84. String dir2 = Integer.toHexString( (fileName.hashCode() & 0xf0)>>4 );//右移四位
  85. String dir3 = Integer.toHexString( ( fileName.hashCode() & 0xf00 )>>8);
  86. File dir = new File(path+"/"+dir1+"/"+dir2+"/"+dir3);//16*16*16个文件夹
  87. if(!dir.exists()){
  88. dir.mkdirs();
  89. }
  90. File f = new File(dir+"/"+newFileName);
  91. fi.write(f);
  92. }
  93. }
  94. }catch (FileUploadException e) {
  95. throw new RuntimeException(e);
  96. } catch (Exception e) {
  97. throw new RuntimeException(e);
  98. } finally{
  99. if(fi!=null){
  100. fi.delete();//清临时文件
  101. }
  102. }
  103. }
  104. }

演示结果:

进行了一个文字型的文件上传进度,没办法啊,现在还没学AJax,做不了同步~~理解理解,后面会学到的。

注意看文件的保存目录!!!!(0-f)16进制的文件名~

我做了三层~

演示下中文路径的文件不能显示的实例:

  1. <img alt="中文路径不行" src="/myServletDemo3/imgs/图书1.jpg"/>

先移动这个图片到这个目录:

再看浏览器的访问结果:



无法访问到这个文件!!!!!!

进度条前台技术演示:

最后,我们自己来做个假的进度条看看:

其实只是少了aJax技术而已。

index.jsp:

  1. <a href="progress.jsp">进度条前台技术演示</a>

propress.jsp:

  1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
  2. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  3. <html>
  4. <head>
  5. <script type="text/javascript">
  6. var tm=0;
  7. function start(){
  8. a=0;
  9. if(tm!=0)
  10. window.clearInterval(tm);//也要防范一下,否则一直点启动。会出现很多的定时器。a+的速度会越来越快
  11. tm = window.setInterval(run, 100);
  12. }
  13. //真正开发的时候,应该是在run()方法中利用aJax到后台读取当前的进度值,
  14. //用该进度值对页面的进度条进行相应刷新,由于Ajax技术还没学,这里就我们自己模拟吧....
  15. var a=0;
  16. function run(){
  17. a+=1;
  18. if(a>100){
  19. window.clearInterval(tm);
  20. return;
  21. }
  22. var div=document.getElementById("dataDiv");
  23. div.style.width = a+"%";//把里面的div 对应的宽变长百分之一(背景色为红)
  24. }
  25. function stop(){
  26. window.clearInterval(tm);
  27. }
  28. function resume(){
  29. window.clearInterval(tm);//必须先把前面那个给清了。否则会出现前面那个对象无法访问到的情况
  30. tm = window.setInterval(run, 100);
  31. }
  32. </script>
  33. </head>
  34. <body>
  35. <h1>进度条前台技术演示</h1>
  36. <div style="border:1px solid red;width:400px;height:30px;">
  37. <div id="dataDiv" style="background:red;width:0%;height:100%;"></div>
  38. </div>
  39. <button onclick="start()">启动</button>
  40. <button onclick="stop()">停止</button>
  41. <button onclick="resume()">重新启动</button>
  42. </body>
  43. </html>

演示结果:

点启动按钮,就是从0%启动,运行到全部填充完毕(100%)就停止。

点停止按钮,就停止在当前进度,点重新启动,就是恢复启动~从暂停的地方继续~~

Web---文件上传-用apache的工具处理、打散目录、简单文件上传进度的更多相关文章

  1. 使用 ASMCMD 工具管理ASM目录及文件

    ============================== -- 使用ASMCMD 工具管理ASM目录及文件 --============================== 在ASM实例中,所有的 ...

  2. Apache Commons 工具类介绍及简单使用

    转自:http://www.cnblogs.com/younggun/p/3247261.html Apache Commons包含了很多开源的工具,用于解决平时编程经常会遇到的问题,减少重复劳动.下 ...

  3. Apache Commons 工具类介绍及简单使用(转载)

    原文链接 http://www.cnblogs.com/younggun/p/3247261.html Apache Commons包含了很多开源的工具,用于解决平时编程经常会遇到的问题,减少重复劳动 ...

  4. Java:Apache Commons 工具类介绍及简单使用

    Apache Commons包含了很多开源的工具,用于解决平时编程经常会遇到的问题,减少重复劳动.下面是我这几年做开发过程中自己用过的工具类做简单介绍. Commons简介 组件 功能介绍 commo ...

  5. 电脑和手机上常用apk或Pc软件的重要目录或文件或文件夹路径

    常用apk或Pc软件的重要目录或文件或文件夹路径 01.hosts文件位置在哪里 C:\Windows\System32\drivers\etc 02.Windows7的锁屏壁纸目录在哪 C:\Win ...

  6. 如何在CentOS上找出逐渐耗尽磁盘空间的目录和文件

    起因 随着系统运行,CentOS空间不断减少,对此非常焦虑,到底磁盘空间被哪些新增文件占用了呢? 分析过程,主要使用du命令,逐层找出消耗空间的目录 1.在根目录下检索一下文件的占用情况,执行du命令 ...

  7. tar命令: 对某目录文件打tar包时,排除指定的目录或文件

     如某当前目录存在以下文件或目录: 1.txt2.txt3.txtdir1dir2my2015.tarmy2016.tar 若要对当前目录除1.txt 和dir1.tar外,打包tar 步骤一.建立e ...

  8. Linux中/proc目录下文件详解(转贴)

      转载:http://www.sudu.cn/info/index.php?op=article&id=302529   Linux中/proc目录下文件详解(一) 声明:可以自由转载本文, ...

  9. Linux 目录和文件操作

    Linux常用命令--目录和文件操作 [目录]删除.复制.移动 : 1.删除文件夹用:rmdir 文件夹名 但是rmdir不能删除非空的文件夹,那如何删除非空文件夹呢: 2.通常情况下,删除文件用:r ...

随机推荐

  1. HDU 3555 Bomb (数位DP)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3555 题目大意:从0开始到给定的数字N所有的数字中遇到“49”的数字的个数. Sample Input ...

  2. OpenGl入门——视口及物体移动函数

    大学的时候有个选修课,要用OpenGl,很初级的内容,同样入门的学弟学妹适用 推荐个学习的资料NeHe的OpenGl教程,很完整而且有示例,讲的很明白.比某些破书好. 可以配合那本所谓的“红宝书”看看 ...

  3. 九度OJ 1113 二叉树

    题目地址:http://ac.jobdu.com/problem.php?pid=1113 题目描述: 如上所示,由正整数1,2,3……组成了一颗特殊二叉树.我们已知这个二叉树的最后一个结点是n.现在 ...

  4. Vivado Launching SDK "Importing Hardware Specification" error的解决方法

    解决方法是通过参考http://forum.digilentinc.com/topic/611-vivado-launching-sdk-importing-hardware-specificatio ...

  5. height为100%的问题

    问题描述 很多同学,对于设置div 的高度为100%时,有疑惑. 设置div 的高度为100%,意思是此 div 的高度 铺满父元素. 那么 怎么使 div 铺满浏览器屏幕? 代码 <!DOCT ...

  6. yaffs2文件系统

    1 .yaffs2源码目录文件复制到需要移植的linux内核目录fs/下 同时替换掉源码文件中的Makefile文件跟Kconfig文件. 2.在内核中添加对yaffs2的支持. 3.在make me ...

  7. wpf采用Xps实现文档显示、套打功能(原创)

    近期的一个项目需对数据进行套打,用户要求现场不允许安装office.页面预览显示必须要与文档完全一致,xps文档来对数据进行处理.Wpf的DocumentView 控件可以直接将数据进行显示,xps也 ...

  8. window.onresize 多次触发的解决方法

    用了window.onresize但是发现每次 onresize 后页面中状态总是不对,下面与大家分享下onresize 事件多次触发的解决方法. 之前做一个扩展,需要在改变窗口大小的时候保证页面显示 ...

  9. 树莓派-交叉编译环境搭建(Eclipse)

    转自别人的文章(http://www.cnblogs.com/emouse/archive/2013/06/07/3124063.html),一些看不清楚的图片替换了一下. In this blog  ...

  10. DM8168 debug continue... ...

    1.boot   VFS: Unable to mount root fs via NFS, trying floppy.   VFS: Cannot open root device "n ...