于是找啊找,单纯的文件下载功能还是挺容易的,既可以自己写,也可以用类似smartupload这类现成的包。 至于为什么不用直接的链接,是为了防止服务器文件结构泄漏,有心人其他文件也可以随意下载,那岂不是麻烦?
如果要自己写得话,action的写法大致有三 1, 用输入流,输出流 2, 用dispatcher 3, 用downloadAction
方法3是struts推荐的官方写http://wiki.apache.org/struts/StrutsFileDownload 写的时候,只要继承downloadAction类,然后重写getStreamInfo方法就可以了。但是看一下这个类的src http://www.docjar.org/html/api/org/apache/struts/actions/DownloadAction.java.html 就明白,这个类的getStreamInfo会把结果传给execute方法,而execute方法的最后却被注明
Java代码
// Tell Struts that we are done with the response.
return null;
意味着根本不可能做任何转向。至于试着再重写一下execute方法,好像没有人这么办,在google.com上以关键字downloadAction redirect 或者downloadAction foward,也没有任何可以有用的结果,所以首先放弃了这个方法。不过这个方法还是最简单最可靠的,仿照它给的例子,几行代码就完事,真好。
方法2 以前单独在jsp中,这种方法可能挺流行的,不过在action中一样行不通。 例如代码
Java代码
<pre name=”code” class=”java”>
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
FileDownLoadForm fdform =(FileDownLoadForm)form;
String path = fdform.getFilePath();
response.setContentType("application/x-download");
String filenamedownload = path;
String filenamedisplay = path.substring(path.lastIndexOf("/")+1);
try {
filenamedisplay = URLEncoder.encode(filenamedisplay,"UTF-8");
response.addHeader("Content-Disposition","attachment;filename=" + filenamedisplay);
RequestDispatcher dispatcher = request.getRequestDispatcher(filenamedownload);
if(dispatcher != null)
{
dispatcher.forward(request,response);
}
response.flushBuffer();
return null ;
// return mapping.findForward("success");
}catch(FileNotFoundException e){
e.printStackTrace();
return mapping.findForward("error");
}catch(Exception e){
e.printStackTrace();
return null;
}
}
</pre>
解释1 为什么成功后return null 因为前面response 已经提交过,没办法再forward,否则报错
解释2 为什么FileNotFoundException转到error画面,因为对话框中,用户如果点取消按钮,tomcat会报ClientAbortException
假如连这个exception都抓掉,然后进行forward,一样会报response已经提交过的错误,根本无法转向。所以干脆就留
着它好了。
方法1 其实根方法3一样,输入流,输出流,有兴趣地可以用IOUtils.copy(in, response.getOutputStream());
没兴趣的可以参照以下代码,我也是参考论坛上一位兄弟的
Java代码
Java代码
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
FileDownLoadForm fdform =(FileDownLoadForm)form;
String path = fdform.getFilePath();
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
InputStream fis = null;
OutputStream fos = null;
try{
File uploadFile = new File(path);
fis = new FileInputStream(uploadFile);
bis = new BufferedInputStream(fis);
fos = response.getOutputStream();
bos = new BufferedOutputStream(fos);
response.reset();
response.setHeader("Content-disposition", "attachment;filename =" + URLEncoder.encode(path.substring(path.lastIndexOf("/")+1), "utf-8"));
int bytesRead = 0;
byte[] buffer = new byte[4096];
while((bytesRead = bis.read(buffer,0,4096)) != -1){
bos.write(buffer, 0, bytesRead);
}
bos.flush();
fis.close();
bis.close();
fos.close();
bos.close();
//return mapping.findForward("success");
return null;
}catch(FileNotFoundException e){
e.printStackTrace();
return mapping.findForward("error");
}catch(Exception e){
e.printStackTrace();
return null;
}
}
解释1 为什么要response.reset(); 假如这个方法是写在一个图片的链接上,如果不reset,就没办法多次下载,
不过对我来说现在没什么影响
解释2 对话框那块为什么只显示文件名 开始的时候我把整个路径都写进去了,结果倒也能下载,可使整个文件的路径都暴露了,跟直接用链接没什么区别了,所以一定要只写文件名
以上3个方法都不能实现成功后转向成功页面的问题,在javaeye和csdn上询问也没有什么结果,不过我的确是见过类似的网页,不知道他们是怎么完成的?始终疑问阿。
没有办法,只好考虑作个假的成功画面,用DispatchAction
一个action1 ,实现转向成功页面功能 , 一个action 2 ,实现下载功能
工作流程为 点击链接, 甭管文件存在不存在,直接进入成功画面,在成功画面打开的同时,执行action2
Java代码
<script type="text/javascript">
function download() {
window.location ="download.do?method=action2&filePath="+"<bean:write name="filePath" />";
}
</script>
</head>
<body onload=download()>
如果文件找不到,则成功画面会转向到失败画面,否则会留在成功画面并弹出对话框