`
judim
  • 浏览: 40979 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论
阅读更多
    如果在表单中使用表单元素 <input type=“file” />,浏览器在解析表单时,会自动生成一个输入框和一个按钮,输入框可供用户填写本地文件的文件名和路径名,按钮可以让浏览器打开一个文件选择框供用户选择文件:  
    当表单需要上传文件时,需指定表单 enctype 的值为 multipart/form-data 
    在 form 元素的语法中,enctype 属性指定将数据发送到服务器时浏览器使用的编码类型。  
    enctype 属性取值:
    application/x-www-form-urlencoded:表单 enctype 属性的默认值。这种编码方案使用有限的字符集,当使用了非字母和数字时,必须用”%HH”代替(H 代表十六进制数字)。对于大容量的二进制数据或包含非 ASCII 字符的文本来说,这种编码不能满足要求。
    multipart/form-data:form 设定了enctype=“multipart/form-data”属性后,表示表单以二进制传输数据 .  
    Commons-fileupload 组件上传的基本原理 
    FileUpload组件将页面提交的所有元素(普通form表单域,如text和文件域file)都看作一样的FileItem,这样上传页面提交的 request请求也就是一个FileItem的有序组合,FileUpload组件可以解析该request,并返回一个一个的FileItem。而对每一个FileItem,FileUpload组件可以判断出它是普通form表单域还是文件file域,从而根据不同的类型,采取不同的操作--如果是表单域,就读出其值,如果是文件域,就保存文件到服务器硬盘上或者内存中      
    Commons-fileupload 组件API   
    ServletFileUpload 负责处理上传的文件数据,并将每部分的数据封装成一到 FileItem 对象中。 
    DiskFileItemFactory 是创建 FileItem 对象的工厂,在这个工厂类中可以配置内存缓冲区大小和存放临时文件的目录。 
    ServletFileUpload 在接收上传文件数据时,会将内容保存到内存缓存区中,如果文件内容超过了 DiskFileItemFactory 指定的缓冲区的大小,那么文件将被保存到磁盘上,存储为 DiskFileItemFactory 指定目录中的临时文件。等文件数据都接收完毕后,ServletUpload 在从文件中将数据写入到上传文件目录下的文件中 
    进行文件上传和下载的具体操作: 
    首先,加载必要的jar包:“commons-fileupload-1.2.1.jar”,“commons-io-1.4.jar” 
    步骤: 
    0. 创建 FileItemFactory 子类 DiskFileItemFactory 的对象 
    1.为了得到 ServletFileUpload 对象, 先需要得到 FileItemFactory 的一个对象, 然后调用 new ServletFileUpload(FileItemFactory fif); 方法得到 ServletFileUpload 对象 
    2.为了得到 FileItem 的集合, 先需要得到 ServletFileUpload 对象, 然后调用该对象的 parseRequest() 方法得到 FileItem 的 List 
    3.从 HttpServletRequest 对象中得到 FileItem 的集合 
    4. 对上述集合进行遍历:判断是表单域还是文件域 
    下面是对文件上传相关操作的代码示例。 
     
    //1. 验证是否使用 FileUpload 组件 
     
            boolean isMultipart = ServletFileUpload.isMultipartContent(request); 
            //2.1  不使用 
     
            if(!isMultipart){ 
     
                response.getWriter().println("没有文件域"); 
                return; 
     
            } 
     
            //2.2 使用 
     
            
     
            //3. 获取 DiskFileItemFactory 对象 
     
            DiskFileItemFactory itemFactory = new DiskFileItemFactory(); 
     
            
     
            //4. 获取 ServletFileUpload 对象 
     
            ServletFileUpload fileUpload = new ServletFileUpload(); 
     
            fileUpload.setFileItemFactory(itemFactory); 
     
            设置上传文件的最大大小 
     
            fileUpload.setFileSizeMax(1000 * 100); 
     
            
     
            String forwardPage = null; 
     
            
     
            try { 
     
                //5. 调用 ServletFileUpload 的 parseRequest() 方法, 获取 FileItem 的集合 
     
                List<FileItem> items = fileUpload.parseRequest(request); 
     
                
     
                Map<String, String> paramMap = new HashMap<String, String>(); 
     
                FileItem fileItem = null; 
     
                
     
                //6. 对 5 获取的集合进行遍历 
     
                Iterator<FileItem> it = items.iterator(); 
     
                while(it.hasNext()){ 
     
                    FileItem item = it.next(); 
     
                    //7. 验证是否为表单域 
     
                    if(item.isFormField()){ 
     
                        //7.1 是表单域, 把获取到得 表单域的 fieldName 和 value 放在 map 中. 
     
      获得表单中该字段的字段名 
     
                        String fieldName = item.getFieldName(); 
     
    获得表单中与上面字段名对应的字段值 
     
                        String value = item.getString("UTF-8"); 
     
                        
     
                        paramMap.put(fieldName, value); 
     
                    } 
     
                        //7.2 不是表单域, 即为文件域. 获取 FileItem 对象, 注意限制条件. 
     
                    else{ 
     
    这里获得了与file对应的FileItem对象 
     
                        fileItem = item; 
     
                    } 
     
                        
     
                } 
     
                
     
                //8. 对 7.2 获取的 FileItem 对象进行文件上传操作. 
     
                //10.1 获取全路径名 
     
                String path = null; 
     
                
     
                path = this.getServletContext().getRealPath("/photoes"); 
     
                
     
                File photoesDir = new File(path); 
     
                if(!photoesDir.exists()){ 
     
                    photoesDir.mkdir(); 
     
                } 
     
                
     
                path = path + "/" + paramMap.get("username"); 
     
                
     
                File file = new File(path + ".jpg"); 
     
                
     
                //10.2 上传操作,把用户在页面上传的文件保存到服务器 
     
                fileItem.write(file); 
     
      
     
    上传文件表单的两个准备工作 
     
    1. 提交方式改为 POST 
     
    2. enctype 属性的取值改为 multipart/form-data 
     
      
     
    在获取表单值时 
     
    1. 不能使用 request.getParameter() 方法, 因为该方法仅能获取字符串, 对二进制无能为力. 
     
    2. 使用 fileUpload 组件读取上传文件及表单域字段. 
     
      
     
    fileUpload 组件的核心思想 
     
    fileUpload 组件认为: 所有的表单域(包含文件域和文本域)都是 FileItem 对象. 
     
    步骤: 
     
    1. 获取 FileItem 对象组成的 List 
     
    2. 对 List 进行遍历 
     
    3. 判断每一个  FileItem 对象是表单域 还是 文件域, 以进行不同的处理. 
     
      
     
    详细步骤: 
     
    1. 检查表单的 enctype 是否为 multipart/form-data, 以决定是否使用 FileUpload 组件进行解析请求 
     
    2. 若表单的 enctype 是否为 multipart/form-data, 则需要获取 封装了所有表单域 的对应的 FileItem 对象的 List: List<FileItem> list = null; 
     
       3) 获取 ServletFileUpload 对象, 调用该对象的 public java.util.List parseRequest(javax.servlet.http.HttpServletRequest request) 
     
                   方法获取封装 FileItem 的List 
     
       2) 需要使用 ServletFileUpload 的构造器来创建 ServletFileUpload 对象: 
     
          ^ 使用任意一个构造器都可以得到 ServletFileUpload 对象, 但都需要先得到 FileItemFactory 对象 
     
          * ServletFileUpload upload = new ServletFileUpload(); 
     
              upload.setFileItemFactory(factory); 
     
            * ServletFileUpload upload = new ServletFileUpload(factory); 
     
       1) 创建 FileItemFactory 接口是想类对象: DiskFileItemFactory, 直接创建该对象. 
     
    3. 可以调用 DiskFileItemFactory 的相关方法来对文件上传进行一些优化: 
     
       1) setSizeThreshold(int sizeThreshold):设置使用临时文件夹的大小. 
     
       2) setRepository(): 设置临时文件夹 
     
    4. 可以调用 ServletUpload 的方法进行文件上传的一些控制 
     
       1) setFileSizeMax: 设置单个文件的最大上传值 
     
       2) setSizeMax:设置总上传文件的最大值, 以 byte 为单位. 
     
    5. 关于中文乱码的问题: 
     
       1) 在解析 request 之前: request.setCharacterEncoding("UTF-8"); 可以解决文件域的乱码问题 
     
       2) 在解析表单域时需要使用: new String(value.getBytes("iso-8859-1"), "UTF-8"); 解决中文乱码问题. 
     
    但是有时候,即使我们按照上面方式设置了,可以还是中文乱码,这个时候问题多半就出在tomcat的配置上了,打开tomcat的service.xml文件,在那里面注意下面部分 
     
     <Connector port="8989" protocol="HTTP/1.1" 
     
                   connectionTimeout="20000" 
     
                   redirectPort="8443" useBodyEncodingForURI="true"/> 
     
    只有加上了红色部分的设置,我们在程序中配置EncodingUrl才能起作用。 
     
      
     
    下面一段代码是文件下载的相关操作 
     
    //1. 设置响应报头 contentType: application/x-msdownload --> 
     
            //   告诉浏览器其所输出的内容的类型不是普通的文本文件或 HTML 文件,而是一个要保存到本地的下载文件 
     
            //response.setHeader("conent-type", "application/x-msdownload"); 
     
            response.setContentType("application/x-msdownload"); 
     
            
     
            //2. 设置响应抱头 Content-Disposition: attachment --> 
     
            //   Web 服务器希望浏览器不直接处理相应的实体内容,而是由用户选择将相应的实体内容保存到一个文件中 
     
            response.setHeader("Content-Disposition", "attachment; filename=haha.ppt"); 
            //3. 利用 response.getOutputStream() 进行 io 操作 
     
            OutputStream os = response.getOutputStream(); 
            BufferedOutputStream bos = new BufferedOutputStream(os); 
            //文件的输入流 
     
            InputStream is = null; 
     
            is = new FileInputStream("E:\\source\\090515\\javaee\\fileupload\\fileUpload.ppt"); 
     
            BufferedInputStream bis = new BufferedInputStream(is); 
     
            
     
            int length = 0; 
     
            byte [] temp = new byte[1 * 1024 * 10]; 
     
            while((length = bis.read(temp)) != -1){ 
     
                bos.write(temp, 0, length); 
     
                System.out.println("循环操作中..."); 
     
            } 
            bis.close(); 
            bos.close(); 
     
      
     
    但是上面的这种方式无法被迅雷之类的下载工具下载,如果希望被迅雷之类的东西下载,就直接这么写就可以了 
     
    request.getRequestDispatcher("/data/fileUpload.ppt") 
     
                .forward(request, response); 




(提交表单时,程序会自动识别表单哪个是文件,以下自己测试成功的代码,页面表单需要做一点点小的设置 enctype="multipart/form-data" method="post",这两个是必需的)
package com.util;

import java.io.File;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

public class UploadFiles {

public static void uploadFile(HttpServletRequest request, String savePath)
throws Exception {
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if(!isMultipart){
System.out.println("没有使用FileUpload组件,请在表单(form)中加入“ enctype=\"multipart/form-data\" method=\"post\" ”");
return;
}
DiskFileItemFactory factory = new DiskFileItemFactory();

factory.setSizeThreshold(10240000);// 设置内存缓冲区,超过后写入临时文件
File file = new File(savePath);// 设置临时文件存储位置
if (!file.exists())
file.mkdirs();
factory.setRepository(file);
ServletFileUpload upload = new ServletFileUpload(factory);

upload.setFileSizeMax(10002400000l);// 设置单个文件的最大上传值
upload.setSizeMax(10002400000l);// 设置整个request的最大值
upload.setHeaderEncoding("UTF-8");

List<?> items = upload.parseRequest(request);
FileItem item = null;
String fileName = null;
if (items != null) {
for (int i = 0; i < items.size(); i++) {
item = (FileItem) items.get(i);
fileName = savePath + File.separator + item.getName();
// 保存文件
if (!item.isFormField() && item.getName().length() > 0) {
item.write(new File(fileName));
}
}
}
}
}


分享到:
评论

相关推荐

    Ajax Upload多文件上传插件

    Ajax Upload文件上传插件允许你上传多个插件而无需刷新页面,可以使用任何的元素来显示文件选择窗口。它可以在所有主流的浏览器下工作,从2.0版本开始,不需要任何库运行。Ajax Upload文件上传插件不会污染任何命名...

    基于html5的多文件上传

    多文件上传,带进度条,支持主流浏览器,不支持IE,因为采用的是html5的技术。使用ajax提交表单,方便修改。不使用三方文件上传控件。

    基于html5的文件上传

    基于html5的文件上传,带有进度条,采用ajax表单方式提交,方便修改。

    基于java的企业级应用开发:文件上传和下载.ppt

    开发文件上传表单页面 在实现文件上传时,首先需要设置文件上传表单,这个表单的提交方式必须为POST。另外,还需要增加上传的属性enctype= “multipart/form-data”,该属性说明浏览器可以提供文件上传功能。 2.编写...

    jquery文件上传表单.zip

    jquery文件上传表单是一款基于jquery css3实现的表单文件上传选择框样式。  jquery文件上传表单演示 点击查看演示

    基于thinkPHP的文件上传+layui实现头像上传功能:

    基于thinkPHP的文件上传+layui实现头像上传功能的demo,包含数据库。。。。。。。。。。。。。。。。。。。。。。

    jquery文件上传表单

    jquery文件上传表单是一款基于jquery+css3实现的表单文件上传选择框样式。

    ASP.net+jQuery无刷新多文件上传

    一款基于ASP.net+jQuery的无刷新多文件上传系统,轻松实现AJAX无刷新上传文件,没有使用任何第三方控件,全是用ASP.NET自写程序实现的上传,一次可以上传多个文件,用到了jQuery插件来控制程序的执行,可以适合添加...

    HttpUpload Qt Http上传文件简单示例

    基于Qt5.12.10开发的http文件上传,采用QHttpMultiPart方式上传,详情请看博客: https://fulin.blog.csdn.net/article/details/111933283

    servlet方式完美实现文件上传

    今天和大家分享下基于servlet的方式实现文件上传; 1、众所周知在不实用框架的时候使用表单模式实现文件上传是无法接收其他的参数的; 2、但是在使用mutipart/form-data模式上传的时候,其实非文件属性的属性的值是...

    layui拖拽图片上传表单代码.zip

    jQuery基于layui制作图片上传和名称表单验证,支持文件拖拽图片上传和进度条功能。

    基于ajax实现文件上传并显示进度条

    下面给大家分享下基于ajax实现文件上传并显示进度条。在jsp部分,需要设计一个表单,form的属性添加 enctype=”multipart/form-data”,设计一个iframe,作为隐藏。form的target等于iframe的name; 在servlet部分:...

    C#文件批量上传服务器源码

    基于C#MVC-WEBAPI实现的文件批量上传服务器源代码,客户端通过form表单或ajax提交参数及文件,本程序负责接收并处理请求:将文件根据时间戳重命名后存入指定目录,并将参数与文件一一对应后存入mysql数据库,代码简洁,4-...

    IE9 elementUI文件上传的问题解决

    文件上传之后的返回值 Content-Type值不能是application/json 这会导致IE去解析返回结果,最终调用文件的保存或者打开,此处需要与后端协商将Content-Type改为text/plain 如果需要图片回显,回显的图片路径中有有...

    jQ AJAX文件上传.zip

    脚本简介jQ AJAX文件上传是一款基于jquery实现的PHP迷你AJAX文件上传表单。

    简单的文件上传.zip

    简单的文件上传基于jquery实现的PHP迷你AJAX文件上传表单。

    多文件上传插件

    在页面元素中include一个php文件,会在dom中增加一个上传文件的按钮,在dom尾部追加一个隐藏的iframe以及一个隐藏的form表单用于实现无刷新上传文件和调用页面js方法实现回调操作。 全部的配置在config.php

    一个php文件上传类库.zip

    这个PHP文件的上传类主要是用来上传文件的,包括图片,视频,...$_FILES["file"]["error"] - 由文件上传导致的错误代码 这是一种非常简单文件上传方式。基于安全方面的考虑,您应当增加有关什么用户有权上传文件的限制。

    HTTP 文件批量上传组件

    基于FLASH开发的,文件批量上传组件 完美代替FORM表单上传

    Spring MVC文件上传与下载

    文章目录文件上传commons-fileupload组件基于表单的文件上传MultipartFile接口文件下载文件下载的实现方法文件下载的过程 文件上传 Spring MVC 框架的文件上传是基于 commons-fileupload 组件的文件上传,只不过 ...

Global site tag (gtag.js) - Google Analytics