1 设计思路
Java 对于Excel 的操作一般借助于POI 类库,由于有些报表的表头比较复杂,直接用POI 控制报表的生成比较困难,这时可以先制作Excel 报表模板,而后再通过Java 调用POI 函数将用户数据写入到Excel 报表模板,最后导出到新的目标文件即可。
2 设计步骤
2.1 初始步骤
2.1.1创建Excel 报表模板
根据需要设计出Excel 报表,并保存为default.xls。如下图所示。
/**
* 该类实现了基于模板的导出
* 如果要导出序号,需要在excel中定义一个标识为sernums
* 如果要替换信息,需要传入一个Map,这个map中存储着要替换信息的值,在excel中通过#来开头
* 要从哪一行那一列开始替换需要定义一个标识为datas
* 如果要设定相应的样式,可以在该行使用styles完成设定,此时所有此行都使用该样式
* 如果使用defaultStyls作为表示,表示默认样式,如果没有defaultStyles使用datas行作为默认样式
*/
public class ExcelTemplate {
private ExcelTemplate() {
}
public static ExcelTemplate getInstance() {
return et;
}
}
下面是以后要用到的一些变量和常量
/**
* 数据行标识
*/
public final static String DATA_LINE = "datas";
/**
* 默认样式标识
*/
public final static String DEFAULT_STYLE = "defaultStyles";
/**
* 行样式标识
*/
public final static String STYLE = "styles";
/**
* 插入序号样式标识
*/
public final static String SER_NUM = "sernums";
private static ExcelTemplate et = new ExcelTemplate();
private Workbook wb;
private Sheet sheet;
/**
* 数据的初始化列数
*/
private int initColIndex;
/**
* 数据的初始化行数
*/
private int initRowIndex;
/**
* 当前列数
*/
private int curColIndex;
/**
* 当前行数
*/
private int curRowIndex;
/**
* 当前行对象
*/
private Row curRow;
/**
* 最后一行的数据
*/
private int lastRowIndex;
/**
* 默认样式
*/
private CellStyle defaultStyle;
/**
* 默认行高
*/
private float rowHeight;
/**
* 存储某一方所对于的样式
*/
private Map styles;
/**
* 序号的列
*/
private int serColIndex;
2.2 读取excel报表模板的数据
/**
* 1、读取相应的模板文档
*/
public ExcelTemplate readTemplateByClasspath(String path){
try {
wb=WorkbookFactory.create(ExcelTemplate.class.getResourceAsStream(path));
initTemplate();
} catch (InvalidFormatException e) {
e.printStackTrace();
throw new RuntimeException("InvalidFormatException, please check.");
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("The template is not exist, please check.");
}
return this;
}
public ExcelTemplate readTemplateByPath(String path){
try {
wb=WorkbookFactory.create(new File(path));
} catch (InvalidFormatException e) {
e.printStackTrace();
throw new RuntimeException("InvalidFormatException, please check.");
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("The template is not exist, please check.");
}
return this;
}
在读取报表模板的时候会初始化模板,记录模板的样式,插入数据的位置
private void initTemplate(){
sheet=wb.getSheetAt(0);
initConfigData();
lastRowIndex = sheet.getLastRowNum();
curRow=sheet.getRow(curRowIndex);
}
/**
* 循环遍历,找到有datas字符的那个单元,记录initColIndex,initRowIndex,curColIndex,curRowIndex
* 调用initStyles()方法
* 在寻找datas字符的时候会顺便找一下sernums,如果有则记录其列号serColIndex;如果没有则调用initSer()方法,重新循环查找
*/
private void initConfigData() {
boolean findData=false;
boolean findSer = false;
for(Row row : sheet){
if(findData) break;
for(Cell c: row){
if(c.getCellType()!=Cell.CELL_TYPE_STRING) continue;
String str=c.getStringCellValue().trim();
if(str.equals(SER_NUM)){
serColIndex=c.getColumnIndex();
findSer=true;
}
if(str.equals(DATA_LINE)){
initColIndex=c.getColumnIndex();
initRowIndex=row.getRowNum();
curColIndex=initColIndex;
curRowIndex=initRowIndex;
findData=true;
break;
}
}
}
if(!findSer){
initSer();
}
initStyles();
}
/**
* 初始化序号位置
*/
private void initSer() {
for(Row row:sheet) {
for(Cell c:row) {
if(c.getCellType()!=Cell.CELL_TYPE_STRING) continue;
String str = c.getStringCellValue().trim();
if(str.equals(SER_NUM)) {
serColIndex = c.getColumnIndex();
}
}
}
}
/**
* 初始化样式信息
*/
private void initStyles(){
styles = new HashMap();
for(Row row:sheet) {
for(Cell c:row) {
if(c.getCellType()!=Cell.CELL_TYPE_STRING) continue;
String str = c.getStringCellValue().trim();
if(str.equals(DEFAULT_STYLE)) {
defaultStyle = c.getCellStyle();
rowHeight=row.getHeightInPoints();
}
if(str.equals(STYLE)||str.equals(SER_NUM)) {
styles.put(c.getColumnIndex(), c.getCellStyle());
}
}
}
}
2.3 新建excel并向其写数据
public void writeToFile(String filepath){
FileOutputStream fos=null;
try {
fos=new FileOutputStream(filepath);
wb.write(fos);
} catch (FileNotFoundException e) {
e.printStackTrace();
throw new RuntimeException("写入的文件不存在"+e.getMessage());
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("写入数据失败"+e.getMessage());
} finally{
if(fos!=null)
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.4 实现Excel公共模板的第一步(实现了数据插入)
下面是创建单元格的方法,以及重载方法
public void createCell(String value){
Cell c =curRow.createCell(curColIndex);
setCellStyle(c);
c.setCellValue(value);
curColIndex++;
}
public void createCell(int value) {
Cell c = curRow.createCell(curColIndex);
setCellStyle(c);
c.setCellValue((int)value);
curColIndex++;
}
public void createCell(Date value) {
Cell c = curRow.createCell(curColIndex);
setCellStyle(c);
c.setCellValue(value);
curColIndex++;
}
public void createCell(double value) {
Cell c = curRow.createCell(curColIndex);
setCellStyle(c);
c.setCellValue(value);
curColIndex++;
}
public void createCell(boolean value) {
Cell c = curRow.createCell(curColIndex);
setCellStyle(c);
c.setCellValue(value);
curColIndex++;
}
public void createCell(Calendar value) {
Cell c = curRow.createCell(curColIndex);
setCellStyle(c);
c.setCellValue(value);
curColIndex++;
}
上面的方法会调用setCellStyle方法来设置单元格样式
/**
* 设置某个单元格的样式
* @param c
*/
private void setCellStyle(Cell c) {
if(styles.containsKey(c.getColumnIndex())) {
c.setCellStyle(styles.get(c.getColumnIndex()));
} else {
c.setCellStyle(defaultStyle);
}
}
createNewRow方法用于创建新的行,新的行的位置位于curRowIndex,从curRowIndex到lastRowIndex的所有行会自动向下移动一行。
public void createNewRow(){
if(lastRowIndex>curRowIndex&&curRowIndex!=initRowIndex) {
sheet.shiftRows(curRowIndex, lastRowIndex, 1,true,true);
lastRowIndex++;
}
curRow = sheet.createRow(curRowIndex);
curRow.setHeightInPoints(rowHeight);
curRowIndex++;
curColIndex=initColIndex;
}
2.5 实现增加序号
/**
* 插入序号,会自动找相应的序号标示的位置完成插入
*/
public void insertSer() {
int index = 1;
Row row = null;
Cell c = null;
for(int i=initRowIndex;i
2.6 替换模板中#开头的值
/**
* 根据map替换相应的常量,通过Map中的值来替换#开头的值
* @param datas
*/
public void replaceFinalData(Map datas) {
if(datas==null) return;
for(Row row:sheet) {
for(Cell c:row) {
if(c.getCellType()!=Cell.CELL_TYPE_STRING) continue;
String str = c.getStringCellValue().trim();
if(str.startsWith("#")) {
if(datas.containsKey(str.substring(1))) {
c.setCellValue(datas.get(str.substring(1)));
}
}
}
}
}
3实现步骤
@Test
public void test01() {
ExcelTemplate et = ExcelTemplate.getInstance()
.readTemplateByClasspath("/excel/default.xls");
et.createNewRow();
et.createCell("1111111");
et.createCell("aaaaaaaaaaaa");
et.createCell("a1");
et.createCell("a2a2");
et.createNewRow();
et.createCell("222222");
et.createCell("bbbbb");
et.createCell("b");
et.createCell("dbbb");
et.createNewRow();
et.createCell("3333333");
et.createCell("cccccc");
et.createCell("a1");
et.createCell(12333);
et.createNewRow();
et.createCell("4444444");
et.createCell("ddddd");
et.createCell("a1");
et.createCell("a2a2");
et.createNewRow();
et.createCell("555555");
et.createCell("eeeeee");
et.createCell("a1");
et.createCell(112);
et.createNewRow();
et.createCell("555555");
et.createCell("eeeeee");
et.createCell("a1");
et.createCell("a2a2");
et.createNewRow();
et.createCell("555555");
et.createCell("eeeeee");
et.createCell("a1");
et.createCell("a2a2");
et.createNewRow();
et.createCell("555555");
et.createCell("eeeeee");
et.createCell("a1");
et.createCell("a2a2");
et.createNewRow();
et.createCell("555555");
et.createCell("eeeeee");
et.createCell("a1");
et.createCell("a2a2");
et.createNewRow();
et.createCell("555555");
et.createCell("eeeeee");
et.createCell("a1");
et.createCell("a2a2");
et.createNewRow();
et.createCell("555555");
et.createCell("eeeeee");
et.createCell("a1");
et.createCell("a2a2");
Map datas = new HashMap();
datas.put("title","测试用户信息");
datas.put("date","2012-06-02 12:33");
datas.put("dep","昭通师专财务处");
et.replaceFinalData(datas);
et.insertSer();
et.writeToFile("d:/test/poi/test01.xls");
}
4 最后结果