strtus2 批量下載 中文問題、壓縮文件等 ------ 討論struts2工作流程
Posted on 2009-10-30 23:52 xcp 閱讀(5544) 評論(8) 編輯 收藏 所屬分類: struts2 最近因為一個項目,需要做統一的下載,并且要支持批量下載..其中涉及到的知識點有:get請求中文處理,下載動態設置下載名,批量下載,動態打包,流處理,刪除臨時文件,使用迅雷下載后臺發出兩次次下載請求,以及struts2工作流程與原理等..
下面是我自己做的一個實例,主要實現遍歷一個文件夾生成下載列表,用戶可以單一下載,也可選擇相關文件批量下載.....做的其中發現有很多疑惑的地方,請高手們指出....謝謝
一.實例區
1.index.html
二. 說明區
1.get請求中文處理參見:http://www.aygfsteel.com/xcp/archive/2009/10/29/download2.html
2.文件打包參見:http://www.aygfsteel.com/xcp/archive/2009/10/30/CompressToZip.html
三.本人疑惑區
1.getDownloadFile()返回目標下載文件輸入流跟struts2,然后struts2再生成輸出流,對應struts.xml的<param name="inputName">downloadFile </param>
, 但是struts2后臺不可能一次性將我們的輸入流輸出到輸出流里面.. 而我們也就是不好控制,例在何時刪除產生的臨時文件,而且我上面刪除臨時文件的時候出錯.(所有下面有一個struts2的工作流程,歡迎大家來討論,指教,學習)
2.就下載的時候,如果用普通的window對話框形式來下載,一切正常.而我們用迅雷下載的時候,產生兩個臨時文件,當時把我雷慘了...后來打斷點測試,確實迅雷下載的時候是重新發出了一次請求,雖然對下載無影響,但打包下載本身就比較慢,這樣就對下載的性能有很大的影響,這也是我下面要問的問題
3.打包下載性能真的很差,有沒有更好的批量下載方法,請大家指出..謝謝
四.討論struts2流程
1.我加載struts2的FilterDispatcher類的init()方法處打下斷點,可以明顯看出從tomcat到struts2工作的整個流程,大家都看看,把學到的跟小弟共享下.
2. 一個傻傻的問題,但是要真正把它弄清楚也不容易,Servlet,Filter,Intercept,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<%
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>
<?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.jsp</result>
<result name="error">/downloadListError.jsp</result>
</action>
<action name="download" class="cn.edu.cuit.disasterSystem.web.struts2.action.DownloadAction">
<result name="success" 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<!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.jsp</result>
<result name="error">/downloadListError.jsp</result>
</action>
<action name="download" class="cn.edu.cuit.disasterSystem.web.struts2.action.DownloadAction">
<result name="success" 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>
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.jspimport 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;
}
}
}
<%@ 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 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----DownloadActionpageEncoding="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 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>
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;
}
}
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.get請求中文處理參見:http://www.aygfsteel.com/xcp/archive/2009/10/29/download2.html
2.文件打包參見:http://www.aygfsteel.com/xcp/archive/2009/10/30/CompressToZip.html
三.本人疑惑區
1.getDownloadFile()返回目標下載文件輸入流跟struts2,然后struts2再生成輸出流,對應struts.xml的<param name="inputName">downloadFile </param>
, 但是struts2后臺不可能一次性將我們的輸入流輸出到輸出流里面.. 而我們也就是不好控制,例在何時刪除產生的臨時文件,而且我上面刪除臨時文件的時候出錯.(所有下面有一個struts2的工作流程,歡迎大家來討論,指教,學習)
2.就下載的時候,如果用普通的window對話框形式來下載,一切正常.而我們用迅雷下載的時候,產生兩個臨時文件,當時把我雷慘了...后來打斷點測試,確實迅雷下載的時候是重新發出了一次請求,雖然對下載無影響,但打包下載本身就比較慢,這樣就對下載的性能有很大的影響,這也是我下面要問的問題
3.打包下載性能真的很差,有沒有更好的批量下載方法,請大家指出..謝謝
四.討論struts2流程
1.我加載struts2的FilterDispatcher類的init()方法處打下斷點,可以明顯看出從tomcat到struts2工作的整個流程,大家都看看,把學到的跟小弟共享下.
2. 一個傻傻的問題,但是要真正把它弄清楚也不容易,Servlet,Filter,Intercept,Struts2工作底層到底有何聯系..
請高手多多指教!!!!
名稱: ?4C.ESL | .↗Evon
口號: 遇到新問題?先要尋找一個方案乄而不是創造一個方案こ
mail: 聯系我