struts文件下载机制

Struts2 中使用 type="stream" 的 result 进行下载即可。只用提供一个输入流inputStream,剩下的输出工作struts帮我们做。

例子一:

1.可以为 stream 的 result 设定如下参数

contentType: 结果类型
contentLength: 下载的文件的长度
contentDisposition: 设定 Content-Dispositoin 响应头. 该响应头指定响应是一个文件下载类型, 一般取值为  attachment;filename="document.pdf".
inputName: 指定文件输入流的 getter 定义的那个属性的名字. 默认为 inputStream

这四个一般在getter方法中定义或者在execute方法执行时设置,而且不用声明变量,直接getter方法,第一个字母大写,例如public InputStream getInputStream()

bufferSize: 缓存的大小. 默认为 1024
allowCaching: 是否允许使用缓存
contentCharSet: 指定下载的字符集

这三个参数一般使用默认值或者在xml文件中配置。


以上参数可以在 Action 中以 getter 方法的方式提供,也可以通过配置配置,也可以使用默认值。也可以动态设置值,在execute方法中设置。

 

 1 package FileDownload;
 2 
 3 import java.io.FileInputStream;
 4 import java.io.InputStream;
 5 
 6 import javax.servlet.ServletContext;
 7 
 8 import org.apache.struts2.ServletActionContext;
 9 
10 import com.opensymphony.xwork2.ActionSupport;
11 
12 public class FileDownLoad extends ActionSupport {
13 
14     /**
15      * 
16      */
17     private static final long serialVersionUID = 1L;
18 
19     private String contentType;
20     private long contentLength;
21     private String contentDisposition;
22     private InputStream inputStream;
23     
24     
25     public String getContentType() {
26         return contentType;
27     }
28 
29 
30     public long getContentLength() {
31         return contentLength;
32     }
33 
34 
35 //    在getter方法中设置所需要的参数
36     public String getContentDisposition() {
37         contentDisposition = "attachment;filename=filesUp.html";
38         return contentDisposition;
39     }
40 
41 
42     public InputStream getInputStream() {
43         return inputStream;
44     }
45 
46 
47     @Override
48     public String execute() throws Exception {
49         
50         //确定各个成员变量的值
51         contentType = "text/html";
52         
53         ServletContext servletContext = 
54                 ServletActionContext.getServletContext();
55         String fileName = servletContext.getRealPath("/files/filesUp.html");
56 //        打开输入流
57         inputStream = new FileInputStream(fileName);
58         contentLength = inputStream.available();
59                 
60         
61         return super.execute();
62     }
63 }

上面可以在execute方法执行时动态设置参数,也可以在getter方法中设置参数。

 

 

配置文件

 <!-- 文件下载 -->
        <action name="fileDownload" class="FileDownload.FileDownLoad">
            <result type="stream">
                <!-- 其他的参数在类中设置或者使用默认 -->
                <param name="bufferSize">2048</param>
            </result>
        </action>

 

 例子二:

目录结构:

 

动态将数据写到Excel文件并提供下载:

package cn.xm.exam.action.exam.exam;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.io.FileUtils;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.struts2.ServletActionContext;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;

import com.opensymphony.xwork2.ActionSupport;

import cn.xm.exam.MyElFunction.MyElFunction;
import cn.xm.exam.service.exam.exam.ExamService;
import cn.xm.exam.service.grade.EmployeeExamService;
import jxl.common.Logger;

/**
 * 导出参考人信息 1.查出数据 2.写入Excel 3.打开流,提供下载
 * 
 * @author QiaoLiQiang
 * @time 2017年10月29日下午10:29:51
 */
@Controller
@Scope("prototype")
@SuppressWarnings("all")
public class ExtExamEmployeesAction extends ActionSupport {
    private Logger logger = Logger.getLogger(FindExamAction.class);
    private String fileName;// 导出的Excel名称
    @Resource
    private ExamService examService;// 考试service
    @Resource
    private EmployeeExamService employeeExamService;// 员工成绩service

    // 1.查数据
    private String examId;// 考试ID(用于查询考试员工)

    public List<Map<String, Object>> findExamEmployeeByExamId() {
        List<Map<String, Object>> employees = null;
        try {
            employees = employeeExamService.getEmployeeexamsByExamId(examId);
        } catch (SQLException e) {
            logger.error("导出考试人员异常", e);
        }
        return employees;
    }

    // 2.写入Excel
    public boolean writeExamEmployees2Excel(List<Map<String, Object>> examEmployees, String fileName) {
        // 标题
        String[] title = { "序号", "姓名", "身份证号", "性别", "所属部门", "员工类型", "考试方式" };
        // 创建一个工作簿
        HSSFWorkbook workbook = new HSSFWorkbook();
        // 创建一个工作表sheet
        HSSFSheet sheet = workbook.createSheet();
        // 设置列宽
        setColumnWidth(sheet, 7);
        // 创建第一行
        HSSFRow row = sheet.createRow(0);
        // 创建一个单元格
        HSSFCell cell = null;
        // 创建表头
        for (int i = 0; i < title.length; i++) {
            cell = row.createCell(i);
            // 设置样式
            HSSFCellStyle cellStyle = workbook.createCellStyle();
            cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 设置字体居中
            // 设置字体
            HSSFFont font = workbook.createFont();
            font.setFontName("宋体");
            font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);// 字体加粗
            // font.setFontHeight((short)12);
            font.setFontHeightInPoints((short) 13);
            cellStyle.setFont(font);
            cell.setCellStyle(cellStyle);
            cell.setCellValue(title[i]);
        }

        // 写入数据
        // 从第二行开始追加数据
        for (int i = 1; i < (examEmployees.size() + 1); i++) {
            // 创建第i行
            HSSFRow nextRow = sheet.createRow(i);
            // 获取数据
            Map<String, Object> employees = examEmployees.get(i - 1);
            for (int j = 0; j < 7; j++) {
                HSSFCell cell2 = nextRow.createCell(j);
                if (j == 0) {
                    cell2.setCellValue(j + 1);
                }
                if (j == 1) {
                    cell2.setCellValue(employees.get("employeeName").toString());
                }
                if (j == 2) {
                    cell2.setCellValue(employees.get("employeeId").toString());
                }
                if (j == 3) {
                    cell2.setCellValue(MyElFunction.replace(employees.get("sex").toString(), "12", "男女"));
                }
                if (j == 4) {
                    cell2.setCellValue(employees.get("departmentName").toString());
                }
                if (j == 5) {
                    cell2.setCellValue(
                            MyElFunction.replace(employees.get("employeeType").toString(), "01", "内外") + "部员工");
                }
                if (j == 6) {
                    cell2.setCellValue(employees.get("examMethod").toString());
                }
            }
        }

        // 创建一个文件
        File file = new File(fileName);
        // 如果存在就删除
        if (file.exists()) {
            file.delete();
        }
        try {
            file.createNewFile();
            // 打开文件流
            FileOutputStream outputStream = FileUtils.openOutputStream(file);
            workbook.write(outputStream);
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return true;
    }

    // 设置列宽()
    private static void setColumnWidth(HSSFSheet sheet, int colNum) {
        for (int i = 0; i < colNum; i++) {
            int v = 0;
            v = Math.round(Float.parseFloat("15.0") * 37F);
            v = Math.round(Float.parseFloat("20.0") * 267.5F);
            sheet.setColumnWidth(i, v);
        }
    }

    // 3.打开文件的流提供下载
    public InputStream getInputStream() throws Exception {
        this.create();// 创建文件到指定目录下
        String path = ServletActionContext.getServletContext().getRealPath("/files/examEmployeesExcel");
        String filepath = path + "\\" + fileName + ".xls";
        File file = new File(filepath);
        // 只用返回一个输入流
        return FileUtils.openInputStream(file);// 打开文件
    }

    // 产生Excel到文件夹下面
    public void create() {
        // 获取工程下的路径
        String path = ServletActionContext.getServletContext().getRealPath("/files/examEmployeesExcel");
        String filepath = path + "\\" + fileName + ".xls";
        // 获取文件
        List<Map<String, Object>> examEmployees = this.findExamEmployeeByExamId();
        this.writeExamEmployees2Excel(examEmployees, filepath);
    }

    // 文件下载名
    public String getDownloadFileName() {
        String downloadFileName = "";
        String filename = fileName + ".xls";
        try {
            downloadFileName = URLEncoder.encode(filename, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return downloadFileName;
    }

    @Override
    public String execute() throws Exception {
        // 先将名字设为秒数产生唯一的名字
        this.setFileName(String.valueOf(System.currentTimeMillis()));
        return super.execute();
    }

    // get,set方法
    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public String getExamId() {
        return examId;
    }

    public void setExamId(String examId) {
        this.examId = examId;
    }

}

 

 

 配置文件:

        <!-- 导出参考人员信息 -->
        <action name="exportExamEmployees" class="extExamEmployeesAction">
            <result type="stream">
                <!-- 其他的参数在类中设置或者使用默认 -->
                <param name="contentType">application/octet-stream</param>
                <param name="inputName">inputStream</param>
                <param name="contentDisposition">attachment;filename="${downloadFileName}"</param>
                <param name="bufferSize">8192</param>
            </result>
        </action>

 

 ${downloadFileName}会调用getDownloadFileName()方法

 

 例子三:

目录结构:

 

1.前台JS

<script type="text/javascript">
    function down(flag) {
        if (flag == 1) {
            if (confirm("确定下载谷歌浏览器?")) {
                window.location.href = "export_execute.action?name=ChromeStandalone_56.0.2924.87_Setup.exe"
            }
        }
        if (flag == 2) {
            if (confirm("确定下载火狐浏览器?")) {
                window.location.href = "export_execute.action?name=Firefox-57.0.2.6549-setup.exe"
            }
        }
        if (flag == 3) {
            if (confirm("确定下载操作手册?")) {
                window.location.href = "export_execute.action?name=《安全培训管理系统》用户考试操作手册.pdf"
            }
        }
    }
</script>

 

2.后台Action(tomcat编码是UTF-8)

package cn.xm.exam.action.exam.exam;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

import org.apache.struts2.ServletActionContext;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;

import com.opensymphony.xwork2.ActionSupport;

/**
 * 下载专区的下载文件
 * 
 * @author QiaoLiQiang
 * @time 2017年12月14日上午10:06:41
 */
@Controller // 控制层
@Scope("prototype") // 单例模式
@SuppressWarnings("all") // 压制警告
public class ExtDownloadFile extends ActionSupport {
    // 注入服务器目录地址
    private String serverPath;// 注入要下载的文件的地址
    // 接收文件名
    private String name;// struts的属性驱动

    public void setServerPath(String serverPath) {
        this.serverPath = serverPath;
    }

    public String getServerPath() {
        return serverPath;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    // 需要提供给struts写出数据的输入流
    public InputStream getInputStream() {
        try {
            // 转码:解决中文乱码问题
            // 先用ISO8859-1编码 再使用UTF-8解码
            // String filename = new
            // String(name.getBytes("ISO8859-1"),"UTF-8");//中名名称.后缀名
            String filename = name;
            String path = ServletActionContext.getServletContext().getRealPath(serverPath);
            FileInputStream fis = new FileInputStream(new File(path + "\\" + filename));// 服务器目录地址+文件名
            name = new String(name.getBytes("UTF-8"), "ISO8859-1");
            return fis;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException();
        }

    }

    // 下载方法
    public String execute() {
        return SUCCESS;
    }
}

 

3.配置:

        <!-- 下载专区的文件下载 -->
        <action name="export_*" class="extDownloadFile">
            <!-- 为setServerPath方法中的serverPath属性注入值 也就是文件存放的地址/目录(文件应该从哪里下载) -->
            <param name="serverPath">/files/downloadFiles</param>
            <!-- 文件下载的关键:视图类型一定是stream -->
            <result type="stream">
                <!-- 往StreamResult类中的属性注入内容 -->
                <!-- 返回给浏览器的文件类型。返回通用的二进制 -->
                <param name="contentType">application/octet-stream</param>
                <!-- 返回给浏览器的输入流 -->
                <!-- 默认就是 inputStream,它将会指示 StreamResult 通过 inputName 属性值的 getter 方法, 
                    比如这里就是 getInputStream() 来获取下载文件的内容,意味着你的 Action 要有这个方法 -->
                <param name="inputName">inputStream</param>
                <!-- 告诉浏览器的方式下载资源 ${name}:获取Action中getName()方法的数据 -->
                <!-- 默认为 inline(在线打开),设置为 attachment 将会告诉浏览器下载该文件,filename 指定下载文 件保存的文件名,若未指定将会是以浏览的页面名作为文件名,如以 
                    download.action 作为文件名, 这里使用的是动态文件名,${name}, 它将通过 Action 的 getName() 获得文件名 -->
                <param name="contentDisposition">attachment;filename=${name}</param>
                <!-- 缓存大小 -->
                <param name="bufferSize">1024</param>
            </result>
        </action>

 

posted @ 2017-07-15 18:58  QiaoZhi  阅读(451)  评论(0编辑  收藏  举报