好久没时间写帖子了,由于工作需要,写一个基于JAVA实现的Excel多表头动态导出功能,首先可能这个叫法比较啰嗦,大家多担待下,下面我们先看看什么是Excel多表头动态导出(效果图):

它包含两部分:1、是表头,就像大家看到的表头是由多行合并的(多表头);2.内容部分,就是下方的数据数据内容。

当然两个内容都是由后台人员,分别由两个接口返回的(也可以一个,但一个会显得格式冗余),一是因为数据是由后天提供,因此他的表头数据是不固定的,所以我们就不能写死,因为表头可能有甲方、乙方、丙方要求等;二是随机看后台数据的,所以我们就不能事先画好Excel模板进行导出,好以上就是我对java实现Excel多表头动态导出的说明。

一、在开发前我们要捋一下思路,该怎么去做?会遇到什么坑?首先不用多说,肯定是这个多表头的问题了,因为后端返回的Json数据一般都为:

不难发现一个list<Map>发现虽然都有一、二级目录的区分,但是是分开的不符合我们的需要,因此我们需要转换分组为想要的数据类型

Map<String, List<Map>>格式的数据:既把同一个一级目录下的二级目录放到一个List<Map>中方便后面的Excel渲染

二、就是在Excel做数据渲染时的数据角标的计算问题,以及如何让经过我们分组后的表头数据与内容匹配上,因为数据是动态生成的,所以在生成数据是一定要注意,后几列的数据再前几列数据生成的基础上向后推的。

三、主要的坑应该就是上面两个问题了,那我们开发撸代码吧:

1、我使用的实现语言是JAVA中的servlet,关于servlet不太熟悉的小伙伴可以百度自行科普一下,简单说就是(1):

集成HttpServlet并实现其几个方法;(2)配置web.xlm文件等。

代码:

/*** 自定义表头导出方法* @throws: l* @param :resultParam 导出excel名称、模板名称、导出地址*/
public void exportExcelByDiyTitle(HttpServletRequest request, HttpServletResponse response)throws IOException{System.out.println("进入自定义导出表头方法");response.reset();// 清空输出流String templateName ="按异常原因统计";//获取导出参数进行查询orgId=06&date=2020-07String orgId = request.getParameter("orgId");//组织IDString date = request.getParameter("date");//日期String type = request.getParameter("type");//日期List<Map<String,Object>> listtitle=null;List<Map<String,Object>> list=null;WorkOrderInforShowService workOrderInforShowService = new WorkOrderInforShowServiceImpl();//这是调用后台Execl表头数据接口listtitle = workOrderInforShowService.getYCLXTypeOfYY(orgId,date);//获取Excell内容数据接口list = workOrderInforShowService.getAppWorkOrderStatisticsOfYY(orgId,date);//设置谷歌和Ie浏览器导出表单乱码问题String userAgent = request.getHeader("User-Agent");if (userAgent.contains("MSIE")||userAgent.contains("Trident")){templateName = java.net.URLEncoder.encode(templateName, "UTF-8");}else{templateName = new String(templateName.getBytes("UTF-8"),"ISO-8859-1");}response.setHeader("Content-disposition", "attachment; filename="+ templateName+ ".xls");// 设定输出文件头response.setContentType("application/msexcel");// 创建一个工作薄HSSFWorkbook workbook = new HSSFWorkbook();// 生成一个表格HSSFSheet sheet = workbook.createSheet("数据明细");HSSFCellStyle cellStyle = workbook.createCellStyle();//设置表头字体HSSFFont font2 = workbook.createFont();font2.setFontName("仿宋_GB2312");font2.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);//粗体显示font2.setFontHeightInPoints((short) 10);//TODO 水平垂直居中 列宽cellStyle.setAlignment(HorizontalAlignment.CENTER_SELECTION);cellStyle.setFont(font2);// 产生表格标题行HSSFRow firrow = sheet.createRow(0);// 产生表格标题行HSSFRow row = sheet.createRow(1);CellRangeAddress cellRange = null;//一级表头String manKey=null;//判断表头是否有数据if(listtitle.size()==0){return;}
//这就是我们对无序的表头数据进行分组得等满足要求的Map<String, List<Map>> 格式数据Map<String, List<Map>> temp =new HashMap<String, List<Map>>();for(Map item:listtitle){String key = item.get("VAL_ONE").toString();if(temp.get(key) == null){List<Map> list1 = new ArrayList<>();temp.put(key,list1);}else{temp.put(key,temp.get(key));}temp.get(key).add(item);}//设置固定单位列HSSFCell organizeCell = firrow.createCell(0);organizeCell.setCellStyle(cellStyle);//由于后台数据并没有返回项目名称这一列接口数据,因此我们只能自己生成organizeCell.setCellValue("项目名称");sheet.addMergedRegion(new CellRangeAddress(0, 1, 0, 0));//遍历生成一、二级表头int count = 1;for(Map.Entry<String, List<Map>> entry : temp.entrySet()){List<Map> mapValue = entry.getValue();manKey=entry.getKey();if(mapValue.size()>0){//设置一级表头HSSFCell fircell = firrow.createCell(count);fircell.setCellStyle(cellStyle);fircell.setCellValue(manKey);//对合并列进行判断,当二级目录为一时既不需要合并if(mapValue.size()>1){//设置单元格合并操作,可以查询Excel导出apicellRange = new CellRangeAddress(0, 0, count, count + mapValue.size()-1);try {sheet.addMergedRegion(cellRange);addBorderLine(sheet,cellRange,workbook);}catch (Exception e){e.printStackTrace();}}for (short i = 0; i < mapValue.size(); i++) {try {//设置二级表头HSSFCell cell = row.createCell(count+i);HSSFRichTextString text = new HSSFRichTextString(mapValue.get(i).get("VAL_TWO").toString());cell.setCellValue(text);//设置二级表头宽度sheet.setColumnWidth(count+i, text.toString().getBytes("UTF-8").length*256);cell.setCellStyle(cellStyle);CellRangeAddress cellRange1 = new CellRangeAddress(1, 1, count-1, count+i);//sheet.addMergedRegion(cellRange1);//设置水平位置addBorderLine(sheet, cellRange1, workbook);}catch (Exception e){e.printStackTrace();}}count = count + mapValue.size();}}// 遍历集合数据,产生数据行if(list!=null && list.size() > 0){int index = 1;int count1 = 1;for (short i = 0; i < list.size(); i++) {index++;// 从表头下一行开始插入数据row = sheet.createRow(index);row.createCell(0).setCellValue(list.get(i).get("XLMC").toString());for(Map.Entry<String, List<Map>> entry : temp.entrySet()){List<Map> mapValue = entry.getValue();manKey=entry.getKey();if(mapValue.size()>0){for (short ii = 0; ii < mapValue.size(); ii++) {try {HSSFCell cell = row.createCell(count1 + ii);//通过遍历表头二级表单“CODE_TWO”值 匹配内容接口数据if(null==list.get(i).get(mapValue.get(ii).get("CODE_TWO").toString())||("null").equals(list.get(i).get(mapValue.get(ii).get("CODE_TWO").toString()))){cell.setCellValue("0");}else {cell.setCellValue(list.get(i).get(mapValue.get(ii).get("CODE_TWO").toString()).toString());}}catch (Exception e){e.printStackTrace();}}count1 = count1 + mapValue.size();}}//当该行数据遍历完成之后,下一行从第二列开始count1=1;}}OutputStream outputStream = response.getOutputStream();// 打开流workbook.write(outputStream);// HSSFWorkbook写入流workbook.close();// HSSFWorkbook关闭outputStream.flush();// 刷新流outputStream.close();// 关闭流System.out.println("导出成功");
}
private void addBorderLine(HSSFSheet sheet,CellRangeAddress cellRangeAddress,HSSFWorkbook workbook){RegionUtil.setBorderTop(1, cellRangeAddress, sheet, workbook);RegionUtil.setBorderBottom(1, cellRangeAddress, sheet, workbook);RegionUtil.setBorderLeft(1, cellRangeAddress, sheet, workbook);RegionUtil.setBorderRight(1, cellRangeAddress, sheet, workbook);
}

内容接口:

Java实现Excel多表头动态数据导出相关推荐

  1. java实现excel横排以及竖排数据导出

    相信不少同学使用excel导出工具时,都能很方便的导出数据库里的数据,只不过,通常来讲,是如下的excel格式: 但需求总是会变得,等哪天产品跑来跟你说,''这横排的看起来 不方便啊,你给我撸出一个竖 ...

  2. Java读取excel指定行列的数据(通过jxl的方式)

    目录 Java读取Excel指定列的数据详细教程和注意事项(通过jxl的方式) 1.前言 2.注意事项 3.主要的API说明 4.示例代码 Java读取Excel指定列的数据详细教程和注意事项(通过j ...

  3. springboot+easyexcel实现固定表头+动态表头的数据导出

    /*** 固定标头的实体类*/ @Data public class BaseExportExcelStringVo implements Serializable {private static f ...

  4. java输出excel 异常处理_使用poi导出Excel,并设定单元格内容类型,抛出异常

    本例子使用的是HSSF,为Excel2003提供处理方案. 设定为输入类型为数值 import org.apache.poi.hssf.usermodel.DVConstraint; import o ...

  5. java程序转换excel中科学记数法的数据为date类型

    今天出于某些原因从mongodb数据库中导出了一些数据,为了更直观的发送给其他人查阅,便使用mongoVUE的导出为excel功能. 但是导出后出现了一个问题,里边有一列存储时间的,存储的是long型 ...

  6. java搜索excel表格里的数据_Java读取Excel表格中的数据

    前言 本文主要讲述如何在Java中读取Excel表中的数据并在控制台输出,实现工具为Eclipse 提示:以下是本篇文章正文内容,下面案例可供参考 一.添加jar包文件 描述:在Java中导入导出Ex ...

  7. Java读取Excel表格中的数据

    文章目录 前言 一.添加jar包文件 1.在Eclipse工程下新建lib文件夹 2.复制jar包 3.将jar包粘贴到Eclipse中 4.配置构建路径 二.案例代码 1.新建类 2.获取Excel ...

  8. dbeaver导出excel文件_vue将数据导出为excel文件就是如此简单

    前言: 在以前需要将数据导出为excel文件时,往往需要后端提供支持,后端导出后以文件流的形式进行下载.但也带了一些问题,如: 1. 代码量复杂,一般前端难以完成. 2. 实现数据导出往往会大量消耗服 ...

  9. JS前端--数据导出为EXCEL(支持大量数据导出)

    数据导出为excel是前端比较常用的功能.笔者近期在网上收集汇总了几种常用的方法,供大家使用. 1.ActiveXObject("Excel.Application") 这种方法只 ...

最新文章

  1. github用相对路径显示图片_url-图像未显示在GitHub的README.md中
  2. Kaggle大神:竞赛代码别删,这都是宝藏
  3. PHP取得json前面有乱码(去除文件头部BOM)
  4. JPA2.0回调函数的使用
  5. ElasticSearch 知识点整理(入门)
  6. jpa 手动预编译_编译时检查JPA查询
  7. 帮助孩子学会感恩_页数204_出版日期2015.03_完整版PDF电子书下载
  8. odis工程师使用方法_傅里叶红外光谱仪常见故障维修及排除方法,你了解有多少种呢?...
  9. 基于STM32的嵌入式语音识别模块设计实现
  10. mysql 拷贝权限_mysql复制表的三种方法+grant三类权限说明
  11. linux下载git并为git配置连接ssh
  12. 英语口语练习二十二之I'd strongly recommend that... (我强烈建议……)用法
  13. 解决WinPcap无法安装的问题
  14. python实现屏幕截图
  15. 北京链家二手房数据分析
  16. 三亚免税店积分抵现_海南放大招!10万购物免税额、离岛半年可补购,一文教你买转海南自贸港...
  17. idea的maven中出现target文件不完整或者“class not found“ 或 “test not fount“
  18. 纵观20年间程序员薪酬变化:涨幅下降,初级编码岗大幅消失
  19. 【OpenCV C++ 案例实战一】实现双人篮球游戏
  20. 诺基亚将裁员万人 风雨飘摇中该何去何从

热门文章

  1. JAVA程序员M1踩坑指南 2021-08-29
  2. sublime中检查php语法错误
  3. 程序员放松的9个好网站推荐
  4. 微信支付完成或取消后在ios系统回跳到Safari默认浏览器的解决方案
  5. 1952. 金发姑娘和 N 头牛
  6. vivos7和华为p40哪个好 vivos7和华为p40参考配置区别评测
  7. 一个好用又好看的UEFI启动管理器rEFInd
  8. 论程序员的时代焦虑与焦虑的缓解[转]
  9. VS调试出现bin\...exe文件正由另一进程使用,因此读取进程无法访问文件解决方式
  10. es6入门到五连绝世之四杀(quadra kill )