`
115893520
  • 浏览: 142653 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

java web 文件文件上传

阅读更多

 今日学习的主要内容是——文件的上传与下载,下载我们在之前的学习中已经有实现过。主要就是上传文件的功能。上传文件看似简单,但一项成熟的应用是需要考虑到诸多问题的。下面就让我们一起来学习吧!

实现WEB开发中的文件上传功能,需完成如下二步操作:

在WEB页面中添加上传输入项,<input type=“life” name=“”>,使用时注意:

1.          必须要设置input输入项的name属性,否则浏览器将不会发送上传文件的数据。

2.          必须把input项的enctype属值设为multipart/form-data.设置该值后,浏览器在上传文件时,将把文件数据附带在http请求消息体中,并使用MIME协议对上传的文件进行描述,以方便接收方对上传数据进行解析和处理。

 

如何在Servlet中读取文件上传数据,并保存到服务器本地硬盘中?

     Request对象提供了一个getInputStream()方法,使用这个方法可以获取浏览器提交过来的输入流。但如果浏览器上传多个文件时,我们应该如何区分开来?这是一项复杂的工作。

     为了方便用户处理文件上传数据,Apache开源组织提供了用于处理上面应用的开源组件——Commons-fileupload。这个组件使用简单,性能也比较优异,所以几乎都使用它来实现上传文件的处理功能。Struts的上传文件处理部分也是使用它实现的。

   

Fileupload组件工作流程:


WEB服务器

request

ServletFil

eupLoad

DiskFileItem

Factory

代表普通字段的

FileItem

代表上传文件1

FileItem

代表上传文件2

FileItem

isFileForm

getFieldName

getString

getInputStream

getName

getInputStream

getName

 

核心API-DiskFileItemFactory:

     DiskFileItemFactory是创建FileItem对象的工厂,这个工厂常用方法:

1.      public DiskFileItemFactory(int sizeThreshold, java.io.File repository),常用的构造函数。

2.      public void setSizeThreshold(int sizeThreshold),设置内存缓冲区的大小,默认值为10K。当上传文件大于缓冲区大小时, fileupload组件将使用临时文件缓存上传文件。

3.      public void setRepository(java.io.File repository),指定临时文件目录,默认值为System.getProperty("java.io.tmpdir")。

       

核心API-ServletFileupLoad:

ServletFileUpload 负责处理上传的文件数据,并将表单中每个输入项封装到一个FileItem对象中。常用方法有:

1.      boolean isMultipartContent(HttpServletRequest request),判断上传表单是否为上传表单类型。

2.      List parseRequest(HttpServletRequest request),解析request对象,并把表单中的每一个输入项包装到一个fileItem 对象中,并返回一个保存了所有FileItem的list集合。

3.      setFileSizeMax(long fileSizeMax),设置上传文件的最大尺寸值。

4.      setSizeMax(long sizeMax),设置上传文件总量的最大值。

5.      setHeaderEncoding(java.lang.String encoding),设置编码格式。如果文件路径中存在中文可能会造成文件路径乱码,用此方法处理可以解决。

6.      setProgressListener(ProgressListener pListener),设置进程监听器,与AWT和Swing的事件处理机制一样。文件上传一点就会触发ProgressListener,这样我们就可以获取文件上传的进度。

 

上传文件案例:

public class FileuploadServlet extends HttpServlet {

 

    public void doGet(HttpServletRequest request, HttpServletResponse response)

           throws ServletException, IOException {

       // 创建文件处理工厂,它用于生成FileItem对象。

       DiskFileItemFactory difactory = new DiskFileItemFactory();

       //设置缓存大小,如果上传文件超过缓存大小,将使用临时目录做为缓存。

       difactory.setSizeThreshold(1024 * 1024);

 

       // 设置处理工厂缓存的临时目录,此目录下的文件需要手动删除。

       String dir = this.getServletContext().getRealPath("/");

       File filedir = new File(dir + "filetemp");

       if (!filedir.exists())

           filedir.mkdir();

       difactory.setRepository(filedir);

 

       // 设置文件实际保存的目录

       String userdir = dir + "files";

       File fudir = new File(userdir);

       if (!fudir.exists())

           fudir.mkdir();

 

       // 创建request的解析器,它会将数据封装到FileItem对象中。

       ServletFileUpload sfu = new ServletFileUpload(difactory);

       // 解析保存在request中的数据并返回list集合

       List list = null;

       try {

           list = sfu.parseRequest(request);

       } catch (FileUploadException e) {

           e.printStackTrace();

       }

 

       // 遍历list集合,取出每一个输入项的FileItem对象,并分别获取数据

       for (Iterator it = list.iterator(); it.hasNext();) {

           FileItem fi = (FileItem) it.next();

           if (fi.isFormField()) {

              System.out.println(fi.getFieldName());

              System.out.println(fi.getString());

           } else {

              //由于客户端向服务器发送的文件是客户端的全路径,在这我们只需要文件名即可

              String filename = fi.getName();

              int index = filename.lastIndexOf("\\");

              if(index != -1)

                  filename = filename.substring(index+1);

              //向服务器写出文件

              InputStream in = fi.getInputStream();

              FileOutputStream fos = new FileOutputStream(fudir + "/" +filename);

              byte[] buf = new byte[1024];

              int len = -1;

              while((len = in.read(buf)) != -1){

                  fos.write(buf, 0, len);

              }

              // 关闭流

              if(in != null){

                  try{

                     in.close();

                  }finally{

                     if(fos!=null)

                         fos.close();

                  }

              }

           }

       }

    }

 

    public void doPost(HttpServletRequest request, HttpServletResponse response)

           throws ServletException, IOException {

       doGet(request, response);

    }

}

 

上面的代码只是功能的练习,实际开发中的文件上传需要考虑诸多因素,我们接下来继续学习。

   

JS动态添加文件上传框和按钮的JavaScript代码:

function add(){

           var file = document.createElement("input");

           file.type = "file";

           file.name = "file";

         

           var butt = document.createElement("input");

           butt.type = "button";

           butt.value = "删除";

           butt.onclick = function rem(){

           //必须使用按钮的父节点DIV的父节点来删除自己和自己的父节点DIV。

               this.parentNode.parentNode.removeChild(this.parentNode);

           };

         

           var div = document.createElement("div");

           div.appendChild(file);

           div.appendChild(butt);

         

           var parent = document.getElementById("files");

           parent.appendChild(div);

        }

 

上传文件的处理细节(1):

1.      中文文件乱码的问题,可以调用两个方法来设置字符编码:servletUpLoader.setHeaderEncoding()或request.setCharacterEncoding()。我们可以在源文件的创建ServletFileUpload对象后边添加如下代码:

sfu.setHeaderEncoding("UTF-8");

 

2.      临时文件的删除,如果临时文件大于setSizeThreshold设置的缓存大小,Commons-fileupload组件将使用setRepository设置的临时目录来保存上传的文件,上传完成后我们需要手动调用FileItem.delete来删除临时文件。建议不要修改缓存区大小,如果设置缓存为1MB,1000个用户上传文件就需要1000MB内存,服务器会受不了的。我们删除掉setSizeThreshold的代码,并在每次完成一个文件后添加下而的代码:

// 删除临时目录中的文件

fi.delete();

 

上传文件的处理细节(2):

1.      在上面的代码中,我们将文件的实际保存目录设置在WEB-INF目录之外。这样外部可以直接访问被上传的文件,这会造成安全问题。比如用户上传了一个带有恶意脚本功能的JSP文件,然后从外部访问执行了JSP文件…后果不堪设想。所以我们将源代码中对应位置处修改如下:

// 之所以放在"WEB-INF"目录下是为了防止上传的文件被直接被访问的安全问题

String userdir = dir + "WEB-INF/files";

 

2.      一个WEB应用会许多不同的用户访问,不同的用户可能会上传相同名称的文件,如果这样可能会造成文件覆盖的情况发生,所以我们必须保证文件名称的唯一性,我编写一个方法来生成唯一性名称的文件名:

/**

     * 生成具有唯一性的UUID文件名称

     * @param fileName

     * @return

     */

    private String uuidName(String fileName){

       UUID uuid = UUID.randomUUID();

       return uuid.toString() + "_" + fileName;

    }

我们将代码“filename = filename.substring(index + 1);”修改为:filename = uuidName(filename.substring(index + 1));

 

3.      如果一个目录下的文件过多,会极大减慢文件的访问速度。比如一个目录下的文件如果超过1000个,达到1万个呢?恐怖!我们必须编写一个目录结构生成算法,来分散存上传的文件。我们一个方法:

    /**

     * 使用哈希算法生成的文件路径

     * @param dir

     * @param fileName

     * @return

     */

    private String hashPath(String dir, String fileName) {

       int hashCode = fileName.hashCode();

     

       int dir1 = (hashCode >> 4) & 0xf;

       int dir2 = hashCode & 0xf;

     

       String newpath = dir + "/" + dir1 + "/" + dir2 + "/";

       File file = new File(newpath);

       if(!file.exists()){

           file.mkdirs();

       }

     

       return newpath + uuidName(fileName);

    }

 

上传文件的处理细节(3)

1.      使用ProgressListener显示上传文件进度,在创建ServletFileUpload之后添加如下代码:

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

       sfu.setProgressListener(new ProgressListener() {

           public void update(long pBytesRead, long pContentLength, int pItems) {

              System.out.println("已上传:" + pBytesRead + " 总大小:"

                     + pContentLength);

           }

});

2.      上面的代码会造成频繁的打印,为了使它在上传一定数量后再打印,比如上传10KB后再打印,我们修改上面的代码如下:

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

       sfu.setProgressListener(new ProgressListener() {

           long temp = -1;

 

           public void update(long pBytesRead, long pContentLength, int pItems) {

              long size = pBytesRead / 1024 * 1024 * 10;

              if(temp == size)

                  return;

              temp = size;

              if(pBytesRead != -1)

                  System.out.println("已上传:" + pBytesRead + " 总大小:"

                     + pContentLength);

              else

                  System.out.println("上传完成!");

           }

});

上面的代码比较经典,好好回味一下。

 

文件下载:

    WEB应用中实现文件下载的两种方式:

1.         超链接直接指向下载资源

2.         程序实现下载需设置两个响应头:

(1).  设置Content-Type 的值为:application/x-msdownload。Web 服务器需要告诉浏览器其所输出的内容的类型不是普通的文本文件或 HTML 文件,而是一个要保存到本地的下载文件。

(2).  Web 服务器希望浏览器不直接处理相应的实体内容,而是由用户选择将相应的实体内容保存到一个文件中,这需要设置 Content-Disposition 报头。该报头指定了接收程序处理数据内容的方式,在 HTTP 应用中只有 attachment 是标准方式,attachment 表示要求用户干预。在 attachment 后面还可以指定 filename 参数,该参数是服务器建议浏览器将实体内容保存到文件中的文件名称。在设置 Content-Dispostion 之前一定要指定 Content-Type。

 

     为实现文件下载,首先我们遍历目录下所有文件,Servlet:

import java.io.File;

import java.io.IOException;

import java.util.HashMap;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

 

 

public class ListFileServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)

           throws ServletException, IOException {

       // 获取目录

       String dir = this.getServletContext().getRealPath("/WEB-INF/files");

       HashMap map = new HashMap();

       listFile(new File(dir), map);

       // 将文件列表设置到request的属性中,然后由JSP页面打印列表。

       request.setAttribute("filemap", map);

       request.getRequestDispatcher("/list.jsp").forward(request, response);

    }

 

    /**

     * 使用递归算法,将所有子目录中的文件添加到列表中

     *

     * @param f

     * @param l

     */

    private void listFile(File f, HashMap map) {

       if (f.isFile()) {

           String path = f.getAbsolutePath().substring(

                  this.getServletContext().getRealPath("/").length());

           String name = f.getName();

           name = name.substring(name.indexOf("_")+1);        

           //BASE64Encoder encoder = new BASE64Encoder();

           map.put(path, name);

       } else {

           File[] files = f.listFiles();

           for (int i = 0; i < files.length; i++) {

              listFile(files[i], map);

           }

       }

 

    }

 

    public void doPost(HttpServletRequest request, HttpServletResponse response)

           throws ServletException, IOException {

       doGet(request, response);

    }

}

分享到:
评论

相关推荐

    java web文件上传-下载-查看操作.docx

    Java Web 文件上传、下载、查看操作 Java Web 文件操作是日常开发解决的问题,主要是针对解决文件的上传下载、查看操作。下面是相关的知识点: 一、Java Web 文件上传操作 * 文件上传是指通过 HTTP 请求将文件从...

    java web 文件上传进度条源码

    在Java Web开发中,文件上传是一项常见的功能,而为用户提供实时的上传进度条可以显著提升用户体验。本项目提供的"java web 文件上传进度条源码"着重解决了这一需求,包括已用时间、剩余时间、上传速度以及进度条的...

    文件上传(JAVA WEB)

    文件上传在JAVA WEB开发中是一项基础且重要的功能,它允许用户通过Web界面上传本地文件到服务器。本案例基于Struts框架实现,Struts是Apache软件基金会的一个开源项目,主要用于构建MVC(Model-View-Controller)...

    java web文件上传至服务器示例

    java web 开发 上传文件至服务端保存于服务端某个文件夹下 java代码示例

    Java web文件上传

    本示例中,我们探讨的是如何在Java Web环境中实现文件上传,涉及到的关键技术和工具包括Eclipse(一个流行的Java IDE)、JDK 1.6(Java Development Kit,用于编译和运行Java程序)以及Tomcat 7(一个广泛使用的Java...

    java web文件上传-下载-查看操作

    在Java Web开发中,文件上传、下载和查看是常见的功能需求,尤其在构建交互性强的Web应用程序时。这里我们将深入探讨这些操作的核心概念和技术。 **文件上传** 文件上传主要是指用户通过Web表单将本地文件传输到...

    java web文件上传和下载的程序

    在Java Web开发中,文件上传和下载是常见的功能,尤其对于构建交互性强的Web应用程序来说至关重要。本教程将深入探讨如何使用Java实现Web文件上传和下载的程序,这对于初学者理解Web开发的基本流程非常有帮助。 一...

    java Web上传文件

    在Java Web开发中,文件上传是一项常见的功能,用于让用户上传图片、文档等文件到服务器。在描述中提到的“测试可用的,网上下了很多都不能用,经过自己的努力成功了”,这可能指的是开发者在寻找和实践Java Web文件...

    java web 文件上传与下载

    在Java Web开发中,文件上传和下载是常见的功能需求,特别是在构建交互性强的Web应用程序时。这个小例子为你提供了一种实现方式,帮助你理解如何在Java Web环境中处理文件的上传与下载。以下是对这些知识点的详细...

    java web 上传文件代码

    在Java Web开发中,文件上传是一项常见的功能,用于允许用户从他们的本地计算机向服务器传输文件。`jspsmartupload`是一个流行的开源库,专门用于在Java Web应用中处理文件上传任务。这个技术提供了简单易用的API,...

    java web文件上传-下载-查看操作.rar

    在Java Web开发中,文件上传、下载和查看是常见的功能需求,尤其对于构建交互性强的Web应用程序至关重要。这里我们将深入探讨这些操作的核心概念和技术。 首先,让我们从文件上传开始。在Java Web中,文件上传主要...

    java上传文件jar

    这两个库提供了强大的文件操作和文件上传功能,是Java开发者处理文件上传问题的得力助手。 首先,`commons-io-2.5.jar`是Apache Commons IO库的一部分,这是一个用于处理输入/输出操作的Java库。它提供了许多实用...

    FileUtils java web 文件上传下载工具

    在Java Web开发中,文件上传和下载是常见的功能需求,特别是在构建用户交互性强的Web应用时。`FileUtils`是一个方便的工具类,用于简化这些操作。本篇将详细讲解如何利用`FileUtils`实现文件的上传和下载,并介绍...

    Java 上传文件到 SharePoint

    在实际开发中,你还需要考虑错误处理和异常捕获,确保在文件上传过程中遇到问题时能够妥善处理。此外,如果SharePoint的访问控制较为严格,可能需要使用ADAL(Active Directory Authentication Library)来获取访问...

    java web文件上传

    Java Web文件上传是一个常见的开发需求,它涉及到服务器端接收客户端发送的文件并存储到服务器的特定位置。在Java Web环境中,文件上传可以通过多种框架和技术实现,例如Servlet和Struts2。接下来,我们将深入探讨这...

    java web 开发技术大全光盘文件(part02)

    Java Web开发技术大全光盘文件,由于上传权限只有20M所以打成了5个rar包(java web 开发技术大全光盘文件(part01)、java web 开发技术大全光盘文件(part02)、java web 开发技术大全光盘文件(part03)、java web 开发...

    java web实现文件的上传下载

    在Java Web开发中,文件的上传和下载是常见的功能需求,尤其在构建动态网站或Web应用程序时。本项目采用jsp(JavaServer Pages)和servlet技术来实现这一功能。下面将详细阐述这两种技术以及如何结合它们来处理文件...

    java web 开发技术大全光盘文件(part04)

    Java Web开发技术大全光盘文件,由于上传权限只有20M所以打成了5个rar包(java web 开发技术大全光盘文件(part01)、java web 开发技术大全光盘文件(part02)、java web 开发技术大全光盘文件(part03)、java web 开发...

    java文件异步上传

    在Java端,我们需要创建一个处理文件上传的服务器端接口。这通常涉及到Servlet或Spring MVC中的控制器方法。当文件上传请求到达服务器时,这些方法会接收文件流,保存到服务器的磁盘上,或者将其存储到数据库或云...

Global site tag (gtag.js) - Google Analytics