最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Struts2文件下载(全)

旗下网站admin438浏览0评论

Struts2文件下载(全)

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;
	}

}

发布评论

评论列表(0)

  1. 暂无评论