在线实时生成excel文件下载
我正在的一个项目,需要实现在线实时生成 Excel文件供客户端下载的需求,最初考虑的是先在服务器端生成真实的文件,然后在客户端下载该文件。后来发现这样做不但性能不够好、速度较慢,而且还 要占用服务器空间。所以找到网上的例子采取了在服务器端生成文件输出流(ServletOutputStream),通过HttpServletResponse对象设 置相应的响应头,然后将此输出流传往客户端的方法实现。在实现过程中,用到了Apache组织的Jakarta开源组件POI,不过因为是用到webwork框架,而需求是大画面的其中一个按钮,目前只能考虑jsp来写画面,出现了输出流和jsp页面打开流出现冲突抛出异常。暂时的解决方法是return null,使它只是警告而不抛出异常。
一、首先,根据Excel表的特点,我编写了一个Excel表模型类ExcelModel,代码如下:
java 代码
二、编写一个下载接口ExcelDownLoad,定义基本的方法:
java 代码
- import java.io.IOException;
- import java.util.List;
-
- import javax.servlet.http.HttpServletResponse;
-
- /**
- * 初始化要生成的Excel的表模型
- *
- * @param list List 填充了 Excel表格数据的集合
- * @param form ActionForm及其子类
- * @param excel ExcelModel Excel表的对象模型
- * @see ExcelModel
- * @throws Exception
- */
- public interface ExcelDownLoad {
-
- /**
- * 在已文件已存在的情况下,采用读取文件流的方式实现左键点击下载功能
- *
- * @param inPutFileName 读出的文件名
- * @param outPutFileName 保存的文件名
- * @param HttpServletResponse
- * @see HttpServletResponse
- * @throws IOException
- */
- public void downLoad(String inPutFileName, String outPutFileName, HttpServletResponse response) throws IOException;
-
- /**
- * 初始化要生成的Excel的表模型
- *
- * @param list List 填充了 Excel表格数据的集合
- * @param form ActionForm及其子类
- * @param excel ExcelModel Excel表的对象模型
- * @see ExcelModel
- * @throws Exception
- */
- public ExcelModel createDownLoadExcel(List list, ExcelModel excel) throws Exception;
-
- /**
- * 在已文件不存在的情况下,采用生成输出流的方式实现左键点击下载功能。
- *
- * @param outPutFileName 保存的文件名
- * @param out ServletOutputStream对象
- * @param downExcel 填充了数据的ExcelModel
- * @param HttpServletResponse
- * @see HttpServletResponse
- * @throws Exception
- */
- public void downLoad(String outPutFileName, ExcelModel downExcel, HttpServletResponse response) throws Exception;
-
- }
三 公共基类BaseExcelDownLoad,并提供downLoad()方法的公共实现
java 代码
- public abstract class BaseExcelDownLoad implements ExcelDownLoad {
-
- /**
- * 初始化要生成的Excel的表模型
- *
- * @param list List 填充了 Excel表格数据的集合
- * @param form ActionForm及其子类
- * @param excel ExcelModel Excel表的对象模型
- * @see ExcelModel
- * @throws Exception
- */
- public abstract ExcelModel createDownLoadExcel(List list, ExcelModel excel) throws Exception;
-
- /**
- * 在已文件已存在的情况下,采用读取文件流的方式实现左键点击下载功能
- *
- * @param inPutFileName 读出的文件名
- * @param outPutFileName 保存的文件名
- * @param HttpServletResponse
- * @see HttpServletResponse
- * @throws IOException
- */
- public void downLoad(String inPutFileName, String outPutFileName, HttpServletResponse response) throws IOException {
-
- // 打开指定文件的流信息
- InputStream is = new FileInputStream(inPutFileName);
- // 写出流信息
- int data = -1;
- OutputStream outputstream = response.getOutputStream();
-
- // 清空输出流
- response.reset();
- // 设置响应头和下载保存的文件名
- response.setHeader("content-disposition", "attachment;filename=" + outPutFileName);
- // 定义输出类型
- response.setContentType("APPLICATION/msexcel");
-
- while ((data = is.read()) != -1)
- outputstream.write(data);
- is.close();
- outputstream.close();
- response.flushBuffer();
-
- }
-
- /** */
- /**
- * 在文件不存在的情况下,采用生成输出流的方式实现左键点击下载功能。
- *
- * @param outPutFileName 保存的文件名
- * @param out ServletOutputStream对象
- * @param downExcel 填充了数据的ExcelModel
- * @param HttpServletResponse
- * @see HttpServletResponse
- * @throws Exception
- */
- public void downLoad(String outPutFileName, ExcelModel downExcel, HttpServletResponse response) throws Exception {
-
- // 取得输出流
- OutputStream out = response.getOutputStream();
- // 清空输出流
- response.reset();
-
- // 设置响应头和下载保存的文件名
- response.setHeader("content-disposition", "attachment;filename=" + outPutFileName);
- // 定义输出类型
- response.setContentType("APPLICATION/msexcel");
-
- ExcelOperator op = new ExcelOperator();
- // out:传入的输出流
- op.WriteExcel(downExcel, out);
-
- out.close();
- // ServletOutputStream os = response.getOutputStream();
- // out.clear();
- // out = pageContext.pushBody();
-
- // 强行将响应缓存中的内容发送到目的地
- response.flushBuffer();
-
-
- }
操作类,进行生成下载文件流的操作
java 代码
- /**
- * 实现生成Excel文件的操作
- */
- public class ExcelOperator {
-
- /**
- * 将数据信息写入到Excel表文件,采取自建输出流的方式。
- *
- * @param excel ExcelModel Excel表的模型对象
- * @throws Exception
- */
- public void WriteExcel(ExcelModel excel) throws Exception {
-
- try {
-
- String file = excel.getPath();
-
- // 新建一输出文件流
- FileOutputStream fOut = new FileOutputStream(file);
- BufferedOutputStream bf = new BufferedOutputStream(fOut);
-
- HSSFWorkbook workbook = this.getInitWorkbook(excel);
-
- // 把相应的Excel 工作簿存盘
- workbook.write(fOut);
- fOut.flush();
- bf.flush();
- // 操作结束,关闭文件
- bf.close();
- fOut.close();
- // System.out.println("Done!");
- } catch (Exception e) {
- // System.out.print("Failed!");
- throw new Exception(e.getMessage());
- }
-
- }
-
- /**
- * 将数据信息写入到Excel表文件 ,采取传入输出流的方式。
- *
- * @param excel Excel表的模型对象
- * @param out OutputStream 输出流
- * @throws Exception
- */
- public void WriteExcel(ExcelModel excel, OutputStream out) throws Exception {
- try {
- HSSFWorkbook workbook = this.getInitWorkbook(excel);
- workbook.write(out);
- out.close();
- // System.out.println("Done!");
- } catch (Exception e) {
- // System.out.println("Failed!");
- throw new Exception(e.getMessage());
- }
实现按照具体的需求生成Excel表格文件流的类
java 代码
- /**
- * 根据需求的表格类或者结果集list
- *
- * @author Koala
- */
- public class UserExcelDownLoad extends BaseExcelDownLoad {
-
- public ExcelModel createDownLoadExcel(List list, ExcelModel excel) throws Exception {
- String titleStr = "ID;名称;性别;";
-
- ArrayList data = new ArrayList();
-
- Iterator ir = list.iterator();
- while (ir.hasNext()) {
-
- ArrayList rowData = new ArrayList();
-
- User user = (User) ir.next();
- rowData.add(user.getId());
- rowData.add(user.getName());
- rowData.add(user.getSex());
-
- data.add(rowData);
-
- }
-
- String[] titles = titleStr.split(";");
-
- /**//*
- * for(int i=0;i
- */
-
- ArrayList header = new ArrayList();
- for (int i = 0; i < titles.length; i++) {
- header.add(titles[i]);
- }
-
- // 设置报表标题
- excel.setHeader(header);
- // 设置报表内容
- excel.setData(data);
- return excel;
- }
-
- }
最后在action部分
java 代码
- public class FileOutAction implements Action, ModelDriven {
-
- private static Log log = LogFactory.getLog(FileOutAction.class);
-
- public String execute() throws Exception {
- ExcelModel excel = new ExcelModel();
- excel.setSheetName("BidCost");
- ActionContext ctx = ActionContext.getContext();
- HttpServletResponse response = (HttpServletResponse) ctx.get(ServletActionContext.HTTP_RESPONSE);
- //写入到Excel格式输出流供下载
- try {
- // TODO 返回对象list
- List userList = new ArrayList();
- for (int i = 0; i <3; i++) {
- User user = new User();
- user.setId(i);
- user.setName("1"+i);
- user.setSex(i);
- userList.add(user);
-
- }
-
- //调用自编的下载类,实现Excel文件的下载
- ExcelDownLoad downLoad = new AgentInfoExcelDownLoad();
- ExcelModel downExcel = downLoad.createDownLoadExcel(userList, excel);
- //不生成文件,直接生成文件输出流供下载
- downLoad.downLoad("BidCost.xls", downExcel, response);
- response.resetBuffer();
- log.info("create Excel outputStream successful!");
-
- } catch (Exception e) {
-
- log.info("create Excel outputStream failed!");
-
- }
- //TODO暂时的解决异常抛出
- return null;
|
这是参照网上一个仁兄的提示写出的,如果跳转到本身画面,就会抛出流已经被打开的异常,所以暂时用了返回null,意味用servlet写画面太麻烦显示页面的东西了,而且有些不够统一,今天发现了,webwork可以返回none,不返回视图,问题终于解决了