struts文件下载

Struts2 文件下载(中文处理方法以及控制下载文件名称和扩展名)

Struts2的框架提供了现成的文件下载方式,大大简化了开发下载功能的便利性。网上的例子有很多,我把一些大家普遍比较关注的点,集中一下,给出一个整体方案。

一般我们照着书本或者网上的列子写出了一个Demo,都会存在几个疑问:

 

1.下载文件的文件名怎么搞?不搞的话浏览器默认名字是提交的action的名字,显然不好

2.文件名里面想搞中文,但是实际上下载文件名出现了乱码或不显示中文怎么搞?

3.文件的扩展名怎么搞?比如要下载的文件是word(doc,docx)或者excel(xls,xlsx)怎么办?难道让用户自己改扩展名,太不友好了吧。

下面我们逐个说明。

 

场景:我们需要下载存放在服务器tomcat中webapp文件夹,对应x项目根目录下“电子表格.xlsx"文件。即tomcat\webapp\x\电子表格.xlsx文件。

并且希望用户下载的名字是“我的电子表格.xlsx”。

首先,如同Struts2框架处理其他问题一样,我们需要有一个标准的action类来对下载请求进行处理。

Action类:

  

Struts.xml的action配置

 

 

看完代码后的解释:

1.核心的下载功能是怎么实现的

 第一,action类里面提供了InputStream流的对象is,并且在配置文件中,同Struts框架的inputName参数进行了绑定。Strut2利用Servlet本来就有的标准流服务提供给客户端的浏览器进行下载。

  关键配置:

  result的type不再是一般的"dispatcher",而是"stream",表明返回给客户端的是流对象。一个名字为"inputName"的param参数表示,你得告诉框架,

action类里面哪个参数是要提供下载的InputStream对象。我们这里就是is

  

     关键代码:

  InputStream对象 is,并且必须有对应的get方法,不然框架拿不到这个对象。注意大小写

     

      

  为is对象赋值,得到真正文件的流对象。

    

 2.名字怎么搞?

 这种姿势搞(顺便把扩展名和中午字符一并搞了):

   关键配置:

  attachment标示告诉浏览器是附件,不要打开(有时候下载的文件是txt之类的有些浏览器默认自动打开,而不是下载)。

  filename=&{fileName},指定要下载的文件是什么名字。${fileName}这个通配符加大括号表示,文件的名字不是fileName,而是在

 action类中一个名字叫fileName的参数的值

  关键编码:

  

  由于浏览器在只能识别用ISO8859-1编码的UTF-8的字符串,所以我们需要在代码中把中文的文件名用ISO8859-1再重新编码一下。这样就解决了中文问题。

 扩展名怎么解决?看上面的图,xlsx扩展名一并同文件名统一处理。下载的文件自然就带这个扩展名了。

 

以上,文章开头的三个问题得到解决。

至于buffersize就不解释了,所有的流传输肯定都有缓冲的概念。

有人可能会问,为什么action的配置中,param参数了没有如<param name="contentType">application/zip</param>这样的配置。其实这就是html页面的头部标记。

我不用是因为:

我不需要呀!因为result的type设置为stream,让浏览器已经知道了是流文件,再加上contentDisposition把文件名连同连扩展名都搞定了,加上这个头参数没啥用。不信可以加上,随便设置什么MIME的头标记,都不起作用了。

当然,如果每次下载的都是固定名字,配置文件也可以这样:

这串文字代表MIME协议(多用途的网际邮件扩充协议;)里面的xlsx格式。

下面附上MIME常用的数据类型对应关系:

.doc     application/msword

.docx   application/vnd.openxmlformats-officedocument.wordprocessingml.document

.rtf       application/rtf

 

.xls     application/vnd.ms-excel application/x-excel

.xlsx    application/vnd.openxmlformats-officedocument.spreadsheetml.sheet

 

.ppt     application/vnd.ms-powerpoint

.pptx    application/vnd.openxmlformats-officedocument.presentationml.presentation

 

.pps     application/vnd.ms-powerpoint

.ppsx   application/vnd.openxmlformats-officedocument.presentationml.slideshow

 

.pdf     application/pdf

.swf    application/x-shockwave-flash

.dll      application/x-msdownload

 

.exe    application/octet-stream

.msi    application/octet-stream

.chm    application/octet-stream

.cab    application/octet-stream

.ocx    application/octet-stream

 

.rar     application/octet-stream

.tar     application/x-tar

.tgz    application/x-compressed

.zip    application/x-zip-compressed

.z       application/x-compress

 

.wav   audio/wav

.wma   audio/x-ms-wma

.wmv   video/x-ms-wmv

.mp3 .mp2 .mpe .mpeg .mpg     audio/mpeg

.rm     application/vnd.rn-realmedia

 

.mid .midi .rmi     audio/mid

 

.bmp     image/bmp

.gif     image/gif

.png    image/png

.tif .tiff    image/tiff

.jpe .jpeg .jpg     image/jpeg

 

.txt      text/plain

.xml     text/xml

.html     text/html

.css      text/css

.js        text/javascript

 

.mht .mhtml   message/rfc822

以上网络搜索

 

 

笔记代码:

思路:页面显示文件名(原来上传时候)的链接,链接中调用action,然后action中使用stream的结果集,然后下载文件。

 

分析:关键点:stream的结果集怎么配置:

 

需要三个东西:输入流(需要文件的实际路径)、类型、附件打开方式(是直接打开还是下载,配置原来的文件名)

 

 

 

需要实际文件路径和原来旧的文件名称,都可以从数据库查询:

 

 

思考:两种方案拿到文件路径和文件名:

  1. 将记录的id传递给后台,后台再从数据库查询这条记录,得到路径和文件名(缺点:还要再查询一次数据库)
  2. 直接将路径和文件名传递给后台。(缺点:可能文件名有乱码问题)

 

第一种方式:

View.jsp

 

 

userAction

//下载文件

   public String downfile() throws Exception{

     

      //先获取路径

      UserService userService= new UserService();

      User queryUser=userService.findUserById(user.getUserID());

     

      String realFullFilePath=SystemConstant.BASE_FILE_PATH+ queryUser.getPath();

      //将文件的输入流放入root

      ActionContext.getContext().getValueStack().set("inputStream", new FileInputStream(new File(realFullFilePath)) );//栈顶

      ActionContext.getContext().put("inputStream", new FileInputStream(new File(realFullFilePath)) );

     

      //问题:内置打开的该文件,而且乱码

     

      //两件事情:

      //1.文件类型的获取

      String contentType = ServletActionContext.getServletContext().getMimeType(realFullFilePath);

     

      //将文件类型放入值栈

      //两种方式:压入root栈(set),压入map

      ActionContext.getContext().put("contentType", contentType);

     

      //2.获取附件处理方式的相关值,要获取真实文件名

      String realFilename = queryUser.getFilename();

      //获取浏览器的头信息

      String agent = ServletActionContext.getRequest().getHeader("user-agent");

     

      //文件名编码的问题:如果中文,可能乱码,需要编码

      String encodeFilename = cn.itcast.utils.FileUtils.encodeDownloadFilename(realFilename, agent);  

      //处理方式字符串

      String contentDisposition="attachment;filename="+encodeFilename;

      //将附件处理方式放入值栈

      ActionContext.getContext().put("contentDisposition", contentDisposition);

     

      //必须返回到stream结果集类型的视图

      return "downfile";

     

   }

  

   //action中增加一个getter方法

   //意味着什么?inputStream属性放入值栈,因为action在值栈:getter方法就是属性方法

   public InputStream getInputStream() throws Exception{

      //先获取路径

      UserService userService= new UserService();

      User queryUser=userService.findUserById(user.getUserID());

      String realFullFilePath=SystemConstant.BASE_FILE_PATH+ queryUser.getPath();

      return new FileInputStream(new File(realFullFilePath));

   }

 

Strut.xml

 

第二种方式参考:

页面修改

 

struts.xml:

action:

 

 

优化:

 

问题1:旧文件名(用户原来上传时的)可能是中文名称,那么你这个里a连接是get请求,会出现乱码问题。

怎么解决。全局过滤器。

使用以前的过滤器工具:

 

web.xml:  (要求在struts过滤器之前)

 

2.输入文件流的多种提供方式

Struts.xml

编码工具类;

public class FileUtils {
    /**
     * 下载文件时,针对不同浏览器,进行附件名的编码
     * 
     * @param filename
     *            下载文件名
     * @param agent
     *            客户端浏览器
     * @return 编码后的下载附件名
     * @throws IOException
     */
    public static String encodeDownloadFilename(String filename, String agent)
            throws IOException {
        if (agent.contains("Firefox")) { // 火狐浏览器
            filename = "=?UTF-8?B?"
                    + new BASE64Encoder().encode(filename.getBytes("utf-8"))
                    + "?=";
            filename = filename.replaceAll("\r\n", "");
        } else { // IE及其他浏览器
            filename = URLEncoder.encode(filename, "utf-8");
            filename = filename.replace("+", " ");
        }
        return filename;
    }
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值