Struts2文件下载(全)
利用Struts2来处理文件的下载的问题时,能够解决下载文件的文件名为中英文等,都不出现乱码。此外,还能够在用户下载之前进行检查,判断用户是否有足够的权限来下载该文件等。下面用一个示例来讲解文件的下载:
注意:在处理文件时候尽量不使用特殊字符,路径和文件夹使用英文,文件名可以使用中文、空格、括号,不使用+、¥、%等特殊字符,这个在文件的上传(源头)时候就进行限制,避免在代码中进行处理这些特殊字符
(1) 先写一个下载页面:(index.jsp)
<%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>下载页面</title>
<script type="text/javascript">
//超链接的单击事件,对参数编码(文件名中文或英文)
function downloadFile(filename){
//对文件名编码 避免浏览器中文乱码(后台接收参数时候避免乱码)
var name = encodeURI(encodeURI(filename));
window.location.href = "downLoad.action?downPath=" + name;
}
</script>
</head>
<body>
<h3>1.Struts2多文件文件下载(超链接中有固定的文件名,后台指定路径)</h3>
请下载中文课件:
<a href="javascript:void(0)" onclick="downloadFile('第一章节.docx')">中</a>
<br><br>
请下载英文课件:
<a href="javascript:void(0)" onclick="downloadFile('chapter01.docx')">英</a>
</body>
</html>
在该页面中对文件名进行了编码,避免IE中文乱码,在后台解码即可得到相应参数
(2)在Struts2框架文件下载Action类中,需要提供一个返回InputStream流方法,该输入流代表了被下载文件的入口。该Action类代码如下所示:(DownLoadAction.java)
package cn.tedu.action;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import org.apache.struts2.ServletActionContext;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import cn.tedu.util.MyUtil;
import cn.tedu.web.BaseAction;
@Controller
@Scope("prototype")
public class DownLoadAction extends BaseAction{
private String downPath; // 下载时的文件名
private String contentType; // 保存文件类型
private String filename; // 保存时的文件名
public String getDownPath() {
return downPath;
}
//做了些细微调整
public void setDownPath(String downPath) {
this.downPath = downPath;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
//提供struts配置文件使用
private InputStream inputStream;
public InputStream getInputStream() {
return inputStream;
}
public void setInputStream(InputStream inputStream) {
this.inputStream = inputStream;
}
//下载时候调用
public String downloadFile() throws UnsupportedEncodingException{
// 下载保存时的文件名和被下载的文件名一样
downPath = java.net.URLDecoder.decode(downPath,"UTF-8");
filename = downPath;
// 下载的文件路径,请在webapps目录下创建down目录,并预先放置好两个文件备用
//downPath = "download/" + downPath;
System.out.println("filename:"+filename);
HttpServletRequest request = ServletActionContext.getRequest();
String tomcatPath = MyUtil.getTomcatPath(request);// E:\apache-tomcat-7.0.81\down
inputStream = new FileInputStream(new File(tomcatPath +File.separator + filename));
//inputStream = ServletActionContext.getServletContext().getResourceAsStream(downPath);
System.out.println(inputStream);//若传过来的参数乱码,则inputStream为null
// 保存文件的类型
contentType = "application/x-msdownload";
//对下载的文件名按照UTF-8进行编码,解决下载窗口中的中文乱码问题
filename = MyUtil.toUTF8String(filename);
System.out.println(filename);
System.out.println("=============结束============");
return SUCCESS;
}
}
(3) 在上述的Action类中定义了一个工具类MyUtil,该类中有一个静态方法toUTF8String实现对下载的文件名按照UTF-8进行编码,解决下载窗口中中文乱码的问题:(MyUtil.java)
package cn.tedu.util;
import java.io.UnsupportedEncodingException;
public class MyUtil {
// 对下载文件按照 UTF-8 进行编码
public static String toUTF8String(String str){
StringBuffer sb = new StringBuffer();
int len = str.length();
for (int i = 0; i < len; i++)
{
// 取出字符中的每个字符
char c = str.charAt(i);
// Unicode码值在0~255之间,不做处理
if(c>=0 && c <= 255){
sb.append(c);
}else {
// 转换 UTF-8 编码
byte b[];
try{
b = Character.toString(c).getBytes("UTF-8");
}catch(UnsupportedEncodingException e){
e.printStackTrace();
b = null;
}
// 转换为%HH的字符串形式
for(int j = 0;j < b.length ; j++){
int k = b[j];
if(k < 0){
k &= 255;
}
sb.append("%" + Integer.toHexString(k).toUpperCase());
}
}
}
return sb.toString();
}
}
(4) 最后,完成Action的配置,关键是要配置一个类型为stream的结果,配置时需要指定如下四个属性:
- contentType: 指定被下载文件的文件类型;
- inputName: 指定被下载文件的入口输入流;
- contentDisposition: 指定下载的文件名;
- bufferSize: 指定下载文件时的缓冲大小。
struts.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
".5.dtd">
<struts>
<!--指定国际化资源文件(下一章会讲到)-->
<constant name="struts.custom.i18n.resources" value="messageResource"/>
<!--设置Struts应用的解码集 指定Web应用的默认编码集,相当于调用HttpServletRequest的setCharacterEncoding方法 -->
<constant name="struts.i18n.encoding" value="utf-8"/>
<!-- 上传文件的总大小(可能上传多个)该属性指定Struts 2文件上传中整个请求内容允许的最大字节数
而拦截器中配置的是限制单个上传文件的大小-->
<constant name="struts.multipart.maxSize" value="1000000000"/>
<package namespace="/" name="default" extends="struts-default">
<!-- 下载功能 -->
<action name="wq2">
<result>/index.jsp</result>
</action>
<action name="downLoad" class="downLoadAction" method="downloadFile">
<result name="success" type="stream">
<!-- 指定文件类型 -->
<param name="contentType">${contentType}</param>
<!--默认就是inputStream,它将会指示StreamResult通过
inputName属性值的getter和setter方法,如这里就是
getInputStream()来获取下载文件的内容,意味着Action要有这个方法
-->
<param name="inputName">inputStream</param>
<!--默认为inline(在线打开),设置为attachment将会告诉浏览器下载
该文件,filename指定下载文件时的文件名,若未指定将会以浏览器
页面名作为文件名,如:以download.action作为文件名
-->
<param name="contentDisposition">attachment;filename=${filename}</param>
<!--指定下载文件的缓冲大小-->
<param name="bufferSize">4096</param>
</result>
</action>
</package>
</struts>
总结:以上代码在谷歌和IE中均测试通过,兼容浏览器
在实际中,可能是在某路径的文件夹下,将该文件夹下的文件以列表显示,单击下载,与上述多文件下载类似,代码在之前上添加即可,代码改动如下:
index.jsp页面:
<%@page import="java.net.URLEncoder"%>
<%@ page import="cn.tedu.util.MyUtil"%>
<%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>下载页面(在入口处限制文件名中不能含有特殊字符例如“+”号)</title>
<%
String tomcatPath = MyUtil.getTomcatPath(request);
tomcatPath = URLEncoder.encode(tomcatPath, "UTF-8");//先编码
//System.out.println(tomcatPath);//E:\apache-tomcat-7.0.81\down
%>
<style>
/*内容th td样式*/
#file_Thead td,#file_Tbody td{ border:1px solid #CCC;padding:2px 0 2px 5px}
</style>
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript">
//超链接的单击事件,对参数编码(文件名中文或英文)
function downloadFile(filename){
//对文件名编码 避免浏览器中文乱码(后台接收参数时候避免乱码)
var name = encodeURI(encodeURI(filename));
window.location.href = "downLoad.action?downPath=" + name;
}
//列表显示可下载文件(记得引入jQuery)
$(function(){
//页面加载完毕后生成下载文件的列表(ajax查询)
findFiles();
//点击下载按钮时候调用
$("#file_Tbody").on("click",".bt2",function(){
var filePath = $(this).data("filePath"); //要下载文件的路径(已经编码)
var fileName = $(this).data("fileName"); //要下载文件名
//对文件名编码 避免浏览器中文乱码(后台接收参数时候避免乱码)
window.location.href = "btnDown.action?filePath=" + filePath + "&fileName=" + fileName;
});
});
//页面加载完毕后自动调用
function findFiles(){
$.ajax({
type:"post",
url:"findFiles.action",
//此处对路径进行编码,后台进行解码即可 传入参数,文件夹位置E:\apache-tomcat-7.0.81\down
data:{path: '<%=tomcatPath%>'},
dataType:"json",
success:function(result){
var fileNames = result.names;//获取names属性(该属性是一个字符串集合,包含了文件名)
for(var i=0;i<fileNames.length;i++){//fileNames[i] 每一个文件名
var tr = "<tr>" +
"<td>" + fileNames[i] + "</td>" + //显示文件名
"<td>" +
"<input type='button' class='bt2' value='下载' >"+//操作按钮
"</td>" +
"</tr>";
var $tr = $(tr);
$("#file_Tbody").append($tr);
//绑定路径和文件名
$("#file_Tbody tr:last").find("input").data("filePath","<%=tomcatPath%>"); //已经编码好的路径
$("#file_Tbody tr:last").find("input").data("fileName",encodeURI(encodeURI(fileNames[i])));//对文件名编码
}
}
});
}
</script>
</head>
<body>
<h3>1.Struts2多文件文件下载(超链接中有固定的文件名,后台指定路径)</h3>
请下载中文课件:
<a href="javascript:void(0)" onclick="downloadFile('第一章节.docx')">中</a>
<br><br>
请下载英文课件:
<a href="javascript:void(0)" onclick="downloadFile('chapter01.docx')">英</a>
<h3>2.Struts2多文件文件下载(列表显示可下载文件)</h3>
<table style="table-layout:fixed;width:50%;border:1px solid #CCC;border-collapse:collapse;margin:10px auto;">
<thead id="file_Thead">
<tr style="background-color: #EEE9E9">
<td>文件名</td>
<td style="width:100px;">操作</td>
</tr>
</thead>
<tbody id="file_Tbody"></tbody>
</table>
</body>
</html>
点击下载时候发送GET请求,将路径和文件名都进行了编码,后台中分别进行解码
struts.xml文件添加如下代码:
<!-- 对指定文件夹下载文件显示,自由下载 -->
<action name="findFiles" class="downLoadAction" method="findFilesByDir">
<result name="success" type="json">
<!-- ie中避免出现下载 -->
<param name="contentType">text/html</param>
</result>
</action>
<action name="btnDown" class="downLoadAction" method="btnDownFile">
<result name="success" type="stream">
<param name="contentType">${contentType}</param>
<param name="inputName">inputStream</param>
<param name="contentDisposition">attachment;filename=${fileName}</param>
<param name="bufferSize">4096</param>
</result>
</action>
Action控制器如下:
package cn.tedu.action;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import org.apache.struts2.ServletActionContext;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import cn.tedu.util.MyUtil;
import cn.tedu.web.BaseAction;
@Controller
@Scope("prototype")
public class DownLoadAction extends BaseAction{
private String downPath; // 下载时的文件名
private String contentType; // 保存文件类型
private String filename; // 保存时的文件名
public String getDownPath() {
return downPath;
}
//做了些细微调整
public void setDownPath(String downPath) {
this.downPath = downPath;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
//提供struts配置文件使用
private InputStream inputStream;
public InputStream getInputStream() {
return inputStream;
}
public void setInputStream(InputStream inputStream) {
this.inputStream = inputStream;
}
//下载时候调用
public String downloadFile() throws UnsupportedEncodingException{
// 下载保存时的文件名和被下载的文件名一样
downPath = java.net.URLDecoder.decode(downPath,"UTF-8");
filename = downPath;
// 下载的文件路径,请在webapps目录下创建download目录,并预先放置好两个文件备用
downPath = "download/" + downPath;
System.out.println("downPath:"+downPath);
System.out.println("filename:"+filename);
inputStream = ServletActionContext.getServletContext().getResourceAsStream(downPath);
System.out.println(inputStream);//若传过来的参数乱码,则inputStream为null
// 保存文件的类型
contentType = "application/x-msdownload";
//对下载的文件名按照UTF-8进行编码,解决下载窗口中的中文乱码问题
filename = MyUtil.toUTF8String(filename);
System.out.println(filename);
System.out.println("=============结束============");
return SUCCESS;
}
private String path;//查找文件夹的路径,由jsp页面传递过来
private List<String> names;//返回查询出的文件名
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public List<String> getNames() {
return names;
}
public void setNames(List<String> names) {
this.names = names;
}
//查找文件列表
public String findFilesByDir() throws UnsupportedEncodingException{
//由于jsp对改路径进行了编码,此处要进行解码
path = java.net.URLDecoder.decode(path,"UTF-8");
//System.out.println("解码后路径:"+path);//E:\apache-tomcat-7.0.81\down
names= new ArrayList<String>();
File file = new File(path);
if(file.isDirectory()){//是文件夹
File[] listFiles = file.listFiles();
for(int i=0;i<listFiles.length;i++){
names.add(listFiles[i].getName());
}
}
//System.out.println(names);
return SUCCESS;
}
//列表下载时候使用,inputStream公用
private String filePath;
private String fileName;
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
//下载文件(在文件入口限制文件名中的特殊字符)
public String btnDownFile() throws UnsupportedEncodingException, FileNotFoundException{
// 下载保存时的文件名和被下载的文件名一样
filePath = java.net.URLDecoder.decode(filePath,"UTF-8");
fileName = java.net.URLDecoder.decode(fileName,"UTF-8");
// 下载的文件路径,E:\apache-tomcat-7.0.81\down + 文件名称
String finPath = filePath + File.separator + fileName;//下载路径
System.out.println("下载路径:"+finPath);
inputStream = new FileInputStream(new File(finPath));
// 保存文件的类型
contentType = "application/x-msdownload";
//对下载的文件名按照UTF-8进行编码,解决下载窗口中的中文乱码问题
fileName = MyUtil.toUTF8String(fileName);
System.out.println("=============结束============");
return SUCCESS;
}
}
页面显示列表如下:
点击下载按钮即可弹框下载
注意:这个案例是先在指定文件夹查询文件显示列表,然后单击按钮下载,需要存在该文件夹,案例中的文件夹路径为:
E:\apache-tomcat-7.0.81\down
补充文档 BaseAction.java如下
package cn.tedu.web;
import java.util.Map;
import org.apache.struts2.interceptor.ApplicationAware;
import org.apache.struts2.interceptor.RequestAware;
import org.apache.struts2.interceptor.SessionAware;
import com.opensymphony.xwork2.ActionSupport;
/**
* 该抽象类 是所有控制器的基类,用于封装常用的session、request等,这样用于提供给子类复用
* ActionSupport 是 Struts2 提供的Action基础类,用于复用公共代码
* 例如:常量 SUCCESS = "success" LOGIN = "login" ERROR = "error 等等
*/
public abstract class BaseAction extends ActionSupport implements SessionAware, ApplicationAware, RequestAware{
//这三个属性均与Web无关,可单独访问
protected Map<String, Object> session;
protected Map<String, Object> application;
protected Map<String, Object> request;
//来源于SessionAware
public void setSession(Map<String, Object> session) {
this.session = session;
}
//来源于ApplicationAware
public void setApplication(Map<String, Object> application) {
this.application = application;
}
public void setRequest(Map<String, Object> request) {
this.request = request;
}
}