</pre>导出报表 ireport 与 poi <p></p><p></p><p>项目需要,制作各种表格,尝试了这两种报表工具,ireport 与poi 都能完成你想要的表格,功能都很强大。</p><p></p><p>1. 配置</p><p> ireport 必须安装ireport 客户端,具体可以参考网上资源。而poi 没有这个步骤。当然都需要在intellij (或eclipse)上导包,pom.xml 中配置,版本号对应下载的包是同一给版本。</p><p></p><p>2. 写查询语句</p><p>ireport 即在其客户端写查询语句,并按照需求编排字段,这个步骤比较花时间,一点点不对齐都会导致导出的excel 表格行列不一致,工具上可以预览导出表格的样式,也可以直接在工具上导出报表,这也是这个工具最大的用处吧,只要会sql语句,就可以制作各种表格,对其他非java编程工作人员导出报表很实用。具体操作可以参考相关教程。完成表格制作后将编译好的两个文件(.jasper,.jrxml)复制放到 intellij 资源路径下。</p><p></p><p>ireport 需要在mapper 中写查询语句,这个其实在页面端需求时已经写好,直接调用即可。</p><p></p><p>3. 后台程序编写</p><p> ireport 后台程序比较简单,将ireport 导出报表需要的参数 组装好传进去即可,直接上例子:</p><p></p><pre code_snippet_id="1579867" snippet_file_name="blog_20160216_2_5403460" name="code" class="java"> public Object exportDetailExcelByIreport(HttpServletRequest request, HttpServletResponse response, String date, String cid) {
String exportFileName = "districtDetailCount"+System.currentTimeMillis()+".xls";
String jasperFilePath = this.getClass().getResource("/").getPath()+"/"+"ireport/reportDistrict.jasper";
Map<String, Object> params = new HashMap<>();
List<!-- <Map> --> selectDistrictData = countDistrictService.searchDistrictDetail(date,cid);
List<!-- <Map> --> districtDetail = countDistrictService.searchDistrictNameById(Integer.parseInt(cid));
double totalNet = 0;
for (int i=0;i<selectDistrictData.size();i++){
totalNet += Double.parseDouble(selectDistrictData.get(i).get("net").toString());
}
params.put("date_month","2015-07");
params.put("net_total", totalNet);
params.put("district_name","桂城街道");
Map result = IReportUtils.exportByDataBaseConnection(request,response,params,exportFileName,jasperFilePath);
return sendResult(ResultCode.CODE_200.code,ResultCode.CODE_200.msg,result);
}
poi 后台程序 逻辑很清晰,从数据库取数据一行行将数据存储到excel表格的行中,代码如下:
public Object exportDetailExcel(HttpServletRequest request, String date, String cid) {
Map<String, Object> result = new HashMap<>();
String path = PathKit.getWebRootPath()+"/upload/file/";
File pathFile = new File(path);
String districtNameList = countDistrictService.searchDistrictNameById(Integer.parseInt(cid));
String title = districtNameList+"收运量统计表"+System.currentTimeMillis();
List<Map> districtData = countDistrictService.searchDistrictDetail(date,cid);
File newFile = new File(path+title+".xls");
try{
if(!pathFile.exists()){
pathFile.mkdirs();
}
newFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
try{
FileOutputStream fos = new FileOutputStream(newFile);
if (!districtData.isEmpty()&&districtData.size()>0){
String[] headers = getDistrictHeaders();
String[] titleHead = getDistrictTitle(date,cid);
Collection<List<String>> dataSet = getDistrictDetailDataSet(districtData);
exportExcel(title,titleHead,headers,dataSet,fos,null);
}else {
return sendResult(ResultCode.CODE_405.code,ResultCode.CODE_405.msg,null);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
return sendResult(ResultCode.CODE_401.code,ResultCode.CODE_401.msg,null);
}
System.out.println(request.getRequestURL().toString());
String url = request.getRequestURL().toString().replace("/ctrl/districtCount/exportDistrictDetail","")+"/upload/file/"+title+".xls";
result.put("url",url);
return sendResult(ResultCode.CODE_200.code,ResultCode.CODE_200.msg,result);
}
4.输出excel表格比较
首先需要说明的是,笔者对ireport的使用仅仅只是初步认识和阶段,ireport的强大之处并没有深入研究,笔者使用ireport 导出的excel表格并没有达到预想的结果,主要有以下几点,
一,整个页面背景为白色,而不是透明显示,使用最笨的方法是通过在ireport中设置页面边距来,来使不存在数据的页面边界透明显示。调试ireport到合适的页面大小很苦逼,如果是动态的数据就更是不可取。不知道还有没有别的方法能达到效果。这也使不得不放弃ireport。
二,导出的excel表格中的斜线无法显示
三,动态数据表格中实现合并单元格功能无法实现;在实际项目需求中,尤其是在动态数据中需要对动态的数据进行合并单元格操作,在ireport中找不到解决的方法。
使用poi完全可以随心所欲的去设计表格,相同格式的excel表格可以公用一个方法,传入不同的参数即可;当遇到格式复杂的表格(例如复杂表头),可以单独重写方法。在ireport中出现的问题,poi都能得到完美解决。
5.综上所述,项目的需求,以及各自的优缺点,笔者最终选择了poi。个人觉得ireport还是比较适合非开发人员去完成表格的导出功能,在ireport中直接导出的表格还是很不错,操作简单,一般的非开发人员使用ireport可以得到需要的各种excel表格,或者pdf格式文档。poi插件可以适合任意excel表格的输出,完全满足开发需求。
一、 POI简介
Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式档案读和写的功能。
二、 HSSF概况
HSSF 是Horrible SpreadSheet Format的缩写,通过HSSF,你可以用纯Java代码来读取、写入、修改Excel文件。HSSF 为读取操作提供了两类API:usermodel和eventusermodel,即“用户模型”和“事件-用户模型”。
三、 POI EXCEL文档结构类
HSSFWorkbook excel文档对象
HSSFSheet excel的sheet HSSFRow excel的行
HSSFCell excel的单元格 HSSFFont excel字体
HSSFName 名称 HSSFDataFormat 日期格式
HSSFHeader sheet头
HSSFFooter sheet尾
HSSFCellStyle cell样式
HSSFDateUtil 日期
HSSFPrintSetup 打印
HSSFErrorConstants 错误信息表
四、 EXCEL常用操作方法
1、 得到Excel常用对象
- POIFSFileSystem fs=newPOIFSFileSystem(new FileInputStream("d:/test.xls"));
- //得到Excel工作簿对象
- HSSFWorkbook wb = new HSSFWorkbook(fs);
- //得到Excel工作表对象
- HSSFSheet sheet = wb.getSheetAt(0);
- //得到Excel工作表的行
- HSSFRow row = sheet.getRow(i);
- //得到Excel工作表指定行的单元格
- HSSFCell cell = row.getCell((short) j);
- cellStyle = cell.getCellStyle();//得到单元格样式
- POIFSFileSystem fs=newPOIFSFileSystem(new FileInputStream("d:/test.xls"));
- //得到Excel工作簿对象
- HSSFWorkbook wb = new HSSFWorkbook(fs);
- //得到Excel工作表对象
- HSSFSheet sheet = wb.getSheetAt(0);
- //得到Excel工作表的行
- HSSFRow row = sheet.getRow(i);
- //得到Excel工作表指定行的单元格
- HSSFCell cell = row.getCell((short) j);
- cellStyle = cell.getCellStyle();//得到单元格样式
2、建立Excel常用对象
- HSSFWorkbook wb = new HSSFWorkbook();//创建Excel工作簿对象
- HSSFSheet sheet = wb.createSheet("new sheet");//创建Excel工作表对象
- HSSFRow row = sheet.createRow((short)0); //创建Excel工作表的行
- cellStyle = wb.createCellStyle();//创建单元格样式
- row.createCell((short)0).setCellStyle(cellStyle); //创建Excel工作表指定行的单元格
- row.createCell((short)0).setCellValue(1); //设置Excel工作表的值
- HSSFWorkbook wb = new HSSFWorkbook();//创建Excel工作簿对象
- HSSFSheet sheet = wb.createSheet("new sheet");//创建Excel工作表对象
- HSSFRow row = sheet.createRow((short)0); //创建Excel工作表的行
- cellStyle = wb.createCellStyle();//创建单元格样式
- row.createCell((short)0).setCellStyle(cellStyle); //创建Excel工作表指定行的单元格
- row.createCell((short)0).setCellValue(1); //设置Excel工作表的值
3、设置sheet名称和单元格内容
- wb.setSheetName(1, "第一张工作表",HSSFCell.ENCODING_UTF_16);
- cell.setEncoding((short) 1);
- cell.setCellValue("单元格内容");
- wb.setSheetName(1, "第一张工作表",HSSFCell.ENCODING_UTF_16);
- cell.setEncoding((short) 1);
- cell.setCellValue("单元格内容");
4、取得sheet的数目
- wb.getNumberOfSheets()
- wb.getNumberOfSheets()
5、 根据index取得sheet对象
- HSSFSheet sheet = wb.getSheetAt(0);
- HSSFSheet sheet = wb.getSheetAt(0);
6、取得有效的行数
- int rowcount = sheet.getLastRowNum();
- int rowcount = sheet.getLastRowNum();
7、取得一行的有效单元格个数
- row.getLastCellNum();
- row.getLastCellNum();
8、单元格值类型读写
- cell.setCellType(HSSFCell.CELL_TYPE_STRING); //设置单元格为STRING类型
- cell.getNumericCellValue();//读取为数值类型的单元格内容
9、设置列宽、行高
- sheet.setColumnWidth((short)column,(short)width);
- row.setHeight((short)height);
10、添加区域,合并单元格
- Region region = new Region((short)rowFrom,(short)columnFrom,(short)rowTo
- ,(short)columnTo);//合并从第rowFrom行columnFrom列
- sheet.addMergedRegion(region);// 到rowTo行columnTo的区域
- //得到所有区域
- sheet.getNumMergedRegions()
11、保存Excel文件
- FileOutputStream fileOut = new FileOutputStream(path);
- wb.write(fileOut);
12、根据单元格不同属性返回字符串数值
- public String getCellStringValue(HSSFCell cell) {
- String cellValue = "";
- switch (cell.getCellType()) {
- case HSSFCell.CELL_TYPE_STRING://字符串类型
- cellValue = cell.getStringCellValue();
- if(cellValue.trim().equals("")||cellValue.trim().length()<=0)
- cellValue=" ";
- break;
- case HSSFCell.CELL_TYPE_NUMERIC: //数值类型
- cellValue = String.valueOf(cell.getNumericCellValue());
- break;
- case HSSFCell.CELL_TYPE_FORMULA: //公式
- cell.setCellType(HSSFCell.CELL_TYPE_NUMERIC);
- cellValue = String.valueOf(cell.getNumericCellValue());
- break;
- case HSSFCell.CELL_TYPE_BLANK:
- cellValue=" ";
- break;
- case HSSFCell.CELL_TYPE_BOOLEAN:
- break;
- case HSSFCell.CELL_TYPE_ERROR:
- break;
- default:
- break;
- }
- return cellValue;
- }
13、常用单元格边框格式
- HSSFCellStyle style = wb.createCellStyle();
- style.setBorderBottom(HSSFCellStyle.BORDER_DOTTED);//下边框
- style.setBorderLeft(HSSFCellStyle.BORDER_DOTTED);//左边框
- style.setBorderRight(HSSFCellStyle.BORDER_THIN);//右边框
- style.setBorderTop(HSSFCellStyle.BORDER_THIN);//上边框
14、设置字体和内容位置
- HSSFFont f = wb.createFont();
- f.setFontHeightInPoints((short) 11);//字号
- f.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);//加粗
- style.setFont(f);
- style.setAlignment(HSSFCellStyle.ALIGN_CENTER);//左右居中
- style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);//上下居中
- style.setRotation(short rotation);//单元格内容的旋转的角度
- HSSFDataFormat df = wb.createDataFormat();
- style1.setDataFormat(df.getFormat("0.00%"));//设置单元格数据格式
- cell.setCellFormula(string);//给单元格设公式
- style.setRotation(short rotation);//单元格内容的旋转的角度
15、插入图片
- //先把读进来的图片放到一个ByteArrayOutputStream中,以便产生ByteArray
- ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
- BufferedImage bufferImg = ImageIO.read(new File("ok.jpg"));
- ImageIO.write(bufferImg,"jpg",byteArrayOut);
- //读进一个excel模版
- FileInputStream fos = new FileInputStream(filePathName+"/stencil.xlt");
- fs = new POIFSFileSystem(fos);
- //创建一个工作薄
- HSSFWorkbook wb = new HSSFWorkbook(fs);
- HSSFSheet sheet = wb.getSheetAt(0);
- HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
- HSSFClientAnchor anchor = new HSSFClientAnchor(0,0,1023,255,(short) 0,0,(short)10,10);
- patriarch.createPicture(anchor , wb.addPicture(byteArrayOut.toByteArray(),HSSFWorkbook.PICTURE_TYPE_JPEG));
16、调整工作表位置
- HSSFWorkbook wb = new HSSFWorkbook();
- HSSFSheet sheet = wb.createSheet("format sheet");
- HSSFPrintSetup ps = sheet.getPrintSetup();
- sheet.setAutobreaks(true);
- ps.setFitHeight((short)1);
- ps.setFitWidth((short)1);
17、设置打印区域
- HSSFSheet sheet = wb.createSheet("Sheet1");
- wb.setPrintArea(0, "$A$1:$C$2");
18、标注脚注
- HSSFSheet sheet = wb.createSheet("format sheet");
- HSSFFooter footer = sheet.getFooter()
- footer.setRight( "Page " + HSSFFooter.page() + " of " + HSSFFooter.numPages() );
19、在工作单中清空行数据,调整行位置
- HSSFWorkbook wb = new HSSFWorkbook();
- HSSFSheet sheet = wb.createSheet("row sheet");
- // Create various cells and rows for spreadsheet.
- // Shift rows 6 - 11 on the spreadsheet to the top (rows 0 - 5)
- sheet.shiftRows(5, 10, -5);
20、选中指定的工作表
- HSSFSheet sheet = wb.createSheet("row sheet");
- heet.setSelected(true);
21、工作表的放大缩小
- HSSFSheet sheet1 = wb.createSheet("new sheet");
- sheet1.setZoom(1,2); // 50 percent magnification
22、头注和脚注
- HSSFSheet sheet = wb.createSheet("new sheet");
- HSSFHeader header = sheet.getHeader();
- header.setCenter("Center Header");
- header.setLeft("Left Header");
- header.setRight(HSSFHeader.font("Stencil-Normal", "Italic") +
- HSSFHeader.fontSize((short) 16) + "Right w/ Stencil-Normal Italic font and size 16");
23、自定义颜色
- HSSFCellStyle style = wb.createCellStyle();
- style.setFillForegroundColor(HSSFColor.LIME.index);
- style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
- HSSFFont font = wb.createFont();
- font.setColor(HSSFColor.RED.index);
- style.setFont(font);
- cell.setCellStyle(style);
24、填充和颜色设置
- HSSFCellStyle style = wb.createCellStyle();
- style.setFillBackgroundColor(HSSFColor.AQUA.index);
- style.setFillPattern(HSSFCellStyle.BIG_SPOTS);
- HSSFCell cell = row.createCell((short) 1);
- cell.setCellValue("X");
- style = wb.createCellStyle();
- style.setFillForegroundColor(HSSFColor.ORANGE.index);
- style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
- cell.setCellStyle(style);
25、强行刷新单元格公式
- HSSFFormulaEvaluator eval=new HSSFFormulaEvaluator((HSSFWorkbook) wb);
- private static void updateFormula(Workbook wb,Sheet s,int row){
- Row r=s.getRow(row);
- Cell c=null;
- FormulaEcaluator eval=null;
- if(wb instanceof HSSFWorkbook)
- eval=new HSSFFormulaEvaluator((HSSFWorkbook) wb);
- else if(wb instanceof XSSFWorkbook)
- eval=new XSSFFormulaEvaluator((XSSFWorkbook) wb);
- for(int i=r.getFirstCellNum();i<r.getLastCellNum();i++){
- c=r.getCell(i);
- if(c.getCellType()==Cell.CELL_TYPE_FORMULA)
- eval.evaluateFormulaCell(c);
- }
- }
说明:FormulaEvaluator提供了evaluateFormulaCell(Cell cell)方法,计算公式保存结果,但不改变公式。而evaluateInCell(Cell cell) 方法是计算公式,并将原公式替换为计算结果,也就是说该单元格的类型不在是Cell.CELL_TYPE_FORMULA而是Cell.CELL_TYPE_NUMBERIC。HSSFFormulaEvaluator提供了静态方法evaluateAllFormu
laCells(HSSFWorkbook wb) ,计算一个Excel文件的所有公式,用起来很方便。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------poi方法总结
-.设置不显示excel网格线
sheet.setDisplayGridlines(false);其中sheet是Sheet对象
2.设置excel单元格中的内容换行
cellStyle.setWrapText(true);其中cellStyle是WorkBook创建的CellStyle对象,然后将cellStyle设置到要换行的Cell对象,最后在要换行的对象(一般为字符串)加入"/r/n"。如
topTile.append("/r/n" +"cellContent");
3.单元格的合并
sheet.addMergedRegion(new CellRangeAddress(0, 4, 0, 2));本示例为合并4行2列
4.设置页眉和页脚的页数
HSSFHeader header = sheet.getHeader();
header.setCenter("Center Header");
header.setLeft("Left Header");
header.setRight(HSSFHeader.font("Stencil-Normal", "Italic") +
HSSFHeader.fontSize((short) 16) + "Right w/ Stencil-Normal Italic font and size 16");
HSSFFooter footer = (HSSFFooter )sheet.getFooter()
footer.setRight( "Page " + HSSFFooter.page() + " of " + HSSFFooter.numPages() );
5.使得一个Sheet适合一页
sheet.setAutobreaks(true);
6.设置放大属性(Zoom被明确为一个分数,例如下面的75%使用3作为分子,4作为分母)
sheet.setZoom(3,4);
7.设置打印
HSSFPrintSetup print = (HSSFPrintSetup) sheet.getPrintSetup();
print.setLandscape(true);//设置横向打印
print.setScale((short) 70);//设置打印缩放70%
print.setPaperSize(HSSFPrintSetup.A4_PAPERSIZE);//设置为A4纸张
print.setLeftToRight(true);//設置打印顺序先行后列,默认为先列行
print.setFitHeight((short) 10);设置缩放调整为10页高
print.setFitWidth((short) 10);设置缩放调整为宽高
sheet.setAutobreaks(false);
if (i != 0 && i % 30 == 0)
sheet.setRowBreak(i);//設置每30行分頁打印
8.反复的行和列(设置打印标题)
HSSFWorkbook wb = new HSSFWorkbook();
wb.setRepeatingRowsAndColumns(0, 0, 12, 1, 6);//设置1到12列,行1到6每一页重复打印
9.调整单元格宽度
sheet.setAutobreaks(true);
sheet.setColumnWidth((short)i,colsWidth[i]); //设定单元格长度
sheet.autoSizeColumn((short) i);//自动根据长度调整单元格长度