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 Mapstyles; /** * 序号的列 */ 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<currowindex;i++) {="" row="sheet.getRow(i);" c="row.createCell(serColIndex);" setcellstyle(c);="" c.setcellvalue(index++);="" }="" }
|
|