开发过程中,需要把数据导出到excel中,用jxl_2_6_4.jar包实现java对excel的操作。
下面介绍两种方法写excel文件,一个是sheet模板,填入数据;一个是row模板,然后填入excel。
利用模板操作excel比较方便,可以用excel设置好所需要的单元格格式,然后读入按照业务规则填写,实现所有的excel格式设置,而不用研究jxl的api,是一种偷懒的做法。
我的项目中,报表全部是生成excel文件输出。
首先,建立一个excel报表接口
/**
* 报表生成器
* @author zhengmw
*
*/
public interface IReportMaker {
/**
* 输出报表
* @return 报表文件路径,让调用者直接打开文件,可能生成多个文件
* @throws GeneException 自定义异常
*/
public List<String> report() throws GeneException;
}
然后实现一个excel报表的抽象类
/**
* EXCEL报表基类
*
* @author zhengmw
*
*/
public abstract class AbstractExcelReportMaker implements IReportMaker {
/**
* 模板文件名, 构造函数传入
*/
private String fileName;
/**
* 每页行数, 构造函数传入
*/
private int iRowAmt;
/**
* 当前行
*/
private int iRow = 0;
/**
* 报表页数
*/
private int iPageAmt = 0;
/**
* 报表数据, 构造函数传入
*/
protected List data;
/**
* 报表列表,保存报表的文件路径
*/
private List<String> reports = new ArrayList<String>();
/**
* 输出默认地址
*/
private final String default_report_path = "report_bak/";
/**
* 工作簿
*/
private WritableSheet ws;
/**
* @param data
* 报表数据
* @param fileName
* 模板文件名
* @param iRowAmt
* 每页行数
*/
public AbstractExcelReportMaker(List data, String fileName, int iRowAmt) {
this.data = data;
this.fileName = fileName;
this.iRowAmt = iRowAmt;
}
/**
* 报表输出路径
*
* @return
*/
protected String getReportOutputDirectory() {
return "";
}
/**
* 获取模板文件
*
* @return
*/
protected File getSourceFile() {
return new File(PluginUtil.getFullPath(DrawbackPlugin.PLUGIN_ID, "report/") + fileName);
}
/**
* 获取生成报表文件
*
* @return
*/
protected File getReportFileUrl() {
return new File(getReportOutputDirectory() + getOutputFileName());
}
/**
* 获取报表文件名
*
* @return
*/
private String getOutputFileName() {
return fileName.substring(0, fileName.length() - 4) + iPageAmt + ".xls";
}
/**
* 取字符CELL,用于替换数字类型的CELL
*
* @return
*/
protected abstract Label getLabelCell(WritableSheet ws);
/**
* 给单元格赋值
*
* @param wc
* @param value
* @throws GeneException
*/
protected void setLableValue(Cell wc, Object value) throws GeneException {
try {
// 判断单元格的类型, 做出相应的转化
if (wc.getType() == CellType.LABEL) {
setCellValue(wc, value);
} else if (wc.getType() == CellType.DATE) {
if (value == null) {
WritableCell c = getLabelCell(ws).copyTo(wc.getColumn(), wc.getRow());
setCellValue(c, value);
ws.addCell(c);
} else {
setCellValue(wc, value);
}
} else if (wc.getType() == CellType.NUMBER) {
if (value == null) {
WritableCell c = getLabelCell(ws).copyTo(wc.getColumn(), wc.getRow());
setCellValue(c, value);
ws.addCell(c);
} else {
setCellValue(wc, value);
}
}
} catch (GeneException e) {
throw e;
} catch (Exception e) {
throw GeneException.getGeneException(ERR.ERROR_ERR_MSG, "数据类型不匹配");
}
}
private void setCellValue(Cell wc, Object value) throws GeneException {
try {
// 判断单元格的类型, 做出相应的转化
if (wc.getType() == CellType.LABEL) {
((Label) wc).setString((String) value);
} else if (wc.getType() == CellType.DATE) {
((DateTime) wc).setDate((Date) value);
} else if (wc.getType() == CellType.NUMBER) {
if (value instanceof Integer) {
((jxl.write.Number) wc).setValue(((Integer) value).doubleValue());
} else if (value instanceof BigDecimal) {
((jxl.write.Number) wc).setValue(Double.parseDouble(StringUtility
.strNull((BigDecimal) value)));
}
}
} catch (Exception e) {
throw GeneException.getGeneException(ERR.ERROR_ERR_MSG, "数据类型不匹配");
}
}
/**
* 设置拷贝cell的值,一般应用与无限制行的模板
*
* @param cell
* @param col
* @param row
* @param value
* @throws GeneException
*/
protected void setCopyCellValue(WritableCell cell, int col, int row, Object value)
throws GeneException {
WritableCell wc = cell.copyTo(col, row);
setCellValue(wc, value);
try {
ws.addCell(wc);
} catch (Exception e) {
throw GeneException.getGeneException(ERR.ERROR_ERR_MSG, "EXCEL数据操作失败");
}
}
/**
* 生成报表头部
*
* @param ws
*/
protected abstract void reportHeadMaker(WritableSheet ws) throws GeneException;
/**
* 生成报表内容
*
* @param ws
* @param i
* 从0行开始
*/
protected abstract void reportContentMaker(WritableSheet ws, Object obj, int iRow)
throws GeneException;
/**
* 生成报表底部
*
* @param ws
*/
protected abstract void reportBottomMaker(WritableSheet ws) throws GeneException;
/**
* 清除报表模板内容
*
* @param ws
* @param i
*/
protected abstract void clearReport(WritableSheet ws, int i) throws GeneException;
/**
* 每页生成报表小计
*
* @param ws
* @throws GeneException
*/
protected abstract void reportSubtotalMaker(WritableSheet ws) throws GeneException;
/**
* 最后一页生成报表总计
*
* @param ws
* @throws GeneException
*/
protected abstract void reportTotalizeMaker(WritableSheet ws) throws GeneException;
/**
* 对数据进行额外处理
*/
protected void reportDataProcessor() {
// do nothing
}
/**
* 是否新页面
*
* @return
*/
protected boolean isNewPage() {
return iRow % iRowAmt == 0;
}
/**
* 拷贝报表模板到指定路径
*
* @throws GeneException
*/
protected void copyFileToDirectory() throws GeneException {
try {
FileUtils.copyFile(getSourceFile(), getReportFileUrl(), false);
} catch (IOException e) {
throw GeneException.getGeneException(ERR.FW_IO_FILE_ERR);
}
}
/**
* 生成报表
*
* @throws GeneException
*/
protected void reportMaker() throws GeneException {
reportDataProcessor();
if (data == null || data.size() < 1) {
throw GeneException.getGeneException(ERR.ERROR_INFO_MSG, "没有找到数据!");
}
Workbook rwb = null;
WritableWorkbook wwb = null;
try {
for (int i = 0; i < data.size(); i++) {
if (isNewPage()) {
// 关闭原来的工作簿
if (wwb != null) {
reportSubtotalMaker(ws);
wwb.write();
wwb.close();
rwb.close();
}
// 填写报表
rwb = Workbook.getWorkbook(this.getSourceFile());
// 页面加1
iPageAmt++;
// 行重置为0
iRow = 0;
// 加入报表列表
reports.add(getReportFileUrl().getPath());
// copyFileToDirectory();
// 利用已经创建的Excel工作薄创建新的可写入的Excel工作薄
wwb = Workbook.createWorkbook(this.getReportFileUrl(), rwb);
// 读取第一张工作表
ws = wwb.getSheet(0);
reportHeadMaker(ws);
reportBottomMaker(ws);
}
reportContentMaker(ws, data.get(i), iRow);
// 行加1
iRow++;
}
// 清空剩余行内容
int iClear = data.size() % iRowAmt;
iClear = iClear == 0 || iRowAmt == Integer.MAX_VALUE ? 0 : iRowAmt - iClear;
for (int i = 0; i < iClear; i++) {
clearReport(ws, iRow + i);
}
// 生成报表总计
reportTotalizeMaker(ws);
// 写入Excel对象
wwb.write();
} catch (GeneException e) {
throw e;
} catch (IOException e) {
throw GeneException.getGeneException(ERR.FW_IO_FILE_ERR);
} catch (Exception e) {
throw GeneException.getGeneException(ERR.ERROR_ERR_MSG, new String[] { "报表生成意外终止" }, e);
} finally {
// 操作完成时,关闭对象,释放占用的内存空间
if (wwb != null) {
try {
wwb.close();
} catch (Exception e) {
throw GeneException.getGeneException(ERR.FW_IO_FILE_ERR);
}
}
if (rwb != null) {
rwb.close();
}
}
}
/*
* (non-Javadoc)
*
* @see com.jl.drawback.business.entity.IReportMaker#report()
*/
public List<String> report() throws GeneException {
// 生成报表
reportMaker();
// 返回报表文件路径
return reports;
}
/**
* 当前报表页数
*
* @return
*/
protected int getPageAmt() {
return iPageAmt;
}
}
这个抽象类主要实现按照模板生成报表,出入每页条数,自动生成多个文件(其实可以改成生成一个文件,多个sheet)。下次再举一个实现类。