• 关于Struts2的文件下载


    首先先来说下关于文件下载的原理:

    服务端为客户端提供了一个下载服务,所以服务端需要一个输出流(把客户请求下载的文件输出),相对于服务端来说,客户端需要下载接收一个文件,所以它需要一个输入流(接收文件)。

    服务器读取要下载文件的内容,用一个Response响应流写回并设置HTTP头信息ContentType(文件类型)、 ContentDisposition(以什么方式打开)

    下面给出一个小Demo,具体代码具体分析吧

    1、首先是提供下载的页面:download.jsp

    给出超链接到Action并用Get方式传递一个文件名进行属性注入

     1 <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
     2 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
     3 <html>
     4 <head>
     5 <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
     6 <title>下载文件示例</title>
     7 </head>
     8 <body>
     9 <h2>下载文件</h2>
    10 <a href="download.action?filename=照片文件.jpg">点击下载照片文件</a>
    11 <a href="download.action?filename=admin.rar">点击下载压缩包文件</a>
    12 <a href="download.action?filename=总结.txt">点击下载文本文件</a>
    13 </body>
    14 </html>

    2、处理下载文件的Action:DowloadAction.java

    这里提供了一个成员变量属性来接收页面传递过来的文件名,由于文件名是以Get方式传递过来的,中文会出现乱码问题,所以在setter方法里需要做一些处理,也就是重新编码。

     1 package com.lcw.struts2.dowload;
     2 
     3 import java.io.File;
     4 import java.io.FileInputStream;
     5 import java.io.FileNotFoundException;
     6 import java.io.IOException;
     7 import java.io.InputStream;
     8 import java.io.UnsupportedEncodingException;
     9 import java.net.URLEncoder;
    10 
    11 import org.apache.struts2.ServletActionContext;
    12 
    13 import sun.misc.BASE64Encoder;
    14 
    15 import com.opensymphony.xwork2.ActionSupport;
    16 /**
    17  * 对于客户端来说它需要下载接收一个文件,也就是说它需要一个输入流
    18  * 对于服务端来说它需要对外提供一个下载的服务,也就是说它需要一个输出流
    19  */
    20 
    21 public class DowloadAction extends ActionSupport {
    22 
    23     private String filename;//下载页面传递了该参数,需提供setter方法接收
    24 
    25     public void setFilename(String filename) {
    26         //由于是get方式传递的,中文会出现乱码,不能直接获取,需转码
    27         try {
    28             this.filename = new String(filename.getBytes("ISO-8859-1"),"utf-8");
    29         } catch (UnsupportedEncodingException e) {
    30             e.printStackTrace();
    31         }
    32     }
    33     
    34     public String execute(){
    35         System.out.println("正在下载文件:"+filename);
    36         return SUCCESS;
    37     }
    38     
    39     //为客户端提供输入流
    40     public InputStream getInputStream() throws FileNotFoundException{
    41         String srcFile=ServletActionContext.getServletContext().getRealPath("/download")+"/"+filename;
    42         File file=new File(srcFile);//得到一个file对象
    43         return new FileInputStream(file);//返回一个文件输入流
    44     }
    45     
    46     //根据不同的文件动态给出MIME文件类型
    47     public String getContentType(){
    48         //在Tomcat Conf里的web.xml有对应的映射文件
    49         return ServletActionContext.getServletContext().getMimeType(filename);
    50     }
    51     
    52     //返回一个文件名
    53     public String getFilename() throws IOException{
    54         String agent=ServletActionContext.getRequest().getHeader("user-agent");//根据http头信息获取对应的浏览器类型
    55         return encodeDownloadFilename(filename,agent);
    56     }
    57     
    58     
    59     //下载附件名乱码问题 , IE和火狐 解决不同   IE默认是Url编码 火狐默认是base64编码
    60     public String encodeDownloadFilename(String filename, String agent)
    61             throws IOException {
    62         if (agent.contains("Firefox")) { // 火狐浏览器
    63             filename = "=?UTF-8?B?"
    64                     + new BASE64Encoder().encode(filename.getBytes("utf-8"))
    65                     + "?=";
    66         } else { // IE及其他浏览器
    67             filename = URLEncoder.encode(filename, "utf-8");
    68         }
    69         return filename;
    70     }
    71 }

    看了上面的代码,如果不清楚这块知识点的朋友可能会有点蒙,别急,下面我来解析下这段代码是怎么来的

    首先Struts2的文件下载是通过一个结果集stream来完成的,在Struts2核心包里的struts-default.xml里我们可以找到这样的一句话:

    <result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/>

    我们来看下这个类(org.apache.struts2.dispatcher.StreamResult)里面有什么,Ctrl+Shift+T关联下源代码

    这个类里面给出了很多参数,因为都有默认值,所以我们不需要全部到去改动它,只需要改变我们需要的地方就可以了。

    这里来解释下上面画红色框的参数内容:contentType,contentDisposition,inputName

    contetType:是下载文件对应的MIME协议类型,比如:text/html,text/plain等,这个参数我们不能写死,因为我们的下载文件的类型有很多,有时是图片,有时是文档等。

    contentDisposition:是下载文件的打开方式,这里默认是inline也就是内联在浏览器打开,如果不想关联浏览器我们可以把它设置成attment以附件的形式打开。

    inputNmae:这是定义一个返回流(客户端需要的输入流)的名称,属性值为inputStream。

    所以我们需要在Action里面提供这些东西,利用JAVA的反射机制让Struts2的配置文件(压入值栈,并给出getter方法)读取到就行了。

    这里我们的下载附件名依旧会乱码,因为IE等浏览器默认的编码是URL而火狐浏览器默认的编码是BASE64,我们需要在这里判断客户端使用的是什么浏览器,这个很简单,只需要得到客户端的HTTP头信息Agment就行了,具体代码在上面encodeDownloadFilename方法里以给出,拿来用便是了。

    3、再来看下配置文件struts.xml的配置:

    由于Action里已给出我们所需参数的getter方法,我们在这边这需要用Ognl表达式取出,就可以根据我们要下载的文件,动态给出所需参数了,没有设置的参数就意味着保持默认值。

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <!DOCTYPE struts PUBLIC
     3     "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
     4     "http://struts.apache.org/dtds/struts-2.0.dtd">
     5 <struts>
     6     <constant name="struts.devMode" value="true" />
     7     
     8     <!-- 全局国际化配置 -->
     9     <constant name="struts.custom.i18n.resources" value="messages"></constant>
    10 
    11     <package name="struts2test" extends="struts-default">
    12         <action name="download" class="com.lcw.struts2.dowload.DowloadAction">
    13             <result type="stream">
    14                 <!-- 一个流二个头 -->
    15                 <!-- ognl表达式,动态给出不同下载文件相相对应的MIME协议规定的类型 比如:text/html-->
    16                 <!-- 在Action里给出getContentType压栈 -->
    17                     <param name="contentType">${contentType}</param>
    18                 <!-- 下载文件打开方式 inline浏览器内部打开, attachment 以附件形式打开 -->
    19                 <!-- 在Action里动态返回文件名 getFilename -->
    20                     <param name="contentDisposition">attachment;filename=${filename}</param>
    21             </result>
    22         </action>
    23     </package>
    24 
    25 </struts>

    然后我们新建一个文件夹download,把要下载的文件和web页面提供的文件名一样放入

    到这里就大功告成了,看下页面效果吧:

  • 相关阅读:
    JavaScript-5(数组)
    JavaScript-作用域-预解析
    JavaScript-日历生成器
    JavaScript-8行5列表格
    package XXX.i386.rpm is not installed(检查在Linux上安装Oracle所需的pkg时)
    ubuntu13.04下安装jdk7
    Linux远程传输命令之scp使用方法
    Mac OS X中MacPorts安装和使用
    第一天 Linux 是什么
    Javascript与当前项目的思考
  • 原文地址:https://www.cnblogs.com/lichenwei/p/3929339.html
Copyright © 2020-2023  润新知