从事JAVA开发一年多了,大约有半年都在搞Excel导入导出吧.刚刚交接项目时,还是个对Java有些陌生,有些惧怕的.但是因为人都走光了,项目中只有咱一个开发了,只能担起全部的开发维护责任,也慢慢成长了起来.项目中以前的Excel导出用的JXL,因为客户的特殊需求,导出并非平时那么简单,涉及到分页(每sheet一页),还要将数据合并.架构师写了分页的代码,并写了某个报表的导出类,然后其他工程师CV,即便对于当时没多少经验的我来说,这也很没意思,很不好,但是事已至此,我也就只能随波逐流了.
直到到某一天,客户提出了由于政策变更要重新制作一套报表的需求,我才意识到问题的严重性,这样一个类一个类的改,不止麻烦,而且要实现客户的那些格式要求(如某列需要加粗,某单元格有上下左边框等等)都十分麻烦,还会大大增加代码复杂度(需要在各种循环里判断),于是萌生了重新构架导出功能的想法.
--------------------以上为发泄心情,可以忽略不看--------------------
做java的必然要有面向对象的意识,万物皆为对象,报表亦如此.一个Excel报表,我将其分为七个部分,那就是首页头信息(只出现在第一页),头信息(每页都有),动态信息,尾信息(每页都有),尾页尾信息(只出现在最后一页),统计信息(所有数据之后的那行),页码信息(位置不固定).如下图所示:
参考了hibernate的orm思想,将excel与对象映射起来,但由于早期,并不会写DTD,于是就用某类的静态成员变量来充当配置文件.报表中的动态信息需要用一个集合来表示,集合中的每个对象代表Excel中动态信息的一行,每个成员变量代表Excel中的一个单元格.其他的头尾信息之类,可以用一个对象来表示.下面简要的介绍一下整体思路.
首先,我们需要准备好模板,用JXL读取模板,并将其sheet复制一份出来,在新的sheet上输出数据,以免影响到模板上的原有数据.之后,当然是根据情况分页,将数据分成几个list,每个list代表一页的数据,然后循环输出,自然循环中的控制变量i就成了页码.对于i为0的时候也就是第一页,要将首页头信息输出,其他的情况下,则要把首页头信息的内容清空(模板上写的那部分).之后输出相应的头信息动态信息尾信息,之后需要判断是否是最后一页,对于最后一页我们需要输出尾页尾信息,其他页我们需要清空模板中的尾页尾信息.这样报表摸板便完成了,不敢说这样可以应对任何报表,但是对于多数报表,我们以后要做的只是配置七大部分的格式,与对象的映射,就足够产生一个xls文件了.
以下便是核心代码部分的简要的介绍.
// 读取模板 tempBook = Workbook.getWorkbook(new File(inPath), workbookSettings); // 创建目标对象 book = Workbook.createWorkbook(new File(outPath), tempBook); WritableSheet copySheet=book.getSheet(0); WritableSheet sheet=null; //拆分动态数据集 List[] lists; //没有动态数据 if(report.getDynamic()==null) { book.copySheet(0,report.getName(), 1); sheet=book.getSheet(1); //填充静态数据的方法参数3代表对应的输出对象,参数4为包含配置的对象,参数5为相对位置,参数6页码 fillStaticData(sheet, copySheet, staticData, report.getFirsthead(), 0,1); } else { //分页 lists=paging(dynamicData); int position=0;//相对位置 for(int i=0;i<lists.length;i++) { position=0; book.copySheet(0,report.getName(),i+1);//复制新sheet sheet=book.getSheet(i+1); if(report.getFirsthead()!=null)//首页 { if(i==0)//输出首页头信息 { position+=fillStaticData(sheet, copySheet,staticData, report.getFirsthead(),0, i); } else //清空头信息 { JXXUtil.cutRange(sheet, 0, 0, report.getFirsthead().getRows(), report.getFirsthead().getColumns()); JXXUtil.blankRange(sheet, 0, 0, report.getFirsthead().getRows(), report.getFirsthead().getColumns()); } } //输出头信息 position+=fillStaticData(sheet, copySheet,staticData, report.getAllhead(),position, i); if(report.getDynamic().getStartRow()!=0) { position=report.getDynamic().getStartRow(); } //写入动态数据 fillDynamicCell(sheet, copySheet, lists[i], position, report.getDynamic()); //相对位置的计算 position+=lists[i].size(); if(i!=lists.length-1)//末页 { if(report.getLasttail()!=null) { JXXUtil.cutRange(sheet, position+1, 0,position+1+report.getLasttail().getRows(), report.getLasttail().getColumns()); JXXUtil.blankRange(sheet,position+1, 0,position+1+report.getLasttail().getRows(), report.getLasttail().getColumns()); } } position+=fillStaticData(sheet, copySheet,staticData, report.getAlltail(),position, i); if(report.getLasttail()!=null) { if(i==lists.length-1)//末页 { fillStaticData(sheet, copySheet,staticData, report.getLasttail(),position, i); } } } } book.removeSheet(0); book.write(); tempBook.close(); book.close();
具体的实现以及JXL处理Excel上的一些困难,以后都会一一介绍,这次就写到这了.