在线实时生成Excel文件流供下载

 

  我做过的一个项目,需要实现在线实时生成 Excel文件供客户端下载的需求,最初考虑的是先在服务器端生成真实的文件,然后在客户端下载该文件。后来发现这样做不但性能不够好、速度较慢,而且还要占用服务器空间。所以采取了在服务器端生成文件输出流(ServletOutputStream),通过HttpServletResponse对象设置相应的响应头,然后将此输出流传往客户端的方法实现。在实现过程中,用到了Apache组织的Jakarta开源组件POI,读者朋友可到其官方网站查阅相关资料及下载。现将整个实现过程介绍如下:

         一、首先,根据Excel表的特点,我编写了一个Excel表模型类ExcelModel,代码如下:

package  com.qnjian.myprj.excel;

import  java.util.ArrayList;

/**
 *
 * <p>Title: ExcelModel</p>
 *
 * <p>Description: Excel表的操作模型</p>
 *
 * <p>Copyright: Copyright (c) 2005-10-20</p>
 *
 * <p>Company: *** </p>
 *
 * 
@author  zzj
 * 
@version  1.0
 
*/


public   class  ExcelModel  {
      
/**
       * 文件路径,这里是包含文件名的路径
       
*/

      
protected  String path;
      
/**
       * 工作表名
       
*/

      
protected  String sheetName;
      
/**
       * 表内数据,保存在二维的ArrayList对象中
       
*/

      
protected  ArrayList data;
      
/**
       * 数据表的标题内容
       
*/

      
protected  ArrayList header;
      
/**
       * 用于设置列宽的整型数组
       * 这个方法在程序中暂未用到
       * 适用于固定列数的表格
       
*/

      
protected   int [] width;

      
public  ExcelModel()  {
            path
= " report.xls " ;
      }


      
public  ExcelModel(String path)  {
           
this .path = path;
     }



      
public   void  setPath(String path) {
           
this .path = path;
      }


      
public  String getPath() {
            
return   this .path;
      }

      
      
public   void  setSheetName(String sheetName) {
          
this .sheetName = sheetName;
      }

      
      
public  String getSheetName() {
          
return   this .sheetName;
      }


      
public   void  setData(ArrayList data) {
            
this .data = data;
      }


      
public  ArrayList getData() {
            
return   this .data;
      }


      
public   void  setHeader(ArrayList header) {
            
this .header = header;
      }


      
public  ArrayList getHeader() {
            
return   this .header;
      }


      
public   void  setWidth( int [] width) {
            
this .width = width;
      }


      
public   int [] getWidth() {
            
return   this .width;
      }

}

      
  二、编写一个下载接口ExcelDownLoad,定义基本的方法:

package  com.qnjian.myprj.excel;

import  java.io.IOException;
import  java.util.List;

import  javax.servlet.http.HttpServletResponse;

import  org.apache.struts.action.ActionForm;


public   interface  ExcelDownLoad  {
    
    
/**
     * 初始化要生成的Excel的表模型
     * 
@param  list List 填充了 Excel表格数据的集合
     * 
@param  form ActionForm及其子类
     * 
@param  excel ExcelModel Excel表的对象模型
     * 
@see  ExcelModel
     * 
@throws  Exception
     
*/

    
public  ExcelModel createDownLoadExcel (List list, ActionForm form, 
            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 ;
    
    
/**
     * 在已文件不存在的情况下,采用生成输出流的方式实现左键点击下载功能。
     * 
@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()方法的公共实现,代码如下:

/**
 *
 * <p>Title: BaseExcelDownLoad</p>
 *
 * <p>Description:Excel表下载操作基类,生成excel格式的文件流供下载 </p>
 *
 * <p>Copyright: Copyright (c) 2005-10-27</p>
 *
 * <p>Company: *** </p>
 *
 * 
@author  zzj
 * 
@version  1.0
 
*/

package  com.qnjian.myprj.excel;

import  java.io.FileInputStream;
import  java.io.IOException;
import  java.io.InputStream;
import  java.io.OutputStream;
import  java.util.List;

import  javax.servlet.http.HttpServletResponse;
import  org.apache.struts.action.ActionForm;


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, ActionForm form, 
            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();
        
        
// 这一行非常关键,否则在实际中有可能出现莫名其妙的问题!!!
       response.flushBuffer(); // 强行将响应缓存中的内容发送到目的地                              
    
   
     }


}


  请注意,BaseExcelDownLoad只是提供了一个生成下载文件流的公共方法,而Excel表格需要显示的数据内容则因具体业务与需求的不同而不同,因此,必须根据具体情况提供一个该类的继承类,实现createDownLoadExcel()方法,以生成所需要输出内容的Excel表格文件流。要说明的是,该方法的参数list ,实际上是一个ArrayList集合,我们将从数据库查询出来的记录集保存在其中,我想这是很容易做到的,实现的方式也可以各种各样。我项目中是通过Hibernate的Query对象取得查询结果集,它正好也是一个ArrayList。不同的客户,甚至不同功能模块内需要生成的Excel报表的内容都是不一样的。下面还是给出我的一个实现类作为例子吧。


  四、实现按照具体的需求生成Excel表格文件流的类举例:继承自BaseExcelDownLoad类的AgentInfoExcelDownLoad:

package  com.qnjian.myprj.excel;

import  java.math.BigDecimal;
import  java.util.ArrayList;
import  java.util.Iterator;
import  java.util.List;

import  org.apache.struts.action.ActionForm;

import  com.netease.bid.cs.model.BidAgent;
import  com.netease.bid.cs.model.BidUser;
import  com.netease.bid.cs.util.DateUtil;
import  com.netease.bidding.cs.servlet.InitCsServlet;
import  com.netease.bidding.cs.vo.InstructUser;

public   class  AgentInfoExcelDownLoad  extends  BaseExcelDownLoad  {

    
public  ExcelModel createDownLoadExcel(List list, ActionForm form,
            ExcelModel excel) 
throws  Exception  {
        
        String titleStr 
=   " 客户帐号;公司名称;所属地区;帐户余额;注册日期;联系方式;联系人; " ;
    
        ArrayList data 
=   new  ArrayList();        
        
        Iterator ir 
=  list.iterator();
        
while (ir.hasNext()) {
            
            ArrayList rowData 
=   new  ArrayList();
            
            BidAgent user 
=  (BidAgent)ir.next();
        
            rowData.add(user.getName());
            rowData.add(user.getCorpName());            
        
            
// 取得所在省名称
            String provStr  =  (user.getProvince() == null  )  ?  
                    
""  : InitCsServlet.getProvinceStr(
                    user.getProvince());
            
            
// 取得所在地区名称
             String cityStr  =  (user.getCity() == null ?
                     
""  : InitCsServlet.getCityStr(
                   user.getCity());
            
if (provStr.equals(cityStr)) {
                cityStr 
=   "" ;
            }

            rowData.add(provStr
+ "   " + cityStr);
            
                        BigDecimal balance 
= user.getReturnBalance().add(user.getBalance());
            rowData.add(balance);            
            
            String date 
=  DateUtil.getFormatDate(user.getCreateTime(), " yyyy-MM-dd " );
            rowData.add(date);        
    
            rowData.add(user.getPhone());
            rowData.add(user.getLinkMan());

            data.add(rowData);        
            
        }

        
    
        String[] titles 
=  titleStr.split( " ; " );
        
        
/* for(int i=0;i<titles.length;i++){
            System.out.print(titles[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;
    }


}


        五、编写一个操作类,进行生成下载文件流的操作:

/**
 *
 * <p>Title: Excel表操作</p>
 *
 * <p>Description:用于生成Excel格式文件 </p>
 *
 * <p>Copyright: Copyright (c) 2005-10-20</p>
 *
 * <p>Company: *** </p>
 *
 * 
@author  zzj
 * 
@version  1.0
 
*/


package  com.qnjian.myprj.excel;

import  org.apache.poi.hssf.usermodel. * ;
import  java.io.FileOutputStream;
import  java.io.BufferedOutputStream;
import  java.util.ArrayList;
import  java.math.BigDecimal;
import  java.io.OutputStream;


/**
 *实现生成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());
         }

         
         
     }

    
    
/**
     * 取得填充了数据的工作簿
     * 
@param  excel ExcelModel Excel表的模型对象
     * 
@return  HSSFWorkbook 工作簿对象
     
*/

    
private   HSSFWorkbook getInitWorkbook(ExcelModel excel) {
            

            
//  创建新的Excel 工作簿
            HSSFWorkbook workbook  =   new  HSSFWorkbook();

             
// 在Excel工作簿中建一工作表
             HSSFSheet sheet  =   null ;
             String sheetName 
=  excel.getSheetName();
             
             
if (sheetName != null )sheet = workbook.createSheet(sheetName);
             
else  sheet = workbook.createSheet();

             
// 设置表头字体
             HSSFFont font_h  =  workbook.createFont();
             font_h.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);

             
// 设置格式
             HSSFCellStyle cellStyle =  workbook.createCellStyle();
             cellStyle.setFont(font_h);            


              
// 在索引0的位置创建行(最顶端的行)
               HSSFRow row  =  sheet.createRow(( short ) 0 );

               ArrayList header 
=  excel.getHeader();
               
if (header != null ) {
                   
for ( int  i = 0 ;i < header.size();i ++ ) {

                  
// 在索引0的位置创建单元格(左上端)
                  HSSFCell cell  =  row.createCell(( short )i);
                  
//  定义单元格为字符串类型
                 cell.setCellType(HSSFCell.CELL_TYPE_STRING);
                 
// 设置解码方式
                 cell.setEncoding(( short ) 1 );
                 
// 设置单元格的格式
                 cell.setCellStyle(cellStyle);
                 
//  在单元格中写入表头信息
                 cell.setCellValue((String)header.get(i));

                   }

               }


               ArrayList cdata 
=  excel.getData();
               
for  ( int  i = 0 ;i < cdata.size();i ++ ) {
                
// 从第二行开始
                HSSFRow row1  =  sheet.createRow(i + 1 );
                ArrayList rdata 
= (ArrayList)cdata.get(i);
               
// 打印一行数据
                 for  ( int  j = 0 ;j < rdata.size();j ++ ) {

                    HSSFCell cell 
=  row1.createCell( ( short )j);
                    cell.setCellType(HSSFCell.CELL_TYPE_STRING);
                    
// 设置字符编码方式
                    cell.setEncoding(( short ) 1 );
                    
                   Object o 
=  rdata.get(j);
                    
                    
// 造型,使写入到表中的数值型对象恢复为数值型,
                   
// 这样就可以进行运算了
                     if (o  instanceof  BigDecimal) {
                        BigDecimal b
= (BigDecimal)o;
                        cell.setCellValue(b.doubleValue());
                    }

                    
else   if (o  instanceof  Integer) {
                           Integer it 
= (Integer)o;
                           cell.setCellValue(it.intValue());
                           
                    }

                    
else   if (o  instanceof  Long) {
                        Long l 
= (Long)o;
                        cell.setCellValue(l.intValue());
                        
                    }

                    
else   if (o  instanceof  Double) {
                        Double d 
= (Double)o;
                        cell.setCellValue(d.doubleValue());
                    }

                    
else   if (o  instanceof  Float) {
                        Float f 
=  (Float)o;
                        cell.setCellValue(f.floatValue());
                    }

                    
else {
                        cell.setCellValue(o
+ "" );
                    }
             
            
                    
                }


               }

           
return  workbook;
            
        }


  
/**
   * Just to test
   * 
@param  args String[]
   
*/

  
public   static   void  main(String[] args) {

                ArrayList data
= new  ArrayList();
                ArrayList header 
=   new  ArrayList();
                header.add(
" 学号 " );
                header.add(
" 姓名 " );
                header.add(
" 成绩 " );
                
for  ( int  i = 0 ;i < 3 ;i ++ ) {

                     ArrayList data1
= new  ArrayList();

                            data1.add((i
+ 1 ) + "" );
                            data1.add(
" Name " + (i + 1 ));
                            data1.add(
"" + ( 80 + i));
                            data.add(data1);
                }

                ExcelModel model 
=   new  ExcelModel();
                model.setPath(
" E:/test.xls " );
                model.setHeader(header);
                model.setData(data);
                ExcelOperator eo
=   new  ExcelOperator();
               
try {
                  eo.WriteExcel(model);
               }
catch (Exception e) {
                     System.out.println(e.getMessage());
               }


        }

}



         六、功能流程小结:

         涉及到不同的项目,采取的框架与结构是可能不同的。我的实现方法可以应用到不同的项目中去,只是作为一个借鉴,它可能需要针对不同情况做相应调整与修改。
         我的项目是采取了Spring+Struts+Hibernate的框架实现的,显示层仍然使用HTML、JSP文件,通过它传递客户端的请求,转到Action类调用业务逻辑对象实现相应功能。持久层使用了Hibernate,使用Hibernate作为数据持久层,在开发与维护方面都带来了较大的便利。至于相关框架的配置与实现,则不在本文论述的范围,请读者朋友参阅相关资料。我的项目中,使用了一个Service类(类似Manager的功能,编写接口与实现类,在Spring配置文件中加入,利用Spring的依赖注入技术在运行中取得对应的Bean实例......)来集成业务逻辑功能,通过它调用涉及到的数据访问类(DAO类),具体Dao类又利用Hibernate提供的对象进行数据库的查询或其他操作。这些东西,我就不再详述了,相信对这些技术使用得比我娴熟者大有人在。功能的最终实现,请看我在某个Action中的几行代码:

 ExcelModel excel  =   new  ExcelModel();
                         excel.setSheetName(
" BidCost " );                           
                                 
                            
// 写入到Excel格式输出流供下载
                            try {                           
                         
                                
// 调用自编的下载类,实现Excel文件的下载
                               ExcelDownLoad downLoad  =   new  BidCostExcelDownLoad();
                               ExcelModel downExcel
=  downLoad.createDownLoadExcel(bidReportList,bcf,excel);
                               
// 不生成文件,直接生成文件输出流供下载
                               downLoad.downLoad( " BidCost.xls " ,downExcel,response);
                               
                               log.info(
" create Excel outputStream successful! " );                               
                           
                           }
catch (Exception e) {
                               msg.add(ActionMessages.GLOBAL_MESSAGE, 
new  ActionMessage(
                                       
" bidding.cs.fileUpDown.fileDownError " )); // 文件下载失败!
                                  saveErrors(request, msg);                                
                              
                                 log.info(
" create Excel outputStream  failed! " );
                              log.info(e.getMessage());
                              
// e.printStackTrace();
                              
                              
return  mapping.getInputForward();                             

                           }
                       


         请看客户端的显示页面:

         

 

贴子来自:http://www.blogjava.net/qnjian/archive/2005/12/30/25999.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下载Excel文件是指通过Vue前端框架实现在网页上实时下载Excel文件的功能。为了实现这一功能,可以通过以下步骤: 1. 在Vue组件中使用axios或者其他网络请求库,向后端发送请求获取Excel文件数据。 2. 后端接收到请求后,根据接口要求生成Excel文件,并将文件返回给前端。 3. 前端接收到Excel文件数据后,通过Blob对象和URL.createObjectURL方法创建可供下载Excel文件链接。 4. 在Vue组件中使用a标签或者其他方式,将Excel文件链接绑定到下载按钮或者表格中。用户点击下载按钮即可下载Excel文件。 在编写相关代码时,需要注意文件的处理、请求的发送和响应的处理。具体示例代码如下:(以axios为例) ```javascript // Vue组件中发送请求 <template> <div> <button @click="downloadExcel">下载Excel</button> </div> </template> <script> import axios from 'axios'; export default { methods: { downloadExcel() { axios({ method: 'get', url: 'http://your-backend-api-url/export-excel', responseType: 'blob', // 告诉axios返回的数据是二进制 }) .then(response => { const url = window.URL.createObjectURL(new Blob([response.data])); const link = document.createElement('a'); link.href = url; link.setAttribute('download', 'excel.xlsx'); document.body.appendChild(link); link.click(); }) } } } </script> ``` 以上就是使用Vue下载Excel文件的基本方法。通过这种方式,用户可以在网页上快速方便地下载后端生成Excel文件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值