strtus2 批量下载 中文问题、压缩文件等 -凯发k8网页登录

苟有恒,何必三更起五更眠;
最无益,只怕一日曝十日寒.
posts - 241, comments - 318, trackbacks - 0, articles - 16
posted on 2009-10-30 23:52 xcp 阅读(5448) 评论(8)     所属分类: struts2
       最近因为一个项目,需要做统一的下载,并且要支持批量下载..其中涉及到的知识点有: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 pagetitle>
    
<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">
    

  
head>
  
  
<body>
           
<hr>
           
<h3>欢迎光临下载区h3>
           
<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" class="cn.edu.cuit.disastersystem.web.struts2.action.downloadlistaction">
            
<result name="success">/downloadlist.jspresult>
            
<result name="error">/downloadlisterror.jspresult>        
        
action>
    
    
        
            
<action name="download" class="cn.edu.cuit.disastersystem.web.struts2.action.downloadaction">
            
<result name="success" type="stream">
                

                
<param name="contenttype">application/octet-stream;charset=iso8859-1param>
                

                

                
<param name="contentdisposition">
                    attachment;filename=${filename}
                
param>
                
<param name="inputname">downloadfileparam>
                
<param name="buffersize">4096param>
            
result>
            
<result name="input">/downloadlist.jspresult>
            
<result name="error">/downloadlisterror.jspresult>
        
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 heretitle>
        
<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
="key" />,<s:property value="value" />">
                            
td>
                            
<td>
                                
<s:property value="key" />
                            
td>
                            
<td>
                                
<href="#"
                                    onclick
="downloadfile1('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
="key" />,<s:property value="value" />">
                            
td>
                            
<td>
                                
<s:property value="key" />
                            
td>

                            
<td>
                                
<href="#"
                                    onclick
="downloadfile1('key" />','<s:property value="value" />')">点击下载a>
                            
td>
                        
tr>
                    
s:else>
                
s:iterator>
            
table>
            
<div align="center">
                
<input class="green_at_bn" title="选择下载的文件"
                    onclick
="selectall(this.form)" type="button" value="全选">
                
<input class="green_at_bn" title="反向选择下载文件"
                    onclick
="turnover(this.form)" type="button" value="反选">
                
<input class="green_at_bn" 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配置文件attachment;filename=${filename}
     *  要想正确的显示中文文件名,我们需要对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的downloadfile 
     *  但是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=测试下载&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.get请求中文处理参见:http://www.blogjava.net/xcp/archive/2009/10/29/download2.html
       2.文件打包参见:http://www.blogjava.net/xcp/archive/2009/10/30/compresstozip.html 
      


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




      四.讨论struts2流程
      1.我加载struts2的filterdispatcher类的init()方法处打下断点,可以明显看出从tomcat到struts2工作的整个流程,大家都看看,把学到的跟小弟共享下.
      2. 一个傻傻的问题,但是要真正把它弄清楚也不容易,servlet,filter,intercept,struts2工作底层到底有何联系..

      请高手多多指教!!!!
    


名称: ♪4c.esl | .↗evon
口号: 遇到新问题♪先要寻找一个方案乄而不是创造一个方案こ
mail:


feedback

# re: strtus2 批量 打包 下载 中文问题 ------ 讨论struts2工作流程[未登录]  回复     

2009-10-31 07:54 by
我路过的, 顺便打酱油.

# re: strtus2 批量 打包 下载 中文问题 ------ 讨论struts2工作流程  回复     

2009-10-31 11:53 by
现在正在学struts2,我是个新手

# re: strtus2 批量下载 中文问题、压缩文件等 ------ 讨论struts2工作流程  回复     

2009-11-02 20:24 by
飘过。。。

# re: strtus2 批量下载 中文问题、压缩文件等 ------ 讨论struts2工作流程  回复     

2009-11-04 14:43 by
看的有点懵!

# re: strtus2 批量下载 中文问题、压缩文件等 ------ 讨论struts2工作流程[未登录]  回复     

2009-11-23 20:56 by
你这个struts2 批量下载 有很大的问题哦。。。我想跟你学习学习。。。。可否有时间联系。。。这是我的qq:973214685

# re: strtus2 批量下载 中文问题、压缩文件等 ------ 讨论struts2工作流程  回复     

2011-03-09 16:52 by
你好,这个程序总是提示这样的错误:
严重: can not find a java.io.inputstream with the name [downloadfile] in the invocation stack. check the tag specified for this action.

请问你是怎样解决的?有什么办法吗?

# re: strtus2 批量下载 中文问题、压缩文件等 ------ 讨论struts2工作流程  回复     

2011-03-09 16:53 by
我的qq: 122 489 488

# re: strtus2 批量下载 中文问题、压缩文件等 ------ 讨论struts2工作流程  回复     

2016-02-02 00:35 by
你好,这个程序总是提示这样的错误:
严重: can not find a java.io.inputstream with the name [downloadfile] in the invocation stack. check the tag specified for this action.

请问你是怎样解决的?有什么办法吗? 我的qq:1135807396

只有注册用户后才能发表评论。


网站导航:
              
 
网站地图