首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

strtus2 批量上载 中文有关问题、压缩文件等 - 讨论struts2工作流程

2012-11-15 
strtus2 批量下载 中文问题、压缩文件等 ------ 讨论struts2工作流程本文转载于:http://www.blogjava.net/x

strtus2 批量下载 中文问题、压缩文件等 ------ 讨论struts2工作流程
本文转载于:http://www.blogjava.net/xcp/archive/2009/10/30/downloadlist.html

最近因为一个项目,需要做统一的下载,并且要支持批量下载..其中涉及到的知识点有:get请求中文处理,下载动态设置下载名,批量下载,动态打包,流处理,删除临时文件,使用迅雷下载后台发出两次次下载请求,以及struts2工作流程与原理等..
      
       下面是我自己做的一个实例,主要实现遍历一个文件夹生成下载列表,用户可以单一下载,也可选择相关文件批量下载.....做的其中发现有很多疑惑的地方,请高手们指出....谢谢
     
      一.实例区
      1.index.html
      

<%@ page language="java" pageEncoding="gbk"%><%String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html>  <head>    <base href="<%=basePath%>">        <title>My JSP 'index.jsp' starting page</title>    <meta http-equiv="pragma" content="no-cache">    <meta http-equiv="cache-control" content="no-cache">    <meta http-equiv="expires" content="0">        <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">    <meta http-equiv="description" content="This is my page">    <!--    <link rel="stylesheet" type="text/css" href="styles.css">    -->  </head>    <body>           <hr>           <h3>欢迎光临下载区</h3>           <a href="downloadList.action">下载列表</a><br/>  </body></html>      
2.配置struts.xml
      
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE struts PUBLIC    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"    "http://struts.apache.org/dtds/struts-2.0.dtd"><struts>    <constant name="struts.custom.i18n.resources" value="message"></constant>    <constant name="struts.i18n.encoding" value="gbk"></constant>    <constant name="struts.multipart.saveDir" value="/tmp"></constant>    <constant name="struts.multipart.maxSize" value="209715200" />        <package name="struts2" extends="struts-default">                <action name="downloadList" type="stream">                <!-- contentType为二进制方式 -->                <param name="contentType">application/octet-stream;charset=ISO8859-1</param>                <!-- attachment属性强调是下载,就不会主动打开,比如图片 -->                <!-- 使用经过转码的文件名作为下载文件名,downloadFileName属性对应action类中的方法 getDownloadFileName() -->                <param name="contentDisposition">                    attachment;filename=${filename}                </param>                <param name="inputName">downloadFile</param>                <param name="bufferSize">4096</param>            </result>            <result name="input">/downloadList.jsp</result>            <result name="error">/downloadListError.jsp</result>        </action>    </package></struts>      
3.产生下载列表的Action----DownloadListAction
package cn.edu.cuit.disasterSystem.web.struts2.action;import java.io.File;import java.util.ArrayList;import java.util.HashMap;import java.util.Map;import org.apache.struts2.ServletActionContext;import com.opensymphony.xwork2.ActionContext;import com.opensymphony.xwork2.ActionSupport;/** * 显示所有down目录的文件,供下载所用 * @author  xcp * @version  1.0 * Copyright (C), 2009 智能开发实验室 所有 * Program Name:灾情信息管理系统 * Date: 2009-10-24 上午11:16:41 */@SuppressWarnings("serial")public class DownloadListAction  extends ActionSupport{        private static ArrayList<String> filelist = new ArrayList<String>();            /**     *    可以是前台一个页面传入,也可以是手动指定,其作用是指定下载文件的根目录     * @author  向才鹏     * 2009-10-24 下午12:02:47     */    private String downloadRootPath = "/upload";        public String getDownloadRootPath() {        return downloadRootPath;    }    public void setDownloadRootPath(String downloadRootPath) {        this.downloadRootPath = downloadRootPath;    }    /**     * 将指定文件路径下的文件全部遍历出来      * @author 向才鹏     * @param strPath 指来要遍历的文件     * 2009-10-24   下午12:04:48     */    public static void refreshFileList(String strPath)    {        File dir = new File(strPath);        File[] files = dir.listFiles();        if (files == null)            return;        for (int i = 0; i < files.length; i++)        {            if (files[i].isDirectory())            {                refreshFileList(files[i].getAbsolutePath());            } else            {                String filePath =  files[i].getPath();                filelist.add(filePath);            }        }    }            /**     * 格式化输出数据存入Map,形式文件名+文件服务端路径     * @author 向才鹏     * @param filelist 遍历出来的文件路径     * @param downloadRootPath 指明服务器下载的文件,便于从遍历出来的文件中取得服务端路径     * @return     * 2009-10-24   下午12:06:18     */    private static Map<String,String> formatFileMap(ArrayList<String> filelist,String downloadRootPath){        Map<String,String> formatFileMap = new HashMap<String,String>();        //得到服务下载的根路径,并将/换成\\,这样便于替换        String formatDownloadRootPath =  downloadRootPath.replaceAll("/", "\\\");        for(String filePath : filelist){            //得到下载的相对路径            String  downloadPath = filePath.substring(filePath.indexOf(formatDownloadRootPath));            //将得到的相对路径的\\转换成/            String formatDownloadPath = downloadPath.replaceAll("\\\", "/");            //得到文件名            String filename = formatDownloadPath.substring(formatDownloadPath.lastIndexOf("/")+1);                    /*try {                formatFileMap.put(filename, URLEncoder.encode(formatDownloadPath, "gbk"));            } catch (UnsupportedEncodingException e) {                formatFileMap.put(filename, formatDownloadPath);                e.printStackTrace();            }*/                        //这就不用考虑设置编码了,再后面统一使用javascript的encodeURI函数            formatFileMap.put(filename, formatDownloadPath);                    }        return formatFileMap;    }            @SuppressWarnings("unchecked")    @Override    public String execute() throws Exception {                //指定下载目录        String upload = ServletActionContext.getServletContext().getRealPath(downloadRootPath);        //清理filelist        filelist.clear();        //遍历文件        refreshFileList(upload);                ActionContext context = ActionContext.getContext();        Map request = (Map) context.get("request");                        if(filelist != null){            //格式化文件信息,包括文件名和地址            Map<String,String> formatFileMap = formatFileMap(filelist,downloadRootPath);            request.put("fileMap", formatFileMap);            return SUCCESS;        }        else{            request.put("errorMessage", "没有相关的下载文件");            return ERROR;        }                }        }      
4.显示下载列表downloadList.jsp
<%@ page language="java" contentType="text/html; charset=gbk"    pageEncoding="gbk"%><%@ taglib prefix="s" uri="/struts-tags"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><script type="text/javascript">    function downloadFile1(filenames,filepaths){        location.href=encodeURI("download.action?filenames="+filenames+"&filepaths="+filepaths);    }    function SelectAll(oForm)    {        for(var i=0;i<oForm.url.length;i++)        {            oForm.url[i].checked=true;        }    }    function TurnOver(oForm)    {        for(var i=0;i<oForm.url.length;i++)        {            oForm.url[i].checked=!oForm.url[i].checked;        }    }    function DownlodSelected(oForm){         if(confirm("因需要在服务端动态打包,需要时间比较长,是否继续批量下载?"))            {             var arrDownloadList = [];            for(var i=0;i<oForm.url.length;i++){                if(oForm.url[i].checked==true){                    if(arrDownloadList.length==0){                        arrDownloadList[0] = oForm.url.value;                    }                    arrDownloadList[arrDownloadList.length] = oForm.url[i].value;                }            }            if (arrDownloadList.length>0){                var temp = [];                var filenames="";                var filepaths="";                for(var i=1;i<arrDownloadList.length;i++){                    temp = arrDownloadList[i].split(",")                    if(filenames=="" && filepaths==""){                        filenames=temp[0]                        filepaths=temp[1]                    }else{                            filenames=filenames+"|"+temp[0];                        filepaths=filepaths+"|"+temp[1];                    }                }                downloadFile1(filenames,filepaths);            }else{                alert("还没有选中下载项");            }           }    }</script><html>    <head>        <meta http-equiv="Content-Type" content="text/html; charset=GB18030">        <title>Insert title here</title>        <script type="text/javascript" src="dwr/engine.js"></script>        <script type="text/javascript" src="dwr/util.js"></script>        <script type="text/javascript" src="dwr/interface/downloaddwr.js"></script>    </head>    <body>        <form name="myform" style="display: inline" onSubmit="return false">            <table width="50%" align="center">                <tr>                    <td colspan="2">                        <h3>                            以后是下载列表,点击进行下载                        </h3>                    </td>                </tr>                <tr>                    <td colspan="2">                        <font color="red"><s:fielderror></s:fielderror> </font>                    </td>                </tr>                <s:iterator value="#request.fileMap" status="stuts">                    <s:if test="#stuts.odd == true">                        <tr style="background-color: #77D9F6">                            <td>                                <input name="url" type="checkbox" id="url"                                    value="<s:property value="key" />,<s:property value="value" />">                            </td>                            <td>                                <s:property value="key" />                            </td>                            <td>                                <a href="#"                                    onclick="downloadFile1('<s:property value="key" />','<s:property value="value" />')">点击下载</a>                            </td>                        </tr>                    </s:if>                    <s:else>                        <tr style="background-color: #D7F2F4">                            <td>                                <input name="url" type="checkbox" id="url"                                    value="<s:property value="key" />,<s:property value="value" />">                            </td>                            <td>                                <s:property value="key" />                            </td>                            <td>                                <a href="#"                                    onclick="downloadFile1('<s:property value="key" />','<s:property value="value" />')">点击下载</a>                            </td>                        </tr>                    </s:else>                </s:iterator>            </table>            <div align="center">                <input title="选择下载的文件"                    onClick="SelectAll(this.form)" type="button" value="全选">                <input title="反向选择下载文件"                    onClick="TurnOver(this.form)" type="button" value="反选">                <input title="下载选中文件"                    onClick="DownlodSelected(this.form)" type="button" value="批量下载文件">            </div>        </form>        <frame src="" id="dis">        </frame>    </body></html>      
5.统一处理下载的Action----DownloadAction
package cn.edu.cuit.disasterSystem.web.struts2.action;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.UnsupportedEncodingException;import java.text.SimpleDateFormat;import java.util.Date;import org.apache.struts2.ServletActionContext;import org.apache.tools.zip.ZipEntry;import org.apache.tools.zip.ZipOutputStream;import com.opensymphony.xwork2.ActionSupport;/** * 统一下载类 *  * @author xcp * @version 1.0 Copyright (C), 2009 智能开发实验室 所有 Program Name:灾情信息管理系统 *          Date: 2009-10-30 上午09:06:01 */@SuppressWarnings("serial")public class DownloadAction extends ActionSupport {    private String   filenames;    private String   filepaths;    private String[] filenameArray = null;    private String[] filepathArray = null;    private String   filename;    private String   filepath;    private SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");                /**     * 得到客户端请求的文件名字符串     * @author 向才鹏     * @return 客户端请求的文件名字符串     * 2009-10-30   下午11:21:31     */    public String getFilenames() {        return filenames;    }    /**     * 将客户端请求的文件名字符串set到filenames变量     * @author 向才鹏     * @param filenames     * 2009-10-30   下午11:21:34     */    public void setFilenames(String filenames) {        this.filenames = filenames;        if (this.filenames.contains("|")) {            parseFilenamesToArray();        }    }    /**     * 得到客户端请求的文件路径字符串     * @author 向才鹏     * @return 客户端请求的文件路径字符串     * 2009-10-30   下午11:21:37     */    public String getFilepaths() {        return filepaths;    }    /**     * 将客户端请求的文件路径字符串set到filepaths变量     * @author 向才鹏     * @param filepaths     * 2009-10-30   下午11:21:40     */    public void setFilepaths(String filepaths) {        this.filepaths = filepaths;        if (this.filepaths.contains("|")) {            parseFilepathsToArray();        }    }                /**     * 解析客户端请求下载的文件名     * @author 向才鹏     * 2009-10-30   下午11:23:43     */    public void parseFilenamesToArray() {        filenameArray = filenames.split("\\|");    }    /**     * 解析客户端请求下载的文件路径     * @author 向才鹏     * 2009-10-30   下午11:23:46     */    public void parseFilepathsToArray() {        filepathArray = filepaths.split("\\|");    }                      /**     *  得到下载显示名,对就struts.xml配置文件<param name="contentDisposition">attachment;filename=${filename}</param>     *  要想正确的显示中文文件名,我们需要对fileName再次编码 否则中文名文件将出现乱码,或无法下载的情况     * @author 向才鹏     * @return 返回下载显示名     * 2009-10-30   下午11:26:49     */    public String getFilename() {        try {            return new String(filename.getBytes(), "ISO-8859-1");        } catch (UnsupportedEncodingException e) {            e.printStackTrace();            return filename;        }    }            /**      *  得到下载文件路径     * @author 向才鹏     * @return 返回下载路径     * 2009-10-30   下午11:27:52     */    public String getFilepath(){        return filepath;    }        /**     * 初始化下载文件名     * @author 向才鹏     * 2009-10-30   下午11:29:00     */    public void initFilename() {        if(isBaleZip()){            this.filename = "批量打包下载.zip";        }else{            this.filename = getFilenames();        }        System.out.println("下载文件名:    "+filename);    }            /**     *  初始化下载路径     * @author 向才鹏     * 2009-10-30   下午11:30:04     */    public void initFilepath() {        if(isBaleZip()){            String rootpath = ServletActionContext.getServletContext().getRealPath("/upload/temp");            String requestip = ServletActionContext.getRequest().getLocalAddr();            //this.filepath = "c:\\批量打包下载.zip";            this.filepath = rootpath+"\"+requestip+"-"+format.format(new Date())+".zip";        }else{            this.filepath = getFilepaths();        }        System.out.println("下载文件路径:    "+filepath);    }        /**     * 判断是否符合打包要求     * @author 向才鹏     * @return 否符合打包要求     * 2009-10-30   上午11:36:09     */    public  boolean isBaleZip(){        boolean isZip = false;        if(this.filenameArray!= null && this.filepathArray!= null && this.filenameArray.length>0 && this.filenameArray.length==this.filepathArray.length){             isZip =  true;        }        return isZip;    }            /**     * 压缩文件     * @author 向才鹏     * @param zipFilePath  产生的压缩文件路径和名字     * @param names        传入要进行打包的所有文件名     * @param paths        传入要进行打包的所有文件路径     * @throws IOException     * 2009-10-30   下午11:39:14     */    public void baleZip(String zipFilePath,String[] names,String[] paths) throws IOException{        File f = new File(zipFilePath);        f.createNewFile();        ZipOutputStream out = new ZipOutputStream(new FileOutputStream(f));        out.putNextEntry(new ZipEntry("/"));        for(int i=0;i<paths.length;i++){            out.putNextEntry(new ZipEntry(names[i]));             InputStream in =ServletActionContext.getServletContext().getResourceAsStream(paths[i]);            int b;            while ((b = in.read()) != -1) {                out.write(b);            }            in.close();        }         out.flush();         out.close();    }                    /**     *  返回目标下载文件输入流跟struts2,然后struts2再生成输出流,对应struts.xml的<param name="inputName">downloadFile </param>     *  但是struts2后台不可能一次性将我们的输入流输出到输出流里面.. 而我们也就是不好控制,例在何时删除产生的临时文件     * @author 向才鹏     * @return 目标下载文件输入流     * 2009-10-30   上午11:45:29     */    public InputStream getDownloadFile(){        initFilename();        initFilepath();        InputStream in = null;        File tempfile = null;        if(isBaleZip()){            try {                baleZip(this.filepath,this.filenameArray,this.filepathArray);                tempfile = new File(this.filepath);                in =  new FileInputStream(tempfile);                            } catch (IOException e) {                System.out.println(e.getMessage()+"   "+"压缩文件出错!!");                return null;            } finally{                if(tempfile.exists()){                    tempfile.delete();                    if(tempfile.exists()){                        System.out.println("------删除临时文件失败-------");                    }else{                        System.out.println("------删除打包产生的临时文件------");                    }                }            }        }else{            in  = ServletActionContext.getServletContext().getResourceAsStream(getFilepath());        }        return in;    }            /**     * 而这种文件下载方式却是存在安全隐患的, 因为访问者如果精通Struts2的话,它可能使用这样的带有表单参数的地址来访问:     * http://localhost:8080/disasterSystem/download.action?filename=%E6%B5%8B%E8%AF%95%E4%B8%8B%E8%BD%BD&filepath=/WEB-INF/web.xml     * 这样的结果就是下载后的文件内容是您系统里面的web.xml的文件的源代码,甚至还可以用这种方式来下载任何其它JSP文件的源码, 这对系统安全是个很大的威胁。     * 作为一种变通的方法,读者最好是从数据库中进行路径配置,然后把Action类中的设置inputPath的方法统统去掉,简言之就是所有set方法定义     * 第二种方法,读者可以在execute()方法中进行路径检查,如果发现有访问不属于download下面文件的代码,就一律拒绝,不给他们返回文件内容。     *      * @author 向才鹏     * @param filepath     *            2009-10-30 上午09:34:43     */    @Override    public String execute() throws Exception {        // 文件下载目录路径        String downloadDir = "/upload";        // 发现企图下载不在 /download 下的文件, 就显示空内容        if (!filepaths.startsWith(downloadDir)) {            // 可以抛出一些异常信息            System.out.println("只能下载upload里面的东西,谢谢!");            return ERROR;        }        return SUCCESS;    }}




======疑惑======
      1.getDownloadFile()返回目标下载文件输入流跟struts2,然后struts2再生成输出流,对应struts.xml的<param name="inputName">downloadFile </param>
, 但是struts2后台不可能一次性将我们的输入流输出到输出流里面.. 而我们也就是不好控制,例在何时删除产生的临时文件,而且我上面删除临时文件的时候出错.(所有下面有一个struts2的工作流程,欢迎大家来讨论,指教,学习)
     2.就下载的时候,如果用普通的window对话框形式来下载,一切正常.而我们用迅雷下载的时候,产生两个临时文件,当时把我雷惨了...后来打断点测试,确实迅雷下载的时候是重新发出了一次请求,虽然对下载无影响,但打包下载本身就比较慢,这样就对下载的性能有很大的影响,这也是我下面要问的问题
     3.打包下载性能真的很差,有没有更好的批量下载方法,请大家指出..谢谢

热点排行