Excel动态导出

#此文章是转载-----

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

下面简单分享一下:

首先需要去找一个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;
}

}

你可能感兴趣的:(apache,jsp,struts,Excel,IE)