struts2+poi实现导出Excel文件

来源:互联网 发布:suse linux下没有setup 编辑:程序博客网 时间:2024/03/29 22:05

首先需要去找一个pio包,我使用的是poi-3.2.jar


jsp:

 <input type="button" id="btnKeyWordExcel" onclick="window.location.href='keyWord_excel.action'" value="导出结果至EXCEL文件"/>

 

struts.xml

<actionname="exportExcel" class="panyu.flow.web.action.ExcelAction"> 
            <resultname="success" type="stream"
               <param name="contentType">application/vnd.ms-excel</param>  

               <param name="inputName">excelStream</param>
               <param name="contentDisposition">attachment;filename="${fileName}.xls"</param>
              <param name="bufferSize">1024</param>
           </result> 
            <resultname="error">/WEB-INF/jsp/msg_error.jsp</result>
</action>

 

上面的配置中需要注意红色字体标注的部分。

1.、result的类型需要配置为stream(流),这是因为我们的Excel文件是以字节流的形式输出的。

2、contentType指定了我们导出的数据流其实是一个Excel文档。

3、inputName配置的是输入流的名称,我们导出的Excel就是从这个输入流里面读取数据。

4、contentDisposition的作用主要是让IE浏览器将其作为一个附件形式返回而不是直接在网页中显示,其中我们用到一个参数fileName,这样可以在Struts中动态修改这个Excel文件的名称。

 

package panyu.flow.web.action;

importjava.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

importjavax.servlet.http.HttpServletRequest;

importorg.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
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.StrutsStatics;

importpanyu.flow.business.service.CzyService;
import panyu.flow.business.service.CzydwService;
import panyu.flow.business.service.GdService;
import panyu.flow.business.vo.Czy;
import panyu.flow.business.vo.Czydw;
import panyu.flow.business.vo.Gd;
import panyu.flow.business.vo.inf.Exportable;

importcom.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;

/**
 * @author Liang Zhibiao
 */
public class ExcelAction extends ActionSupport {
 private GdService gdService;
 private CzyService czyService;
 private CzydwService czydwService;
 InputStreamexcelStream;  //这个输入流对应上面struts.xml中配置的那个excelStream,两者必须一致
 String fileName;  //
这个名称就是用来传给上面struts.xml中的${fileName}

 
 @Override 
 public String execute() throws Exception {   
  
  /*第一步:获取查询参数

 我这个应用要导出的其实是用户查询返回的结果列表(List),而导出Excel”这个按钮我就是放到查询结果显示页面上的。在这个页面上,我用一个form来将用户上一步查询的参数保存下来,然后当用户点击导出Excel”按钮的时候,其实是再执行了一次form表单提交来执行本Action。这两次查询其实是大同小异的,只是显示查询结果的时候还需要做一个分页的功能,而这里导出则不用进行分页。*/
  HttpServletRequest request = (HttpServletRequest) ActionContext
  .getContext().get(StrutsStatics.HTTP_REQUEST);
  DateFormat dateFormat = DateFormat.getDateInstance();
  
  String str_fqrid = request.getParameter("fqrid");
  String str_fsqj1 = request.getParameter("fqsj1");
  ……略  
  
  
  /*第二步:得到List

  这个List需要调用到数据服务层,传入相应参数后会返回一个List

  另外,我这里用到了接口而不是实际的类,这是为了方便我们可以创建一个通用的“Excel表数据填充方法,而不用为每个特定类都创建一个。

  这个接口有两个方法:

   publicString[] getColumnNames() ;  //返回需要导出的列名称,例如工单标题工单内容
   public String[] getColumnMethods(); //
这是一个方法名称数组,我们会用到反射中的invoke来调用这些方法来取得各行数据

 */
  List<Exportable> list = gdService.exportGd(fqrid, fqsj1, fqsj2, gdbt,gdnr, lcszid, nsrsbh, nsrmc,wszt, zzwcsj1, zzwcsj2, dqjbrid, jbrid, jbrdwid,jbrgwid);
  if(list==null){
   request.setAttribute("message", "没有数据");
   return ERROR;
  }else{


   /*第三步:创建Excel工作簿。

  正如上面所说,由于我们使用了接口,所以下面这个getWorkbook方法接收的list中的元素并不针对特定的类,只要该类实现了Exportable接口即可  */

   HSSFWorkbook workbook = getWorkbook(list);

    
    if(workbook != null){
                try{
                       Calendar c = Calendar.getInstance();
                       int year = c.get(Calendar.YEAR);
                        int month = c.get(Calendar.MONTH)+1;
                        String month_ = new String(""+month);
                        if(month<10){
                              month_ = "0"+month;
                        }
                        int day = c.get(Calendar.DAY_OF_MONTH);
                        String day_ = new String(""+day);
                       if(day<10){
                              day_ = "0"+day;
                         }
                        //第四步:将工作簿写入最上面定义的InputStream——名称为excelStream,这个名字对应struts.xml中配置的inputName参数             
                        this.workbook2InputStream(workbook,year+"-"+month_+"-"+day_+"");

                       return SUCCESS;
                  }catch(IOException e){
                        e.printStackTrace();
                        request.setAttribute("message", "创建Excel失败");
                        return ERROR;
                  }
    }else{
     request.setAttribute("message", "创建Excel失败");
                return ERROR;
    }
  }
  
 }
 
 //创建Workbook
 
 //Workbook写入到InputStream
 private void workbook2InputStream(HSSFWorkbook workbook,String fileName)throws Exception{
        this.fileName = fileName; //设置fileName
       ByteArrayOutputStream baos = new ByteArrayOutputStream();
        workbook.write(baos); 
        baos.flush(); 
        byte[] aa = baos.toByteArray();
        excelStream = newByteArrayInputStream(aa, 0, aa.length);
       baos.close();
 }
 
 

 public voidsetGdService(GdService gdService) {
  this.gdService = gdService;
 }
 
 public String getFileName() {
  return fileName;
 }
 
 public InputStream getExcelStream()
 {
  return excelStream;
 }
 
 
 /*下面这个方法是将list转换为Excel工作表的*/
 private HSSFWorkbook getWorkbook(List<Exportable> list) throwsException{
  HSSFWorkbook workbook = new HSSFWorkbook(); 
  HSSFSheet sheet = workbook.createSheet("sheet1");
  String[] columnNames;
  String[] columnMethods;
 

//首先,我们读取list中的第一个元素,根据它来确定工作表的列名,以及输出数据所对应的方法数组
  Exportable exp = list.get(0);
  columnNames = exp.getColumnNames();
  columnMethods = exp.getColumnMethods();

   
  HSSFRowrow = sheet.createRow(0); //创建第1行,也就是输出表头
  HSSFCell cell;
  for(int i=0;i<columnNames.length;i++){
   cell = row.createCell(i); //
创建第i
   cell.setCellValue(new HSSFRichTextString(columnNames[i]));
  }

 

 //下面是输出各行的数据
  for (int i = 0; i < list.size(); i++) {
   exp=(Exportable)list.get(i);
   row=sheet.createRow(i+1);//创建第i+1行
   for(int j=0;j<columnMethods.length;j++){
    cell=row.createCell(j);//创建第j列
    Methodmethod; 
    method = exp.getClass().getMethod(columnMethods[j]);  //
这里用到了反射机制,通过方法名来取得对应方法返回的结果对象
    Object obj = method.invoke(exp);

    cell.setCellValue(obj.toString());
   }
  }
  return workbook;
 }
 
 
 
 

 public voidsetCzyService(CzyService czyService) {
  this.czyService = czyService;
 }

 public voidsetCzydwService(CzydwService czydwService) {
  this.czydwService = czydwService;
 }

}

 

这种实现方式网上已经有很多描述,主要的区别是我这里用到了接口和反射机制,因为我需要导出的类型并不只是工单类(Gd),还会有操作员类(Czy)等等,如果每个类都要单独写一个创建Excel表的方法,那并不是明智的方法。由于我需要用到查询,所以获取list这一块暂时还没有用到接口,其实这一块也可以再继续虚拟化一些,也可以定义一个接口,这样,这个Excel导出类就可以更加通用了。

 

最后看一下Gd类

/**
 * @author Liang Zhibiao
 * 工单
 */

packagepanyu.flow.business.vo;

importjava.util.Date;
import java.util.Set;
import java.util.TreeSet;

importpanyu.flow.business.vo.inf.Exportable;

 

public class Gdimplements Exportable{
 private int id;
 private String gdbt; //工单标题
 private String gdnr; //工单内容
//略
 privateString[] columnNames
 =new String[]{"ID","
工单标题","工单内容","纳税人识别号","纳税人名称","发起人","发起时间","最终完成时间","工单状态"};
 private String[] columnMethods
 = new String[]{"getId","getGdbt","getGdnr","getNsrsbh","getNsrmc","getFqrmc","getFqsjStr","getZzwcsjStr","getWcztName"};

 
 public String[] getColumnNames() {
  return columnNames;
 }
 public String[] getColumnMethods() {
  return columnMethods;
 }
 
}

 

原创粉丝点击