注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

山林客

简单不一定幸福,但幸福其实可以很简单。

 
 
 

日志

 
 
关于我

2004年毕业于中山大学,毕业后专注于网站开发和网络工程技术。先后取得SCWCD、CCNP认证,对Asp/Java有丰富的开发经验,对网络工程也有较深的研究。真诚欢迎大家多多指教、多多指点、多多指正,共同分享IT道路和人生道路上的喜怒哀乐。

网易考拉推荐

Struts2+poi实现Excel文件导出  

2010-06-01 18:39:36|  分类: JavaEE |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

今天在写四位一体系统的过程中,根据需求需要实现工单的导出功能。我上网查找了一些资料,然后根据自己的实际,比较顺利地实现了这个功能。

 

下面简单分享一下:

 

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

 

这个功能只需要用到一个Action,并在struts.xml中将其配置好即可。

 

<action name="exportExcel" class="panyu.flow.web.action.ExcelAction">
            <result name="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>
            <result name="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文件的名称。

 

然后看Struts

package panyu.flow.web.action;

import java.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;

import javax.servlet.http.HttpServletRequest;

import org.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;

import panyu.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;

import com.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;
 InputStream excelStream;  //这个输入流对应上面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表数据填充方法”,而不用为每个特定类都创建一个。

  这个接口有两个方法:

   public String[] 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 = new ByteArrayInputStream(aa, 0, aa.length);
        baos.close();
 }
 
 

 public void setGdService(GdService gdService) {
  this.gdService = gdService;
 }
 
 public String getFileName() {
  return fileName;
 }
 
 public InputStream getExcelStream()
 {
  return excelStream;
 }
 
 
 /*下面这个方法是将list转换为Excel工作表的*/
 private HSSFWorkbook getWorkbook(List<Exportable> list) throws Exception{
  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();

   
  HSSFRow row = 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列
    Method method; 
    method = exp.getClass().getMethod(columnMethods[j]);  //这里用到了反射机制,通过方法名来取得对应方法返回的结果对象
    Object obj = method.invoke(exp);

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

 public void setCzyService(CzyService czyService) {
  this.czyService = czyService;
 }

 public void setCzydwService(CzydwService czydwService) {
  this.czydwService = czydwService;
 }

}

 

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

 

最后看一下Gd类

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

package panyu.flow.business.vo;

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

import panyu.flow.business.vo.inf.Exportable;

 

public class Gd implements Exportable{
 private int id;
 private String gdbt; //工单标题
 private String gdnr; //工单内容
//略
 private String[] 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;
 }
 
}

  评论这张
 
阅读(5974)| 评论(4)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018