二期设计——文件上传

来源:互联网 发布:golang 随机数生成 编辑:程序博客网 时间:2024/04/28 12:24
对表单上传的理解(可能有误):
 <form action="" method="post" enctype="multipart/form-data">
 最大上传2G.
通过 http 协议上传文件(rfc1867协议概述,jsp 应用举例,客户端发送内容构造)
 服务器接收到上传的流,自己其实是不作任何处理的,那个request还是原装的,谁来处理这个request呢,一般采用第三方的工具,这里以commons fileupload为例.
  
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(4096);// 设置缓冲,这个值决定了是fileinputstream还是bytearrayinputstream
factory.setRepository(new File("d:\\temp"));//设置临时存放目录,默认是new File(System.getProperty("java.io.tmpdir"))
ServletFileUpload sfu = new ServletFileUpload(factory);
sfu.setSizeMax(100*1024*1024);//100M
List items = sfu.parseRequest(request);//传入的这个request还是原装的
 见上面的代码,commons fielupload通过ServletFileUpload类的parseRequest(request)方法处理这个原始流。而ServletFileUpload又会调用其爷爷类FileUploadBase的parseRequest(request)方法,然后又会调return parseRequest(new ServletRequestContext(request)),代码如下

        try {
            FileItemIterator iter = getItemIterator(ctx);
            List items = new ArrayList();
            FileItemFactory fac = getFileItemFactory();
            if (fac == null) {
                throw new NullPointerException(
                    "No FileItemFactory has been set.");
            }
            while (iter.hasNext()) {
                FileItemStream item = iter.next();
                FileItem fileItem = fac.createItem(item.getFieldName(),
                        item.getContentType(), item.isFormField(),
                        item.getName());
                try {
                    Streams.copy(item.openStream(), fileItem.getOutputStream(),
                            true);
                } catch (FileUploadIOException e) {
                    throw (FileUploadException) e.getCause();
                } catch (IOException e) {
                    throw new IOFileUploadException(//报错经常在这里
                            "Processing of " + MULTIPART_FORM_DATA
                            + " request failed. " + e.getMessage(), e);
                }
                if (fileItem instanceof FileItemHeadersSupport) {
                    final FileItemHeaders fih = item.getHeaders();
                    ((FileItemHeadersSupport) fileItem).setHeaders(fih);
                }
                items.add(fileItem);
            }
            return items;
        } catch (FileUploadIOException e) {
            throw (FileUploadException) e.getCause();
        } catch (IOException e) {
            throw new FileUploadException(e.getMessage(), e);
        }
    
 这里注意,上传的<input type=file>标记一定要有name,如果没有,commons fielupload不作处理。
 commons fielupload会把上传的文件以流的方式写入到temp文件夹,临时文件夹可以自己设定,如果不手动设置,则是Servlet容器为web应用分配的临时目录,tomcat可能就是%TOMCAT_HOME%\temp,我用weblogic时,是C:\DOCUME~1\yourname\LOCALS~1\Temp\。这些临时文件以"upload"开头,格式是.tmp,例如"upload_47fdc3_11c9eb678b0__8000_00000043.tmp"
 在上传过程中commons fielupload才知道上传的文件的大小,如果你定义允许的最大附件为100M,然后你上传一个200M的文件,那么只有实际传输了100M以后,commons fielupload才知道超过了,然后抛出一个异常(org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException)。
 commons fielupload处理完了以后(处理过程全在parseRequest(request)方法里),返回一个List,里面的每一项已被封装为FileItem,你通过fileItem.isFormField()判断出是普通的表单属性呢,还是一个文件,如果是文件,你可以从fileItem.getInputStream()获得输入流,这个输入流其实是一个FileInputStream.当然,如果文件很小,则是ByteArrayInputStream.那么如何区分?这两者的区别是由factory.setSizeThreshold(4096)确定的。大于4K,为FileInputStream,小于4K为ByteArrayInputStream
这样就可以解释struts用ActionForm的方式处理上传附件的一些问题了,struts接收到enctype="multipart/form-data"的post请求后,会看那个对应的action有没有配置actionform,如果配置了,就会作一些处理,所以你在action里得到的request已经不是一个普通的request了,而是一个被封装过的request。如果想得到原始的request,就不要struts-config.xml里给action类配置actionform
tempDir指定的目录中可能会随着时间推移出现很多后缀为"tmp"的垃圾文件,commons-fileupload1.2提供了一个不错的解决方法,就是把下面的代码加入到web.xml中即可。
<listener>
<listener-class>
org.apache.commons.fileupload.servlet.FileCleanerCleanup
</listener-class>
</listener> 

Q:I'm using FileUpload in an Action, but it's not working. Why? 
A:Struts recognises multipart requests, and parses them automatically, presenting the request parameters to your code in the same manner as if they were regular request parameters. Since struts has already processed the request, and made it available in your form bean, the input stream is no longer available for parsing, so attempting to do so with FileUpload will fail. 
Q:But I need to parse the request myself. How can I do that? 
A:Struts parses multipart a request as a part of the process of populating your form bean from that request. If, for some reason, you need to have full control over the multipart parsing, you can do so by configuring your action mapping without an associated form bean. (A better way of doing this, however, is to replace the default multipart handler with your own. See the struts documentation for details.) 
1,直接用commons fileupload而不用struts的ActionForm时,表单里的属性值不能用request.getParameter()获取了,而url里的queryString可以。
2,  获取form里的属性值的代码
使用commons fileupload的零碎笔记 - 小钳子 - 我的博客
使用commons fileupload的零碎笔记 - 小钳子 - 我的博客                    String formname = fi.getFieldName();// 获取form中的名字
使用commons fileupload的零碎笔记 - 小钳子 - 我的博客                    String formcontent = fi.getString();
使用commons fileupload的零碎笔记 - 小钳子 - 我的博客使用commons fileupload的零碎笔记 - 小钳子 - 我的博客                    if (formname.equals("id")) 使用commons fileupload的零碎笔记 - 小钳子 - 我的博客{
使用commons fileupload的零碎笔记 - 小钳子 - 我的博客                        id = formcontent;
使用commons fileupload的零碎笔记 - 小钳子 - 我的博客使用commons fileupload的零碎笔记 - 小钳子 - 我的博客                    } else if (formname.equals("title")) 使用commons fileupload的零碎笔记 - 小钳子 - 我的博客{
使用commons fileupload的零碎笔记 - 小钳子 - 我的博客                        title = formcontent;
使用commons fileupload的零碎笔记 - 小钳子 - 我的博客使用commons fileupload的零碎笔记 - 小钳子 - 我的博客                    } else if (formname.equals("memo")) 使用commons fileupload的零碎笔记 - 小钳子 - 我的博客{
使用commons fileupload的零碎笔记 - 小钳子 - 我的博客                        memo = formcontent;
使用commons fileupload的零碎笔记 - 小钳子 - 我的博客                    }
使用commons fileupload的零碎笔记 - 小钳子 - 我的博客                
3, 表单里的file控件的name不能为空。
4,上传大文件(190多M)时报异常
org.apache.commons.fileupload.FileUploadException:   Processing   of   multipart/form-data   request   failed.   EOF   after   reading   only:   "3567789 "   of:   "203323339 "   promised   bytes,   out  of   which   at   least:   "0 "   were   already   buffered
http://forums.bea.com/thread.jspa?threadID=200033356
http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=121&threadID=20060&start=0&tstart=0
http://thisisxy.blogcn.com/diary,204014352.shtml
http://www.80diy.com/home/20050527/17/4040711.html
5,
org.apache.commons.fileupload.FileUploadException: Processing of multipart/form-data request failed. Read timed out
HTTP活动超时限制的时间太短 HTTP Keep-Alive Timeout.
6,InputStream is =formFile.getInputStream() ;  //formFile是org.apache.struts.upload.FormFile
上传的文件小时这个输入流是java.io.ByteArrayInputStream,上传比较大的文件时这个输入流是FileInputStream
7,设置表单里的上传路径为只读
<input type=file id="uploadfile" name="uploadfile" style="display: none;">
<input type=text id=tempfile readonly="true">
<input type=button 
onClick="uploadfile.click();tempfile.value=uploadfile.value;" value="浏览..">
0 0
原创粉丝点击