入职后参与的第一个项目是“烟草GIS项目”,分配给我的任务参主要是用户对系统数据Excel格式的录入和导出,满足此项需求可以在很大程度上为用户在项目外对数据的处理中提供很大便利,使其可以利用Excel的强大功能来实现一些统计运算,但是java自带的API中并没有直接操作Excel表格的的方法,为解决问题,只能借助第三方的解决方案。
根据了解所知,在java处理Excel领域已经存在很多的开源解决方案,其中比较突出的有ApachePOI和JExcelApi(jxl)。
*Apache是世界上使用排名第一的Web服务器软件,它的跨平台和安全性使其成为最流行的Web服务器软件之一,ApachePOI是Apache基金组织Jakarta项目的子项目,它包括一系列的API,可以操作多种格式的Microsoft Office文件,通过这些API使java更方便的操作Excel、Word等格式的Office文件
*JExcelApi(jxl)是一个韩国人写的java操作Excel的工具,名气虽然逊于ApachePOI,但同样有自己的的特色
功能上POI要强一些,对于图形图表的支持更完善,但是JExcelApi(jxl)对于以下方面有着明显的优势:1、合并单元格加边框问题;2、中文乱码问题等等
接下来要记录的就是用ApachePOI对Excel的基本操作:
我把项目中对Excel操作划分为三大部分:1、生成Excel模板,方便用户导出后填充;2、完善Excel表格,数据导入处理;3、读取数据库数据,Excel格式导出数据。本文章中记录是对模板生成导出的分析整理
* 模板导出
接下来我会以“个人信息”的excel为例,为大家做示范(如图1.1所示),虽然这只是一个最简单的模板,但是复杂的模板无非是在基础上的堆积,可能多些麻烦,但是基本作法大体都是雷同的
图1.1
首先先阐述需要到处模板的样式和要求(如图1.1所示):
一、模板有3行标题栏(即:方便用户观看,但是读取时不会读取的行);
二、模板中第1行占据5列;
三、模板中1、3、5列的第2行和第3行都是合并的;
四、模板中第2行的3、4列是合并的;
五、特殊要求:(很有效,也很常用)
部门只有固定的几个,为避免录入时录入不明确、模糊信息,模板中设定部门一列中有个选择框,设定只能选择(“研发部”,“财务部”,“工程部”)
六、留给用户填写的空的表格;
七、标题栏的字体多为宋体、加粗;
八、标题栏中和填充栏中都无底色;
九、能够导出,导出存放位置自选;(这点很关键,是个小技巧,但我查了好多资料,关键是查询时不会表述)
下面我们进行代码编写
1、导入要用到的ApachePOI的jar包,我导入的有下图中的这些:
2、我们先来实现纯java语言来实现生成excel并导出到指定位置
(ApachePOI将Excel划分为HSSFWorkBook、HSSFSheet、HSSFRow、HSSFCell几部分,按部就班的填充即可)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public boolean createExcelModel()throws Exception{ 2 //这是基本步骤,创建一个工作簿,在工作簿上创建一页并命名 3 HSSFWorkBook excel=new HSSFWorkBook(); 4 HSSFSheet sheet=excel.createSheet(); 5 excel.setSheetName(0, "个人信息模板"); 6 //创建第一列的样式 7 HSSFCellStyle style=excel.createCellStyle(); 8 style.setAlignment(HSSFCellStyle.ALIGN_CENTER); style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); style.setBorderBottom(HSSFCellStyle.BORDER_MEDIUM); 9 style.setBorderLeft(HSSFCellStyle.BORDER_MEDIUM); 10 style.setBorderRight(HSSFCellStyle.BORDER_MEDIUM); 11 style.setBorderTop(HSSFCellStyle.BORDER_MEDIUM); 12 //创建第一格中字体样式 13 HSSFFont font=model.createFont(); 14 font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); 15 //将设置的字体样式加入单元格样式中 16 style.setFont(font); 17 //创建第一格单元格,并将之前设置的样式加入 18 HSSFRow row=sheet.createRow((short)0); 19 HSSFCell cell=row.createCell((short)0); 20 cell.setCellValue("个人信息录入"); 21 cell.setCellStyle(style); 22 //这个地方加入每个列都是“”,并不是没有用处的 23 //POI对于合并后边框问题处理并不好,这样更美观些,也可能有其他办法 24 HSSFCell cella=null; 25 for (int i = 1; i < 5; i++) { 26 cella=row.createCell((short)i); 27 cella.setCellValue(""); 28 cella.setCellStyle(style); 29 } 30 //设置接下来两行标题的样式 31 HSSFCellStyle styleTitle=excel.createCellStyle(); 32 //加边框 styleTitle.setBorderBottom(HSSFCellStyle.BORDER_MEDIUM); 33 styleTitle.setBorderLeft(HSSFCellStyle.BORDER_MEDIUM); styleTitle.setBorderRight(HSSFCellStyle.BORDER_MEDIUM); 34 styleTitle.setBorderTop(HSSFCellStyle.BORDER_MEDIUM); 35 HSSFFont fontTitle = model.createFont(); 36 fontTitle.setBoldweight((short) 10);// 设置字体的宽度 37 fontTitle.setFontHeightInPoints((short) 10);// 设置字体的高度 38 fontTitle.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);// 粗体显示 39 styleTitle.setFont(fontTitle);// 设置style1的字体 40 styleTitle.setWrapText(true);// 设置自动换行 41 // 设置单元格字体显示居中(左右方向) 42 styleTitle.setAlignment(HSSFCellStyle.ALIGN_CENTER); 43 // 设置单元格字体显示居中(上下方向) styleTitle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); 44 //创建第二行,并将上面设置的标题样式加入 45 HSSFRow rowTitle=sheet.createRow((short)1); 46 //第二行四列数据 47 HSSFCell cellNum=rowTitle.createCell((short)0); 48 cellNum.setCellValue("编号"); 49 cellNum.setCellStyle(styleTitle); 50 HSSFCell cellName=rowTitle.createCell((short)1); 51 cellName.setCellValue("姓名"); 52 cellName.setCellStyle(styleTitle); 53 HSSFCell cellMsg=rowTitle.createCell((short)2); 54 cellMsg.setCellValue("验证信息"); 55 cellMsg.setCellStyle(styleTitle); 56 HSSFCell cellDept=rowTitle.createCell((short)4); 57 cellDept.setCellValue("部门"); 58 cellDept.setCellStyle(styleTitle); 59 //第三行两列数据 60 HSSFRow rowAT=sheet.createRow((short)2); 61 HSSFCell cellS=null; 62 for (int i = 0; i < 2; i++) { 63 cellS=rowAT.createCell((short)i); 64 cellS.setCellValue(""); 65 cellS.setCellStyle(styleTitle); 66 } 67 HSSFCell cellSss=rowAT.createCell((short)2); 68 cellSss.setCellValue("密码"); 69 cellSss.setCellStyle(styleTitle); 70 HSSFCell cellCard=rowAT.createCell((short)3); 71 cellCard.setCellValue("身份证号"); 72 cellCard.setCellStyle(styleTitle); 73 HSSFCell cellD=rowAT.createCell((short)4); 74 cellD.setCellValue(""); 75 cellD.setCellStyle(styleTitle); 76 //将标题的合并合并起来 77 Region region=null; 78 region=new Region((short)0,(short)0,(short)0,(short)4); 79 sheet.addMergedRegion(region); 80 region=new Region((short)1,(short)0,(short)2,(short)0); 81 sheet.addMergedRegion(region); 82 region=new Region((short)1,(short)1,(short)2,(short)1); 83 sheet.addMergedRegion(region); 84 region=new Region((short)1,(short)4,(short)2,(short)4); 85 sheet.addMergedRegion(region); 86 region=new Region((short)1,(short)2,(short)1,(short)3); 87 sheet.addMergedRegion(region); 88 //生成填充表格 89 HSSFRow rowi=null; 90 HSSFCell celli=null; 91 for (int i = 3; i < 10; i++) { 92 rowi=sheet.createRow(i); 93 for (int j = 0; j < 5; j++) { 94 celli=rowi.createCell((short)j); 95 celli.setCellValue(""); 96 celli.setCellStyle(styleTitle); 97 } 98 } 99 for (int i = 0; i < 5; i++) { 100 sheet.setColumnWidth((short) i, (short) 4000); 101 } 102 }
以上代码就生成了Excel模板的雏形,当然不要忘记相应的导包。我们来大体回顾一下代码的基本步骤:
a、生成工作簿,并在工作簿上生成一页并命名;
b、生成一行数据样式;
c、创建一行,并把生成的样式赋给此行;
d、重复b和c两步,生成新的两行,并给予其样式,这样标题栏部分就完成了;
e、Region来完成单元格合并,形成标题栏的正常形式;
f、生成填充栏,并赋予其初始值为“”.
这样我们前面列出的一、二、三、四、六、七和八就都完成了,里面的Region实现合并、HSSFStyle样式中细分类是重点。
备注:Region中(起始行,起始列,终止行、终止列)
3、实现加入下拉列表框功能(在现有基础上补充以下代码),这个地方为固定的,如果想要改变下拉列表框内的值,传递LIST的参数即可。
//设置一个需要提供下拉的区域 String[] list={"研发部","财务部","工程部",}; //确定下拉列表框的位置 CellRangeAddressList regions=new CellRangeAddressList(3,65535,4,4); //生成下拉列表框的内容 DVConstraint constraint=DVConstraint.createExplicitListConstraint(list); //绑定下拉框的作用区域 HSSFDataValidation dataValidate = new HSSFDataValidation(regions, constraint); //对哪一页起作用 sheet.addValidationData(dataValidate)
生成的效果图,如图1.2,这只是个示例图,效果跟这个一样
图1.2
4、这样来看,我们所有的需求只有“导出”一项没有完成了,接下来我们来说说导出。
首先,是最基本最简单的java语言直接导出
1 String path="D:\\test";
//将生成的excel格式文档以流的形式输出 2 FileOutputStream fops=new FileOutputStream(path); 3 excel.write(fops); 4 //输出完成后,关闭流通道 5 fops.close();
另外,如果是想要自己选择下载的位置,那就做如下操作(以jsp+servlet为例):
1 public void doPost(HttpServletRequest request, HttpServletResponse response) 2 throws ServletException, IOException { 3 //添加这个表头,使得可以保存的形式进行导出 4 response.setContentType("application/vnd.ms-excel"); 5 try{ 6 HSSFWorkbook model=new HSSFWorkbook(); 7 //这一部分是在生成的工作簿上做一个excel表格 8 //**这个地方是把生成的工作簿传递给service,在这个工作簿上生成页** 9 //这一部分是数据流的形式还原excel表格 10 //这个地方就不用再加path地址 11 ServletOutputStream out = response.getOutputStream(); 12 model.write(out); 13 //out flush是将缓冲区内的数据,不许等到缓冲区满(自己理解的是缓冲完成)才输出,而是直接输出 14 out.flush(); 15 out.close(); 16 }catch (Exception e) { 17 e.printStackTrace(); 18 } 19 }
该功能的效果图如图1.3所示
图1.3
好了,到此为止,我们想要导出模板的所有需求全部都完成了,现在我们来简单回顾下全部的工作步骤和实现:
a、导入Apache POI的包,为的是用第三方来解决问题,导包是必须滴;
b、生成Excel模板雏形,这里对于region、hssfstyle样式关注比较多,尤其是样式,比较繁琐,像边框、居中、底色、字体等等;
c、下拉列表框的特殊需求,现代人都喜欢干什么都省事,而且实现这个的也能有效避免数据录入错误的几率,有必要做上也好;
d、自主选择导出路径,加上此功能之后在一瞬间感觉项目正规了好多。
这就是我的第一篇博客,经验不多,而且进入软件行业时间不长,理解可能会有些偏颇,写的有点糙,希望大家见谅,如果有我没说到,或者可能会有相关的问题,希望大家能给我留言,大家互相交流,共同进步,接下来我会完成Apache POI实现Excel数据读取和数据库数据放入Excel的博客,谢谢大家。