后台是Struts2,页面是一个GridPanel的文件列表;要求点击“下载”后,弹出文件保存窗口;页面截图如下面形式: 序号     文件名称            文件类型      文件记录数       生成文件日期       下载次数        操作  
 
  1     e_20100909.xls         EXCEL         222                                   4           下载  
  2     A_20100909.xls         EXCEL          22                                   5           下载             
  3    数据源_20100909.txt     TXT             1                                   33          下载 
     我的思路是点击下载后,通过异步请求,将文件名传到后台,调用struts2自带的下载文件功能,根据文件名打开文件流返回到浏览器
    但是始终不成功,还是经验不足啊,希望高人指点,提供一个好的解决办法:

解决方案 »

  1.   

    我的配置文件:
            
            <!-- 文件下载,支持中文附件名 -->
            <action name="fileDownloadAction" class="com.tydic.emc.webapp.action.sharefile.FileDownloadAction" method="download">
                <!-- 初始文件名 -->
                <param name="fileName">fileName</param>
                <result name="success" type="stream">
                    <param name="contentType">application/octet-stream;charset=ISO8859-1</param>
                    <param name="inputName">inputStream</param>
                    <!-- 使用经过转码的文件名作为下载文件名,downloadFileName属性
                    对应action类中的方法 getDownloadFileName() -->
                    <param name="contentDisposition">attachment;filename="${downloadFileName}"</param>
                    <param name="bufferSize">4096</param>
                </result>
            </action>后台Action:package com.tydic.emc.webapp.action.sharefile;import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.UnsupportedEncodingException;import org.apache.struts2.ServletActionContext;import com.opensymphony.xwork2.Action;public class FileDownloadAction implements Action {
    // 初始的通过param指定的文件名属性
    private String fileName;
        //下载文件原始存放路径
        private final static String DOWNLOADFILEPATH="/shareDownload/";    public String getFileName() {
            return fileName;
        }    public void setFileName(String fileName) {
         try {
    fileName = new String(fileName.getBytes("ISO8859-1"),"GBK");
    } catch (UnsupportedEncodingException e) {
    e.printStackTrace();
    }
            this.fileName = fileName;
        }    //从下载文件原始存放路径读取得到文件输出流
        public InputStream getInputStream() throws IOException {
         //拿到web app的绝对根路径
    String rootpath = ServletActionContext.getServletContext().getRealPath("/");
    //要下载的文件路径及文件名
    String fileUrl = rootpath+"shareDownload\\"+fileName;
    System.out.println("===fileUrl===>"+fileUrl);    
            //return ServletActionContext.getServletContext().getResourceAsStream(fileUrl);
    return new ByteArrayInputStream("Struts 2 下载示例".getBytes());
        }
    /** 提供转换编码后的供下载用的文件名 */
    public String getDownloadFileName() {

    String downloadFileName = fileName;

    try {
    downloadFileName = new String(downloadFileName.getBytes("ISO8859-1"), "GBK");
    } catch (UnsupportedEncodingException e) {
    e.printStackTrace();
    }
    return downloadFileName;
    }
    /**
     * 下载文件
     * 
     * @return
     */
    public String download() {
    System.out.println("=====fileName====>"+fileName);
    System.out.println("===DOWNLOADFILEPATH+fileName===>"+DOWNLOADFILEPATH+fileName);
    return SUCCESS;
    }

        public String execute() {
            return SUCCESS;
        }}
    Extjs页面用的是异步请求向后台传要下载的文件名参数: //文件共享下载
    function downLoadFile(){

    //拿到文件名和文件类型;
    var selectedRecords = tableGrid.getSelectionModel().getSelections();
    var fileName = selectedRecords[0].get('fileName');
    var fileType = selectedRecords[0].get('fileType');
            var selectedId = "";
            var selectedId = "&selectedId="+selectedRecords[0].get('id');
            //var params = "&fileName="+encodeURI(encodeURI(fileName));
            var params = "&fileName="+fileName;
            alert("params="+params); 
                   
    var url = "/emc/shareDownload/"+fileName; 

    //window.open(url);
           
            //异步请求,调用struts2的文件下载功能?
    Ext.Ajax.request({
        method: 'POST',
        //向后台Action传表单参数
        url: '<c:url value="/sharefile/fileDownloadAction!download.html?ajax=true"/>' + params,
        //成功返回后调用函数    
        success: function(){
        alert("返回成功!");
        //调用update函数,更新下载次数
        update();
        }    
        });
       // url: '<c:url value="/sharefile/shareFileAction!downLoadFile.html?ajax=true"/>' + params,
    }
      

  2.   


    下载不需要异步的,直接加个文件链接。然后通过文件路径在服务器下载即可。
    //文件共享下载
        function downLoadFile(){
            
            //拿到文件名和文件类型;
            var selectedRecords = tableGrid.getSelectionModel().getSelections();
            var fileName = selectedRecords[0].get('fileName');
            var fileType = selectedRecords[0].get('fileType');
            var selectedId = "";
            var selectedId = "&selectedId="+selectedRecords[0].get('id');
            //var params = "&fileName="+encodeURI(encodeURI(fileName));
            var params = "&fileName="+fileName;
            alert("params="+params); 
                   
            var url = "/emc/shareDownload/"+fileName; 
            
            //window.open(url);//这种方式不行么
           
            //异步请求,调用struts2的文件下载功能?
            Ext.Ajax.request({
                   method: 'POST',
                   //向后台Action传表单参数
                   url: '<c:url value="/sharefile/fileDownloadAction!download.html?ajax=true"/>' + params,//再说你这里的url好像不对啊,/sharefile/fileDownloadAction.action?download.html&ajax=true
    fileDownloadAction这个action下载已经配置了method是download,不带download
                   //成功返回后调用函数                   
                   success: function(){
                       alert("返回成功!");
                       //调用update函数,更新下载次数
                       update();
                   }                   
               });
           // url: '<c:url value="/sharefile/shareFileAction!downLoadFile.html?ajax=true"/>' + params,
        }
      

  3.   

    我之前就是在网页上拼接URL,然后调用window.open(url),我要下载的文件只有三种格式TXT,EXCEL和XML;这种方式有弊端,不能满足需求:
       如果文件名有中文,则服务器不识别;通过改变tomcat的默认编码为UTF-8虽然可以解决这个问题,但是如果是TXT文件就直接在浏览器中打开了,不能弹出文件保存对话框;
       我的想法就是通过异步将下载文件名传到后台,然后调用struts2自带的下载文件功能下载服务器指定目录下的文件。高人指点啊!!!
      
      

  4.   

      我的想法就是:前提不改变tomcat的默认编码;通过异步将下载文件名传到后台,然后调用struts2自带的下载文件功能下载服务器指定目录下的文件。高人指点啊!!!
      

  5.   

    下载的时候乱码我也遇到过了,这个还是可以搞定的。
    分get和默认方式,如果是get传递参数有中文就会乱码
    public String getFileName() {
            return fileName;
        }    public void setFileName(String fileName) {
            try {
                fileName = new String(fileName.getBytes(),"GBK");
                HttpSerlvetRequest request = ServletActionContext.getRequest();
                if (request.getMethod().equalsIgnoreCase("get")) {//get传参
                    fileName = new String(fileName.getBytes("ISO8859-1"),"GBK");
                }
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            this.fileName = fileName;
        }
    就是在下载的时候,如果文件名乱码了会有异常的对不对。你就用这种方式判断
    首次好像不会乱码,你要分情况处理。
    这个思路肯定是可以解决乱码的。还有如果是服务器不能识别的文件名称
    可以用js进行编码传递过去
    fileName = encodeURI(encodeURI("js客户端中文参数"))
    window.open("url?fileName=" + fileName);
    服务器端解码
    URLDecoder.decode(fileName, "utf-8")
      

  6.   

    谢谢您耐心的给予回复!这两天有事没上来,现在要继续解决这个问题,麻烦帮我看下!
    现在情况是这样的:struts.xml下载部分的配置如下:    <package name="sharefile" extends="default" namespace="/sharefile">
            <action name="shareFileAction!*" class="shareFileAction">
               <result name="listShareFiles">/WEB-INF/pages/sharefile/shareFileList.jsp</result>            
            </action>
            <!-- 文件下载,支持中文附件名 -->
            <action name="fileDownloadAction!*" class="com.tydic.emc.webapp.action.sharefile.FileDownloadAction">
                <!-- 初始文件名 -->
                <param name="fileName">\shareDownload\数据源_20100909.txt</param>
                <result name="success" type="stream">
                    <param name="contentType">application/octet-stream;charset=ISO8859-1</param>
                    <param name="inputName">inputStream</param>
                    <!-- 使用经过转码的文件名作为下载文件名,downloadFileName属性
                    对应action类中的方法 getDownloadFileName() -->
                    <param name="contentDisposition">attachment;filename="${fileName}"</param>
                    <param name="bufferSize">4096</param>
                </result>
            </action>
        </package>
    后台Action:package com.tydic.emc.webapp.action.sharefile;import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.UnsupportedEncodingException;import org.apache.struts2.ServletActionContext;import com.opensymphony.xwork2.Action;
    import com.sun.java_cup.internal.internal_error;public class FileDownloadAction implements Action {
    // 初始的通过param指定的文件名属性
    private String fileName ;
        //下载文件原始存放路径
        private final static String DOWNLOADFILEPATH="/shareDownload/";    public String getFileName() {
            return fileName;
        }    public void setFileName(String fileName) {
         try {
    fileName = new String(fileName.getBytes("ISO8859-1"),"GBK");
    } catch (UnsupportedEncodingException e) {
    e.printStackTrace();
    }
            this.fileName = fileName;
        }    //从下载文件原始存放路径读取得到文件输出流
        public InputStream getInputStream() throws IOException {
     
         //拿到web app的绝对根路径
    //String rootpath = ServletActionContext.getServletContext().getRealPath("/");
    //要下载的文件路径及文件名 String realPath=rootpath+"shareDownload\\"+fileName;
         String realPath="/shareDownload/"+fileName;
    System.out.println("getInputStream fileName=>"+fileName+" realPath=>"+realPath);
         InputStream in=ServletActionContext.getServletContext().getResourceAsStream(realPath);
         /*
         int b = 0;
         while((b=in.read())!=-1) {
         System.out.println((char)b);
         }
         */
         if(null==in){
        
         System.out.println("Can not find a java.io.InputStream with the name [inputStream] in the invocation stack. Check the <param name=\"inputName\"> tag specified for this action.检查action中文件下载路径是否正确.");  
         }
         //返回指定文件对应的输入流
         return ServletActionContext.getServletContext().getResourceAsStream(realPath);
    }
    /** 提供转换编码后的供下载用的文件名 */
    public String getDownloadFileName() {

    String downloadFileName = fileName;

    try {
    downloadFileName = new String(downloadFileName.getBytes("ISO8859-1"), "GBK");
    } catch (UnsupportedEncodingException e) {
    e.printStackTrace();
    }
    return downloadFileName;
    }
    /**
     * 下载文件
     * 
     * @return
     */
    public String download() {
    System.out.println("===DOWNLOADFILEPATH+fileName===>"+DOWNLOADFILEPATH+fileName);
    return SUCCESS;
    }
        public String execute() {
        
            return SUCCESS;
        }

    }
    Ext页面:<script type="text/javascript">
    function downLoad(){
         var str = '<a href="#" onclick="javascript:downLoadFile();return false"> <font color="green">下载</font> </a>';
         return str;
    }

    //文件共享下载
    function downLoadFile(){

    //拿到文件名和文件类型;
    var selectedRecords = tableGrid.getSelectionModel().getSelections();
    var fileName = selectedRecords[0].get('fileName');
    var fileType = selectedRecords[0].get('fileType');
            var selectedId = "";
            var selectedId = "&selectedId="+selectedRecords[0].get('id');
            //var params = "&fileName="+encodeURI(encodeURI(fileName));
            var params = "&fileName="+fileName;
            alert("params="+params); 
                   
    var url = "/emc/shareDownload"; 

    //window.open(url+"?fileName="+encodeURI(encodeURI(fileName)));        //异步请求,调用struts2的文件下载功能?
    Ext.Ajax.request({
        method: 'POST',
        //向后台Action传表单参数
        url: '<c:url value="/sharefile/fileDownloadAction!download.html?ajax=true"/>' + params,
        //成功返回后调用函数    
        success: function(){
        alert("返回成功!");
        //调用update函数,更新下载次数
        update();
        }    
        });
       // url: '<c:url value="/sharefile/shareFileAction!downLoadFile.html?ajax=true"/>' + params,
    }

    //更新下载次数
    function update() {

    var selectedRecords = tableGrid.getSelectionModel().getSelections();
    var selectedId = "";
            var selectedId = "&selectedId="+selectedRecords[0].get('id');
            
        Ext.Ajax.request({
        method: 'POST',
        //向后台Action传表单参数
        url: '<c:url value="/sharefile/shareFileAction!update.html?ajax=true"/>' + selectedId,
        //成功返回后调用函数    
        success: function(){
        parent.closePopupWin();
        //重新加载数据,刷新列表
        parent.rightContentFrm.contentWindow.location.reload();
        }    
        });
    }</script>执行流程==>点击下载后执行Action的download()方法返回SUCCESS;
        后台打印的测试语句如下:
    ===DOWNLOADFILEPATH+fileName===>/shareDownload/数据源_20100909.txt
    getInputStream fileName=>数据源_20100909.txt realPath=>/shareDownload/数据源_20100909.txt    可是并没有弹出文件保存对话框,但是也没有报错;不知道是什么原因呢?是哪里配置错了,还是这种下载方式行不通呢?还请指教!!!!!
        先去睡觉了......好困啊!
      

  7.   


    你的想法是好的,但是ajax好像不能实现异步下载的功能。如果要无刷新下载可以将
    下载的资源的url赋给一个隐藏的iframe,用iframe请求下载地址完成下载功能。
      

  8.   

    谢谢您啦!如果不用异步,但是又不脱离原来的Ext页面,还有其他的下载方式吗?我在网上找了很久,也没有找到好的解决方案!
      

  9.   

        还有一种做法就是不需要后台Action处理,直接在页面上将资源的URL地址拼接,比如:url="/emc/shareDownload/e_2010819.txt",其中/emc为web应用的根目录,然后掉用window.open(url);可以打开一个窗口;但是当这个文件名为中文,比如:url="/emc/shareDownload/数据源_2010819.txt",这时就不行了;
        还望高人指点啊!!!!!
      

  10.   


    你这样是直接链接到你的资源,并没有用struts action;
    你下载的Action干什么用的,你写了这么多还配置了xml。你又不用它?
    用FileDownloadAction 下载传递参数即可
    url="/emc/shareDownload/e_2010819.txt";
    <a href="FileDownloadAction.action?fileName=e_2010819.txt">下载</a>
      

  11.   

    那是我采用的第一种思路,没走通;
    我现在就是想问题简单化,不用Action处理了,直接window.open()打开资源;文件名是英文可以,一旦是中文就不行了,会报错,即资源找不到,报错:HTTP Status 404 - /emc/shareDownload/%E6%95%B0%E6%8D%AE%E6%BA%90_2010817.txt
      

  12.   


    所以就用action啊,action里面转码就可以了。上面不是给你说了么?
    look #6
      

  13.   

        那种方式我用过了啊!乱码问题是可以解决,但那不是困难所在;关键是得不到文件流,没有出现预期的文件保存对话框啊!!!我在#7楼已经提出过这个问题;就是上面Action里面贴出来的那句
          //返回指定文件对应的输入流
            return ServletActionContext.getServletContext().getResourceAsStream(realPath);
    我认为这句话执行完后,应该是会有个文件保存对话框的;但是什么都没有,后台也没报错
      

  14.   

    并不是这句话运行完了弹出,你先把struts2的基本下载搞好了,这里的下载和其他的下载是一样的
    只要你在jsp页面能下载,在js中也可以下载的
    就是多一步js将中文件名转码,然后在action再转码
    可以用js进行编码传递过去
    fileName = encodeURI(encodeURI("js客户端中文参数"))
    window.open("url?fileName=" + fileName);
    服务器端解码
    URLDecoder.decode(fileName, "utf-8")
      

  15.   

    中文名的话,Tomcat找不到资源
      

  16.   

    谢谢大侠的指点!呵呵...问题终于解决了!window.location = encodeURI(encodeURI('download.html?path=' + '' + '&fileName=' + fileName));可以去节贴了!!!!!!!!!
      

  17.   

    代码贴出,希望能给遇到相似问题的朋友一点启发!window.location = encodeURI(encodeURI('download.html?path=' + '' + '&fileName=' + fileName));
    后台代码在上面贴出来:
    服务器端解码:URLDecoder.decode(fileName, "utf-8")再次感谢hoojo
      

  18.   

    代码贴出,希望能给遇到相似问题的朋友一点启发!
    页面代码上面也有,关键点:
    window.location = encodeURI(encodeURI('download.html?path=' + '' + '&fileName=' + fileName));
    后台代码在上面贴出来:
    服务器端解码:URLDecoder.decode(fileName, "utf-8")再次感谢hoojo
      

  19.   

    ext下载 急用  我初学者  能否加个扣扣 给我讲下 450198392  谢谢