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

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

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

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

index.jsp:

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

web.xml:

<servlet>
    <servlet-name>UploadServlet</servlet-name>
    <servlet-class>cn.hncu.servlets.upload.UploadServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>UploadServlet</servlet-name>
    <url-pattern>/upload</url-pattern>
  </servlet-mapping>

UploadServlet.java:

package cn.hncu.servlets.upload;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.UUID;

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.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;

public class UploadServlet extends HttpServlet {
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //下面这句解决上传文件名的中文乱码
        //注意。下面这句设置中文,如果是“multipart/form-data”表单,可以设置其中file组件的文件名,但对其中的普通表单组件无效
        //如果是"application/x-www-form-urlencoded"表单,可以设置其中的普通表单组件
        request.setCharacterEncoding("utf-8");

        //先获取所接收文件要保存的路径
        String path = getServletContext().getRealPath("/imgs");

        //文件上传需要临时目录(如果不指定,那么该目录就是tomcat/temp)
        File tempDiv = new File("E:/a");
        if(!tempDiv.exists()){
            tempDiv.mkdir();
        }

        DiskFileItemFactory fileFactory = new DiskFileItemFactory(1024*8, tempDiv);
        //创建用于解析文件的工厂类,同时设置缓存区的大小和位置

        //####思路的入口:
        ServletFileUpload upload = new ServletFileUpload(fileFactory);
        upload.setFileSizeMax(1024*1024*5);//设置单个文件上传最大为5M
        upload.setSizeMax(1024*1024*8);//所有上传文件大小之和的最大值,此处设最多能上传8M
        //setSizeMax方法用于设置请求消息实体内容的最大允许大小,以防止客户端故意通过上传特大的文件来塞满服务器端的存储空间,单位为字节。

        //以下开始解析:
        //parseRequest是从查询字符串和请求体中获取参数赋值到paramMap,然后格式化uri,填充Request对象实例
        try {
            List<FileItem> list = upload.parseRequest(request);
            for(FileItem fi:list){
                // isFormField()。isFormField方法用来判断FileItem对象里面封装的数据是一个普通文本表单字段,还是一个文件表单字段。
                //如果是普通文本表单字段,返回一个true否则返回一个false。
                //因此可以用该方法判断是否是普通表单域还是文件上传表单域。
                if(fi.isFormField()){
                    //普通表单组件,如:<input type="text" name="name"/>
                    String str = fi.getString("utf-8");//以指定编码的方式获取,来解决普通表单组件的中文乱码问题
                    //将FileItem对象中保存的数据流内容以一个字符串返回。
                    System.out.println("普通表单组件:"+str);
                }else{//文件组件
                    String fileName = fi.getName();//获得上传文件的文件名
                    System.out.println("fileName:"+fileName);
                    //由于上传的文件“名字”可能会有中文,而服务器目录当中的资源名称不能够用中文(带中文的文件在浏览器中无法访问的),因此要把它转换成非中文的文件名(要考虑文件名不能重复)
                    //于是,我们用java自带的UUID类,自动生成
                    String uuid = UUID.randomUUID().toString().replace("-", "");//去掉uuid中的'-'
                    String ext = fileName.substring(fileName.lastIndexOf("."));//截取文件的扩展名: .*
                    //System.out.println("ext:"+ext);
                    String newFileName = uuid+ext;//本地服务器存储的文件名
                    //System.out.println("newFileName:"+newFileName);
                    //真正的文件内容在fi.getInputStream() 当中
                    FileUtils.copyInputStreamToFile(fi.getInputStream(), new File(path+"/"+newFileName));//拷贝的字节从InputStream源文件到目的地(file)。
                }
            }
        } catch (FileUploadException e) {
            throw new RuntimeException(e);
        }

    }

}

演示结果:

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

上传二个file项

index.jsp:


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

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

演示结果:

上传文件最终版:

index.jsp:

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

web.xml:

 <servlet>
    <servlet-name>UploadServlet2</servlet-name>
    <servlet-class>cn.hncu.servlets.upload.UploadServlet2</servlet-class>
  </servlet>
<servlet-mapping>
    <servlet-name>UploadServlet2</servlet-name>
    <url-pattern>/upload2</url-pattern>
  </servlet-mapping>    

UploadServlet2.java:

package cn.hncu.servlets.upload;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.UUID;

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.FileUploadException;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

public class UploadServlet2 extends HttpServlet {

    //防黑1---在地址栏直接提交的-我们要防住
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().print("不支持GET方式上传!!!");
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        final PrintWriter out = response.getWriter();//等会内部类需要用到这个变量,所以定义成final

        //防黑2--非multipart表单提交
        //手动方式
        String type = request.getContentType();
        if(!type.contains("multipart/form-data")){//如果此字符串包含 s,则返回 true,否则返回 false
            out.print("不支持普通表单提交");
            return;
        }

        DiskFileItemFactory fiFactory = new DiskFileItemFactory();
        fiFactory.setSizeThreshold(1024*8);//8k,缓存区大小
        File file = new File("d:/a");
        if(!file.exists()){
            file.mkdir();
        }
        fiFactory.setRepository(file);//设置缓存区
        /*
         ServletFileUpload类是Apache文件上传组件处理文件上传的核心高级类(所谓高级就是不需要管底层实现,暴露给用户的简单易用的接口)。
         使用其 parseRequest(HttpServletRequest) 方法可以将通过表单中每一个HTML标签提交的数据封装成一个FileItem对象,然后以List列表的形式返回。
         */
        ServletFileUpload upload = new ServletFileUpload(fiFactory);
        upload.setHeaderEncoding("utf-8");//用于设置文件名的编码,相当于:request.setCharacterEncoding("utf-8");
        String path = getServletContext().getRealPath("/imgs");

        //文件上传进度功能---设置监听器

        upload.setProgressListener(new ProgressListener() {
            private int pre=0;

            //参数解析---pBytesRead:已上传字节数 pContentLength:上传的总字节数 pItems:文件序号(从1开始的)
            @Override
            public void update(long pBytesRead, long pContentLength, int pItems) {
                double d = pBytesRead*100.0/pContentLength;//计算百分比
                int dd = (int)d;
                if(pre!=dd){//防范输出一样的百分比
                    out.print(dd+"%<br/>");
                    pre=dd;
                }
            }
        });

        FileItem fi=null;
        try {
            List<FileItem> list = upload.parseRequest(request);
            for(FileItem fi2:list){
                fi=fi2;//相当于传指针,同一个对象
                if(fi.isFormField()){//普通表单组件
                    String str = fi.getString("utf-8");
                    System.out.println("普通表单组件提交的内容:"+str);
                }else{//表单中的:file组件

                    //防黑3--在file组件中不选择文件
                    if(fi.getSize()==0){
                        continue;
                    }

                    //文件名
                    String fileName = fi.getName();
                    fileName = fileName.substring( fileName.lastIndexOf("\\")+1 );//这里就是文件名(后缀名也在的)
                    String ext = fileName.substring( fileName.lastIndexOf(".") );// .*  后缀名

                    //文件名不能用中文,必须转换成ascii码的格式,而且文件名不能重复(必须保证唯一),因此采用UUID来实现
                    String newFileName = UUID.randomUUID().toString().replace("-", "");//去掉'-'
                    newFileName = newFileName+ext;

                    //打散目录(因为对于普通的机器,一个文件夹如果存储的文件个数超过1000个,性能就会急剧下降!!!)、
                    String dir1 = Integer.toHexString( fileName.hashCode() & 0xf );
                    String dir2 = Integer.toHexString( (fileName.hashCode() & 0xf0)>>4 );//右移四位
                    String dir3 = Integer.toHexString( ( fileName.hashCode() & 0xf00 )>>8);
                    File dir = new File(path+"/"+dir1+"/"+dir2+"/"+dir3);//16*16*16个文件夹
                    if(!dir.exists()){
                        dir.mkdirs();
                    }
                    File f = new File(dir+"/"+newFileName);
                    fi.write(f);
                }
            }
        }catch (FileUploadException e) {
            throw new RuntimeException(e);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally{
            if(fi!=null){
                fi.delete();//清临时文件
            }
        }
    }
}

演示结果:

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

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

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

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

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

再看浏览器的访问结果:


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

进度条前台技术演示:

最后,我们自己来做个假的进度条看看:
其实只是少了aJax技术而已。

index.jsp:

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

propress.jsp:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <script type="text/javascript">
        var tm=0;
        function start(){
            a=0;
            if(tm!=0)
                window.clearInterval(tm);//也要防范一下,否则一直点启动。会出现很多的定时器。a+的速度会越来越快
            tm = window.setInterval(run, 100);
        }
        //真正开发的时候,应该是在run()方法中利用aJax到后台读取当前的进度值,
        //用该进度值对页面的进度条进行相应刷新,由于Ajax技术还没学,这里就我们自己模拟吧....
        var a=0;
        function run(){
            a+=1;
            if(a>100){
                window.clearInterval(tm);
                return;
            }
            var div=document.getElementById("dataDiv");
            div.style.width = a+"%";//把里面的div 对应的宽变长百分之一(背景色为红)
        }
        function stop(){
            window.clearInterval(tm);
        }
        function resume(){
            window.clearInterval(tm);//必须先把前面那个给清了。否则会出现前面那个对象无法访问到的情况
            tm = window.setInterval(run, 100);
        }
    </script>

  </head>

  <body>
    <h1>进度条前台技术演示</h1>
    <div style="border:1px solid red;width:400px;height:30px;">
        <div id="dataDiv" style="background:red;width:0%;height:100%;"></div>
    </div>
    <button onclick="start()">启动</button>
    <button onclick="stop()">停止</button>
    <button onclick="resume()">重新启动</button>
  </body>
</html>

演示结果:

点启动按钮,就是从0%启动,运行到全部填充完毕(100%)就停止。
点停止按钮,就停止在当前进度,点重新启动,就是恢复启动~从暂停的地方继续~~

时间: 2024-10-22 01:06:51

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

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

--============================== -- 使用ASMCMD 工具管理ASM目录及文件 --==============================       在ASM实例中,所有的存储于ASM磁盘组中的文件对于操作系统命令而言是不可访问的,因此也无法使用常规的命令来操纵ASM磁盘中的文 件.所幸的是,我们有ASMCMD工具来代替操作系统命令来完成这部分工作.ASMCMD工具提供了类似于操作系统的常用命令,如ls , du ,find ,cd ,rm ,mkdi

ASM实例中使用ASMCMD工具管理ASM目录及文件

在ASM实例中,所有的存储于ASM磁盘组中的文件对于操作系统命令而言是不可访问的,因此也无法使用常规的命令来操纵ASM磁盘中的文件.所幸的是,我们有ASMCMD工具来代替操作系统命令来完成这部分工作.ASMCMD工具提供了类似于操作系统的常用命令,如ls , du ,find,cd ,rm ,mkdir等等.借助这些工具可以更轻松的完成ASM实例的相关管理工作. 1.ASMCMD文件所在的位置 [root@oradb ~]# su - oracle [oracle@oradb ~]$ which

php计算指定目录下文件占用空间的方法

 这篇文章主要介绍了php计算指定目录下文件占用空间的方法,实例分析了php操作目录及文件的技巧,具有一定参考借鉴价值,需要的朋友可以参考下     本文实例讲述了php计算指定目录下文件占用空间的方法.分享给大家供大家参考.具体分析如下: php中可以通过 RecursiveDirectoryIterator 扩展 DirectoryIterator的getChildren() 方法提供访问子目录中的每一个元素的方法,下面的代码通过遍历访问目录下的所有文件,获取他们暂用的空间. ? 1 2 3

PHP目录与文件操作技巧总结(创建,删除,遍历,读写,修改等)_php技巧

本文实例总结了PHP目录与文件操作技巧.分享给大家供大家参考,具体如下: Demo1.php <?php //将一个路径赋给一个变量 //它目前来说,只是一个字符串,字符串表示的是一个目录的路径 //文件名包含,文件的名称 + 文件的扩展名(就是.后面的文件类型) //文件的扩展名说白了就是文件后缀 $path = 'C:\AppServ\www\Basic6\Demo1.php'; // echo basename($path); // echo '<br/>'; // //dirna

文件上传之Apache commons fileupload使用

文件上传的方法主要目前有两个常用的,一个是SmartUpload,一个是Apache的Commons fileupload. 我们这里主要介绍下第二个的用法,首先要上传文件,注意几个问题: 1 form表单内,要添加空间<input type="file" name="myfile"> 2 form表单的内容格式要定义成multipart/form-data格式 3 需要类库:1 commons-io.jar 2commons-fileupload-1.

【ASP.NET Web API教程】5.3 发送HTML表单数据:文件上传与多部分MIME

原文:[ASP.NET Web API教程]5.3 发送HTML表单数据:文件上传与多部分MIME 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本系列教程,请先看前面的内容. 5.3 Sending HTML Form Data 5.3 发送HTML表单数据(2) 本文引自:http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-2 By Mike Wa

ASP.NET 图片上传工具类 upload image简单好用功能齐全

原文:ASP.NET 图片上传工具类 upload image简单好用功能齐全 使用方法: UploadImage ui = new UploadImage(); /***可选参数***/ ui.SetWordWater = "哈哈";//文字水印 // ui.SetPicWater = Server.MapPath("2.png");//图片水印(图片和文字都赋值图片有效) ui.SetPositionWater = 4;//水印图片的位置 0居中.1左上角.2右

用ASP技术实现在WEB网页上浏览目录及文件

web|网页 用ASP技术实现在WEB网页上浏览目录及文件 周仰平 摘要  目前在许多单位里,象WORD.EXCEL或WPS该类文档文件已成为重要的数据信息资源,在INTRANET WEB平台上如何高效率地管理这些信息资源是一个需要解决的问题.本文是利用ASP技术开发一个基于WEB的应用程序,实现在WEB页面上浏览目录文件,很轻易地做到诸如WORD.EXCEL和WPS等文档文件的查阅和下载,大大地减少信息维护的工作量. 关键词  ASP  WEB  文档文件   前言:在INTRANET平台上,

[sharepoint]rest api文档库文件上传,下载,拷贝,剪切,删除文件,创建文件夹,修改文件夹属性,删除文件夹,获取文档列表

写在前面 最近对文档库的知识点进行了整理,也就有了这篇文章,当时查找这些接口,并用在实践中,确实废了一些功夫,也为了让更多的人走更少的弯路. 系列文章 sharepoint环境安装过程中几点需要注意的地方 Rest API的简单应用 rest api方式实现对文档库的管理 通过WebClient模拟post上传文件到服务器 WebHttpRequest在sharepoint文档库中的使用 [sharepoint]Rest api相关知识(转) [sharepoint]根据用户名获取该用户的权限