servlet文件上传--common-fileupload

本文介绍了Apache Commons FileUpload组件在Servlet文件上传中的使用,包括核心代码、简化处理以及组件内部的工作原理。讨论了DiskFileItemFactory和ServletFileUpload的角色,以及在JSP中设置文件上传表单时应注意的事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

* 介绍

       最近项目上要做上传的功能,apache神奇之处在于开源。这是大家都喜闻乐见的,面对上传的功能,当然我们可以通过流操作完成,不过这也是没有太大的必要,很多现成的组件可以使用,而且比较成熟,今天小媛就来跟大家说说apache下的一款上传组件:Apache提供的commons-fileupload。

       引入需要的jar包:

这里写图片描述


* 开门见山

       我们先建立servlet,在doGet中实现相应的code~

1.上传核心code

       这是我拿到的上传的基本内容,我们接下来就看看如何使用它,以及它是如何工作的~


    System.out.println(request.getContentLength());
    System.out.println(request.getContentType());
    DiskFileItemFactory factory = new DiskFileItemFactory();
    // maximum size that will be stored in memory
    factory.setSizeThreshold(4096);
    // the location for saving data that is larger than getSizeThreshold()
    factory.setRepository(new File("d:\\uploadFile\\addnetFile\\temp"));

    ServletFileUpload upload = new ServletFileUpload(factory);
    // maximum size before a FileUploadException will be thrown
    upload.setSizeMax(2048000);
    try{
        List fileItems = upload.parseRequest(request);
        // assume we know there are two files. The first file is a small
        // text file, the second is unknown and is written to a file on
        // the server
        Iterator iter = fileItems.iterator();

        //  正则匹配,过滤路径取文件名
        //String regExp=".+\\\\(.+)$";

        //  过滤掉的文件类型
        String[] errorType={".exe",".com",".cgi",".asp"};
        //Pattern p = Pattern.compile(regExp);
        while (iter.hasNext()) {
            FileItem item = (FileItem)iter.next();
            //忽略其他不是文件域的所有表单信息
            if (!item.isFormField()) {
                String name = item.getName();
                String filename=name.substring(name.lastIndexOf("\\")+1);
                long size = item.getSize();
                if((name==null||name.equals("")) && size==0)
                    continue;
                //Matcher m = p.matcher(name);
                //boolean result = m.find();

                for (int temp=0;temp<errorType.length;temp++){
                    if (filename.endsWith(errorType[temp])){
                        throw new IOException(name+": wrong type");
                    }
                }
                try {
                    // 保存上传的文件到指定的目录, 在下文中上传文件至数据库时,将对这里改写
                    item.write(new File("d:\\",filename));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
    catch (IOException e){
        out.println(e);
    }
    catch (FileUploadException e){
        out.println(e);
    }

2.精简版

       如果直接使用上面的内容我们真的是一名称职的搬运工,老做搬运工腰也受不了,然后开始尝试做挑拣工。如果你看过上面的代码,你会发现,很多内容可以省略的,比如说判断上传文件的格式,我们可以在前端直接判断;正则表达式截取文件名,容易出错,我们也可以换另一种方式,

// 用于存放上传文件的目录
private String uploadPath = "F:\\viola\\drp\\drpProject\\web\\upload\\"; 
// 用于存放临时文件
private File tempPath =new File("d:\\uploadFile\\addnetFile\\temp\\"); 
request.setCharacterEncoding("GB18030");

DiskFileItemFactory factory = new DiskFileItemFactory();
// maximum size that will be stored in memory
factory.setSizeThreshold(4096);
// the location for saving data that is larger than getSizeThreshold()
factory.setRepository(tempPath);

ServletFileUpload upload=new ServletFileUpload(factory);

// maximum size before a FileUploadException will be thrown
//20M
upload.setSizeMax(1024000*20);

try {
    //解析request取得表单的对象
    List fileItems= upload.parseRequest(request);

    // assume we know there are two files. The first file is a small
    // text file, the second is unknown and is written to a file on
    // the server
    for (Iterator iter = fileItems.iterator();iter.hasNext();){
        FileItem item=(FileItem)iter.next();


        //取得普通表单的输入域
        if (item.isFormField()){
            if ("itemNo".equals(item.getFieldName())){
                itemNo= item.getString();
            }
        }

        //不是正常的输入域,便是上传输入域
        if (!item.isFormField()){
            //得到input内容:‪D:\workPlan.txt
            String fileName=item.getName();
            long size=item.getSize();
            if (fileName==null|| fileName.equals("")||size==0){
                //获取的不是单个上传文件,而是一个集合
                //我们允许中间某个集合没有上传的内容
                continue;
            }
            fileName= fileName.substring(fileName.lastIndexOf("\\")+1,fileName.length());
            System.out.println(fileName);
            item.write(new File(uploadPath+fileName));      

            //保存到数据库中
            //TODO:调用自己的方法
        }
    }

    //上传成功--转到主页上
    response.sendRedirect(request.getContextPath()+"/servlet/item/SearchItemServlet");

}catch (Exception e) {
    e.printStackTrace();
}

3.code分析

       commons-fileupload,主要是两块的内容:DiskFileItemFactory,ServletFileUpload。

       DiskFileItemFactory实现了FileItemFactory接口createItem,在里面指定了默认的阀值。同时声明一个FileCleaningTracker去跟踪是否超过阀值。他有两个基本的方法如下:
   1、setRepository方法用于设置当上传文件尺寸大于setSizeThreshold方法设置的临界值时,将文件以临时文件形式保存在磁盘上的存放目录。有一个对应的获得临时文件夹的 File getRespository() 方法。
   2、setSizeThreshold方法用于设置是否将上传文件已临时文件的形式保存在磁盘的临界值(以字节为单位的int值),如果从没有调用该方法设置此临界值,将会采用系统默认值10KB。对应的getSizeThreshold() 方法用来获取此临界值。

       附赠(源于网络):Apache文件上传组件在解析上传数据中的每个字段内容时,需要临时保存解析出的数据,以便在后面进行数据的进一步处理(保存在磁盘特定位置或插入数据库)。因为Java虚拟机默认可以使用的内存空间是有限的,超出限制时将会抛出“java.lang.OutOfMemoryError”错误。如果上传的文件很大,例如800M的文件,在内存中将无法临时保存该文件内容,Apache文件上传组件转而采用临时文件来保存这些数据;但如果上传的文件很小,例如600个字节的文件,显然将其直接保存在内存中性能会更加好些。

       ServletFileUpload继承了FileUploadBase,所以它具有了文件上传的基本操作。


* jsp配置

       小媛想说一下,如果完成上传我们在jsp中需要注意什么,有什么不同于我们其他的操作呢?

1. input
   设置input输入项的name属性,否则浏览器将不会发送上传文件的数据,type类型为file。这里就对应我们上面上传code中不是普通的输入域。

2. form
   必须把form的enctype属值设为multipart/form-data.设置该值后,浏览器在上传文件时,将把文件数据附带在http请求消息体中,并使用MIME协议对上传的文件进行描述,以方便接收方对上传数据进行解析和处理。
   我们确定了enctype=”multipart/form-data”,便不能通过request.getParameter(“”)的方式进行获取表单的参数值了~如何取呢?上面的code也有提到:

//解析request取得表单的对象
List fileItems= upload.parseRequest(request);

3. post
   表单的提交方式要是post


* End

       开源给我们打开了很多扇门,我们需要做的便是不断的给自己充电,也不是为了学习去学习,而是工作中我们用到了,便去研究,最终应用。当我们的工作经验丰富了,我们的含金量也上去了。


* 番外话

       近日小编一直在跟自己的情绪做斗争,严重感觉自己的情商不够,程序猿的情商绝对是个硬伤。路过的小伙伴,如果有什么更好的办法,拯救一下情商为负数的我吧~

评论 55
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值