【转载】webwork上传下载文件的问题总结

14年前

系统的架构是webwork+spring+hibernate,数据库是SQLServer2000.

因为是第一次用webwork,所以也是到网上搜代码搜例子,现在才发现baidu和google有些不一样啊。

通过这几天的baidu和google,发现网友们的笔记对我们来说真是重要啊,于是乎在做完了这些之后,也打算总结一下,一来让自己把思路理顺,二来方便大家用的到的时候直接粘贴。

先说说文件的上传吧:

首先看xwork的配置文件;

<!-- 文档上传 -->
     <action name="uploadFileAction" class=".......action.UploadFileAction">
   
     <param name="rootPathKey">fileRoot</param>
           
            <result name="input" type="dispatcher">
                <param name="location">uploadDoc.jsp</param>
            </result>
            <interceptor-ref name="fileUpload">
             <param name="maximumSize">10485760</param>
            </interceptor-ref>
         <interceptor-ref name="params"/>
         <interceptor-ref name="autowireDefault"/>
    </action>

    第一个参数是我自己配在action里设置根目录的一个key值,
    第三个是最重要的,就是那个maximumSize,他是用来设置webwork允许上传的文件大小。
    不过根据试验结果来看,他要和webwork.properties里的一个设置一起才能起作用,
  webwork.multipart.maxSize=10485760;
    这个要记得写到webwork.properties里面来。

这下再来看看action的方法吧:

     action里重要的就是要设置属性来接受这些webwork上传上来的数据,

     这里面就有一个非常非常郁闷的问题了,就是在上传的页面里的那个input框的name属性和这些变量是有关系的,

     比如在heml页面的name=“docFile”, 那么在action里的接受上传文件的file的名字就该设置为docFile,而接受文件类型的属性就该设置为docFileContentType,千万不要忘了get和set方法。
  
 <input name="docFile" type="file" class="textbox" id="docFile">

        private java.io.File docFile;

        private String docFileContentType;

之后就可以用这两个变量来进行io操作了。


上传比较简单,做下载的时候可是碰到了一个大大的问题。

起初是在网上搜的代码,也使用webwork设置的,xwork配置如下:

<!-- 文档下载-->
 <action name="downloadFileAction" class="....action.DownloadFileAction">
     
       <result name="download" type="stream">
                 <param name="contentType">application/octet-stream</param>
                 <param name="inputName">docStream</param>
                 <param name="bufferSize">1024</param>             
                 <param name="contentDisposition">
   attachment;filename="${filename}"
    </param>
       </result>
           
          
            <interceptor-ref name="params"/>
            <interceptor-ref name="autowireDefault"/>
 </action>


然后action里是这么设置的:

 先要设置这几个属性,分别对应配置文件的不同参数:
  
 private InputStream docStream;
 
 private String contentType;
 
 private String contentDisposition;
 
 private int bufferSize;
 
 private String filename;

 然后将filename设置为我们需要的filename,在将一个inputstream赋给docStream,
然后return "download";

        起初这么做还可以,可是后来不知道怎么突然不行了,郁闷了半天,(写这个的时候打算完了再试试这种方法。)一直报一个
ClientAbortException: java.net.SocketException: Connection reset by peer: socket write error的异常,而浏览器的动作就是突然打开准备下载的窗口又迅速消失了,我以为是我的浏览器设置的原因,就跑到同事那里试试,果不其然,通过了,happy中。

        可是下午测试时又出问题了,才发现是IE7的问题,在ie6上都没有问题,于是开始怀疑webwork的下载。

        打算自己用response写一个下载了。

        经过了测试,不行,还是原来的错误,于是道网上搜例子,看来看去还是和我的差不多,于是就变态的改header,改contenttype,改contentDisposition,反正是觉得那不顺眼就改那里,还是不行。

        于是我把代码直接贴到一个servlet里面,浏览器直接进入servlet,弹出下载框了。


        更加郁闷中。

        在郁闷中下班的时间来了,路上还在想是不是因为buffersize设的太小了,艾,遇到比较变态的问题时很多问题都不得不考虑,虽然现在想想是比较可笑的。

         今天早上来了一直在搜那个异常的信息,搜到的几乎最全的答案就是这个:

         由于处理http连接时,正在输出内容时,用户关闭了IE,会出现一个个"ClientAbortException",属于I/O处理中出现的一个异常,应用服务器应该会捕捉。
  Connection reset by peer的原因:
         经常出现的Connection reset by peer: 原因可能是多方面的,不过更常见的原因是:
         ①:服务器的并发连接数超过了其承载量,服务器会将其中一些连接Down掉;
         ②:客户关掉了浏览器,而服务器还在给客户端发送数据;
         ③:浏览器端按了Stop    

         加上由于在IE6里面通过了,我更怀疑是浏览器中止了流的输出。


         最后终于有了一个让我发现突破口的现象了,因为是在js里面用window.open指向action的,当我把昨天那个servlet写到js里面是,竟然也出现了同样的状况,于是开始怀疑是提交action的方式不对才导致IE7出现这个错误的。于是我就又把这个servlet用
超链接的方式访问了一下,没问题。于是我想到了利用超链接的方式来访问action的方法,ok。

        最后,终于在js里通过这样的方式解决了一个IE7的下载bug。

        $("downloadhref").href = "downloadFileAction.action?fileId="+id[0];
        $("downloadhref").click();


最后在列上一个webwork文件下载时文件名乱码的解决方法,也是在网上搜的,

        public String toUtf8String(String s) {
     StringBuffer sb = new StringBuffer();
     for (int i = 0; i < s.length(); i++) {
      char c = s.charAt(i);
      if (c >= 0 && c <= 255) {
       sb.append(c);
      } else {
       byte[] b;
       try {
        b = Character.toString(c).getBytes("utf-8");
       } catch (Exception ex) {
        System.out.println(ex);
        b = new byte[0];
       }
       for (int j = 0; j < b.length; j++) {
        int k = b[j];
        if (k < 0)
         k += 256;
        sb.append("%" + Integer.toHexString(k).toUpperCase());
       }
      }
     }
     return sb.toString();
  }

利用最原始的response的下载方式


  //文件下载
  HttpServletResponse response = ServletActionContext.getResponse();
  
  response.setContentType("application/octet-stream");
                response.setHeader("Content-Disposition","attachment;filename="+this.filename);

                //输出流
  ServletOutputStream out = response.getOutputStream();
  //输入流
  java.io.File f = new java.io.File(path);
  BufferedInputStream  in =  new BufferedInputStream(new FileInputStream(f));
  
  byte b[] = new byte[this.bufferSize];
  int bytesRead = 0;
  while ((bytesRead = in.read(b, 0 , this.bufferSize)) != -1)
  { 
   out.write(b, 0, bytesRead); //写数据;
  }
  
  in.close();
  out.close(); 

---------------------------------------------------------------------------------
ie6下载后无法直接打开,缓存目录excel文件不存在
 
若要解决此问题,请按照下列步骤操作:
  1. 单击 开始、 单击 运行,键入 %,然后单击 确定
  2. 删除 Temp 文件夹中的所有文件。
  3. 单击 开始,然后单击 控制面板
  4. 双击 Internet 选项
  5. 常规 选项卡上单击 删除文件,单击以选中 删除所有脱机内容 复选框,然后单击 确定
  6. 在桌面上右键单击 回收站 并单击 清空回收站,然后单击

参考 http://support.microsoft.com/kb/938200/zh-cn