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

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

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

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

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

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

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

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

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

 package com.lcw.struts2.dowload;

 import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder; import org.apache.struts2.ServletActionContext; import sun.misc.BASE64Encoder; import com.opensymphony.xwork2.ActionSupport;
/**
* 对于客户端来说它需要下载接收一个文件,也就是说它需要一个输入流
* 对于服务端来说它需要对外提供一个下载的服务,也就是说它需要一个输出流
*/ public class DowloadAction extends ActionSupport { private String filename;//下载页面传递了该参数,需提供setter方法接收 public void setFilename(String filename) {
//由于是get方式传递的,中文会出现乱码,不能直接获取,需转码
try {
this.filename = new String(filename.getBytes("ISO-8859-1"),"utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
} public String execute(){
System.out.println("正在下载文件:"+filename);
return SUCCESS;
} //为客户端提供输入流
public InputStream getInputStream() throws FileNotFoundException{
String srcFile=ServletActionContext.getServletContext().getRealPath("/download")+"/"+filename;
File file=new File(srcFile);//得到一个file对象
return new FileInputStream(file);//返回一个文件输入流
} //根据不同的文件动态给出MIME文件类型
public String getContentType(){
//在Tomcat Conf里的web.xml有对应的映射文件
return ServletActionContext.getServletContext().getMimeType(filename);
} //返回一个文件名
public String getFilename() throws IOException{
String agent=ServletActionContext.getRequest().getHeader("user-agent");//根据http头信息获取对应的浏览器类型
return encodeDownloadFilename(filename,agent);
} //下载附件名乱码问题 , IE和火狐 解决不同 IE默认是Url编码 火狐默认是base64编码
public String encodeDownloadFilename(String filename, String agent)
throws IOException {
if (agent.contains("Firefox")) { // 火狐浏览器
filename = "=?UTF-8?B?"
+ new BASE64Encoder().encode(filename.getBytes("utf-8"))
+ "?=";
} else { // IE及其他浏览器
filename = URLEncoder.encode(filename, "utf-8");
}
return filename;
}
}

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

首先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表达式取出,就可以根据我们要下载的文件,动态给出所需参数了,没有设置的参数就意味着保持默认值。

 <?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.devMode" value="true" /> <!-- 全局国际化配置 -->
<constant name="struts.custom.i18n.resources" value="messages"></constant> <package name="struts2test" extends="struts-default">
<action name="download" class="com.lcw.struts2.dowload.DowloadAction">
<result type="stream">
<!-- 一个流二个头 -->
<!-- ognl表达式,动态给出不同下载文件相相对应的MIME协议规定的类型 比如:text/html-->
<!-- 在Action里给出getContentType压栈 -->
<param name="contentType">${contentType}</param>
<!-- 下载文件打开方式 inline浏览器内部打开, attachment 以附件形式打开 -->
<!-- 在Action里动态返回文件名 getFilename -->
<param name="contentDisposition">attachment;filename=${filename}</param>
</result>
</action>
</package> </struts>

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

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

关于Struts2的文件下载的更多相关文章

  1. 基于 Struts2 的文件下载

    介于上篇我们讲述了基于 Struts2 的单文件和多文件上传,这篇我们来聊一聊基于 Struts2 的文件下载. 1.导 jar 包 commons-io-2.0.1.jar struts2-core ...

  2. Struts2笔记--文件下载

    Struts2提供了stream结果类型,该结果类型是专门用于支持文件下载功能的.配置stream类型的结果需要指定以下4个属性. contentType:指定被下载文件的文件类型 inputName ...

  3. Struts2 多文件下载

    Step1:导入支持jar包 commons-fileupload-1.3.1.jar commons-io-2.4.jar jstl-1.2.jar standard-1.1.2.jar commo ...

  4. Struts2实现文件下载

    实现文件下载: 1.导包:commons-fileload-xx.jar commons-io-xx.jar 2.jsp页面: <s:iterator value="#session. ...

  5. Struts2中文件下载

    在struts.xml中配置如下 <action name="download" class="cn.itcast.domain.User" method ...

  6. struts2 实现文件下载方法汇总

    http://pengranxiang.iteye.com/blog/259401 一.通过struts2提供的下载机制下载文件: 项目名为 struts2hello ,所使用的开发环境是MyEcli ...

  7. 使用struts2进行文件下载以及下载权限控制的例子

    本测试有两个模块,一个是文件上上传,一个是文件下载,文件下载的时候会检查是否足有权限,如果没有,就会转发到登录页面,如果有权限,就会直接启动下载程序,给浏览器一个输出流. 下面直接上我的代码: 登录表 ...

  8. java之struts2之文件下载

    1.在实际应用开发中,文件下载功能也非常常见. 2.最简单的文件下载方式是通过超链接来进行文件下载: <body> <a href="download/s.txt" ...

  9. java struts2 的 文件下载

    jsp: <%@ page language="java" contentType="text/html; charset=UTF-8" pageEnco ...

随机推荐

  1. WPF学习笔记(2)——动画效果按钮变长

    说明(2017-6-12 11:26:48): 1. 视频教程里是把一个按钮点击一下,慢慢变长: 注意几个方面: (1)RoutedEvent="Button.Click",这里面 ...

  2. VC/Wince 实现仿Win8 Metro风格界面2——页面滑动切换(附效果图)

    前几天开始写仿Win8 Metro界面文章,部分网友觉得不错,感谢各位的意见.本来今天一直在折腾Android VLC播放器,没时间写.不过明天休息,所以今天就抽时间先写一下. 言归正传,我们都知道W ...

  3. mysql行转列转换

    http://blog.csdn.net/sinat_27406925/article/details/77507478 mysql 行列转换 ,在项目中应用的极其频繁,尤其是一些金融项目里的报表.其 ...

  4. iOS中 语音识别功能/语音转文字教程具体解释 韩俊强的博客

    原文地址:http://blog.csdn.net/qq_31810357/article/details/51111702 前言:近期研究了一下语音识别,从百度语音识别到讯飞语音识别:首先说一下个人 ...

  5. 【WPF/C#】图层筛选/拾取——Color Picker

    文章标题实在不懂怎么表述才清楚. 描述问题:多个图片(图层)重叠时,如何通过鼠标点击来拾取到相应的图层.因为图层中会有很多空白的地方(比如图片四周),要求是获取鼠标点击位置的像素颜色值,如果为空白时或 ...

  6. 删除json对象中空值

    function deleteEmptyProperty(obj){ var object = obj; for (var i in object) { var value = object[i]; ...

  7. matlab std函数 用法及实例

    MATLAB常常用到std函数来进行标准差计算,下面我就通过实例介绍一下 matlab std函数怎么用. 1. std函数是用来计算标准偏差的一个函数,由于其有不同的参数,我们就用下面的例子进行介绍 ...

  8. android 代码混淆模板

    #指定代码的压缩级别 -optimizationpasses #包明不混合大小写 -dontusemixedcaseclassnames #不去忽略非公共的库类 -dontskipnonpublicl ...

  9. JS复制内容到剪贴板(兼容FF/Chrome/Safari所有浏览器)

    现在浏览器种类也越来越多,诸如 IE.Firefox.Chrome.Safari等等,因此现在要实现一个js复制内容到剪贴板的小功能就不是一件那么容易的事了. 在FLASH 9 时代,有一个通杀所有浏 ...

  10. [hadoop读书笔记] 第四章 Hadoop I/O操作

    P92 压缩 P102 序列化 序列化:将结构化对象转为字节流便于在网上传输或写到磁盘进行永久性存储的过程 用于进程之间的通信或者数据的永久存储 反序列化:将字节流转为结构化对象的逆过程 Hadoop ...