easyExcel合并数据导出(一对多)
语言 java
框架 ssm
需求 :看图 也是导出效果

数据库查询为(关系为一对多) 一个学生对应多个课程

实现步骤
1.实体类配置, 建议单独写个实体用来导出使用()
学生信息字段正常配置 , 课程表字段 使用 @ExcelProperty({"学生和选课中间表","学生编号"})
StudentExcel.java

package com.example.mybatisplus.pojo; import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import java.io.Serializable;
import java.util.Date; /**
* easy_excel导出
* @author three
* @date 2021/8/23 16:13
*/
@ApiModel("easy_excel导出实体类")
@Data
public class StudentExcel implements Serializable {
private static final long serialVersionUID = 1L; // ----学生信息表( 一 ) @ExcelProperty("学生姓名")
@ApiModelProperty("学生姓名")
private String sname; @ExcelProperty("性别")
@ApiModelProperty("性别")
private String sgender; @ExcelProperty("出生年月")
@ApiModelProperty("出生年月")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date sbirth; //----学生和选课中间表(多)---- @ExcelProperty({"学生和选课中间表","学生编号"})
@ApiModelProperty("学生编号")
private Integer sno; @ExcelProperty({"学生和选课中间表","课程编号"})
@ApiModelProperty("课程编号")
private String cno; @ExcelProperty({"学生和选课中间表","分数"})
@ApiModelProperty("分数")
private String score;
}
2.代码 工具类 ExcelFillCellMergeStrategy.java

package com.example.mybatisplus.utils; import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress; import java.util.List; public class ExcelFillCellMergeStrategy implements CellWriteHandler { private int[] mergeColumnIndex;
private int mergeRowIndex; public ExcelFillCellMergeStrategy(int mergeRowIndex, int[] mergeColumnIndex) {
this.mergeRowIndex = mergeRowIndex;
this.mergeColumnIndex = mergeColumnIndex;
} @Override
public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) { } @Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { } @Override
public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer integer, Boolean aBoolean) { } @Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {
int curRowIndex = cell.getRowIndex();
int curColIndex = cell.getColumnIndex();
if (curRowIndex > mergeRowIndex) {
for (int i = 0; i < mergeColumnIndex.length; i++) {
if (curColIndex == mergeColumnIndex[i]) {
mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);
break;
}
}
}
} /**
* 当前单元格向上合并
*
* @param writeSheetHolder
* @param cell 当前单元格
* @param curRowIndex 当前行
* @param curColIndex 当前列
*/
private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {
Object curData = cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();
Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex);
Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() : preCell.getNumericCellValue();
// 将当前单元格数据与上一个单元格数据比较
Boolean dataBool = preData.equals(curData);
if (dataBool) {
Sheet sheet = writeSheetHolder.getSheet();
List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();
boolean isMerged = false;
for (int i = 0; i < mergeRegions.size() && !isMerged; i++) {
CellRangeAddress cellRangeAddr = mergeRegions.get(i);
// 若上一个单元格已经被合并,则先移出原有的合并单元,再重新添加合并单元
if (cellRangeAddr.isInRange(curRowIndex - 1, curColIndex)) {
sheet.removeMergedRegion(i);
cellRangeAddr.setLastRow(curRowIndex);
sheet.addMergedRegion(cellRangeAddr);
isMerged = true;
}
}
// 若上一个单元格未被合并,则新增合并单元
if (!isMerged) {
CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex, curColIndex);
sheet.addMergedRegion(cellRangeAddress);
}
}
} }
3. EasyExcelController.java
3.1 int[] mergeColumeIndex = {0,1,2}; 数据重复部分会合并成一个单元格,只需标出需要合并的列数
3.2 int mergeRowIndex = 0; 标出合并的开始列数 从0开始

package com.example.mybatisplus.controller; import com.alibaba.excel.EasyExcel;
import com.example.mybatisplus.pojo.StudentExcel;
import com.example.mybatisplus.pojo.StudentinfoEntity;
import com.example.mybatisplus.service.StudentinfoService;
import com.example.mybatisplus.utils.ExcelFillCellMergeStrategy;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.http.HttpRequest;
import org.springframework.web.bind.annotation.*; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List; /**
* EasyExcel test
* 测试地址 http://localhost:8088/easy-excel/export
* 传输数据 [1,2,3]
* @author zou
* @date 2021/8/23 15:51
*/
@Api(tags = "easy-excel的使用")
@RestController
@RequestMapping("/easy-excel")
public class EasyExcelController { @Resource
private StudentinfoService studentinfoService; @PostMapping("/export")
@ApiOperation("导出excel(一对多关系)")
public void excel(HttpServletResponse response,@RequestBody Integer[] sno) throws IOException {
List<StudentExcel> studentinfoEntities = studentinfoService.studentToElectives(sno);
// 设置响应格式
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
//需要合并的列
int[] mergeColumeIndex = {0,1,2};
// 从那一列开始合并
int mergeRowIndex = 0;
String fileName = URLEncoder.encode("one-to-many", "UTF-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream(), StudentExcel.class)
.sheet("one-to-many")
.registerWriteHandler(new ExcelFillCellMergeStrategy(mergeRowIndex, mergeColumeIndex))
.doWrite(studentinfoEntities);
}
}
4.服务层,持久层略去一千行....
....
easyExcel合并数据导出(一对多)的更多相关文章
- 数据的动态合并和导出至EXCEL
最近一段时间都在处理数据的动态合并和导出EXCEL的问题,写个demo记录下,希望和我碰到同样问题的博友可以顺利解决:后面会提供demo下载链接. (VS2012,ASP.NET) 一.主要解决以下问 ...
- php 数据导出到excel 2种带有合并单元格的导出
具体业务层面 可能会有所不同.以下两种方式涉及的合并单元格地方有所不同,不过基本思路是一致的. 第一种是非插件版本.可能更容易理解点,基本思路就是 组装table 然后 读取 输出到excel上.缺点 ...
- 使用VUE+SpringBoot+EasyExcel 整合导入导出数据
使用VUE+SpringBoot+EasyExcel 整合导入导出数据 创建一个普通的maven项目即可 项目目录结构 1 前端 存放在resources/static 下 index.html &l ...
- EasyExcel实现文件导出
官网:https://www.yuque.com/easyexcel/doc/easyexcel 导出 准备工作 引入依赖 <!--EasyExcel相关依赖--> <depende ...
- 百度地图里面搜索到的公司商家电话导出表格?怎样将把百度地图里面搜索到的公司 电话 地址 等数据导出excel里?
好多人在问:如何将百度地图里面搜索到的公司商家电话导出表格?怎样将把百度地图里面搜索到的公司 电话 地址 等数据导出excel里? 现在,很多人都在网络上找商家,联系业务. 百度地图里有很多的商家联系 ...
- asp.net将数据导出到excel
本次应用datatable导出,若用gridview(假设gridview设为了分页显示)会出现只导出当前页的情况. protected void btnPrn_Click(object sender ...
- Java使用POI实现数据导出excel报表
Java使用POI实现数据导出excel报表 在上篇文章中,我们简单介绍了java读取word,excel和pdf文档内容 ,但在实际开发中,我们用到最多的是把数据库中数据导出excel报表形式.不仅 ...
- Delphi 数据导出到Excel
好多办公软件特别是财务软件,都需要配备把数据导出到Excel,下面就来介绍两种数据导出方法 1.ADODB导出查询结果(此方法需要安装Excel) 2.二维表数据导出(根据Excel文件结构生成二进制 ...
- 树结构关系的数据导出为excel
该文针对的是关于树结构的数据的导出,每一个节点都可以创建不定数的子节点,在选择好某个节点进行导出 时,会把该节点以及子节点的数据都导出来.导出后的excel的格式大概如下图的形式,这个是一个比较理想 ...
- java实现Excel数据导出
java实现Excel数据导出: 目前,比较常用的实现Java导入.导出Excel的技术有两种Jakarta POI和Java Excel Jakarta POI 是一套用于访问微软格式文档的Java ...
随机推荐
- Java是解释型语言么
基础概念 JVM虚拟机会将.java类文件编译成.class文件--字节码文件,这大家都知道. 代码运行时还需要将.class字节码文件翻译成机器码才能执行. 解释执行:将编译好的字节码一行一行地翻译 ...
- 浅入 ABP 系列(6):数据库配置
浅入 ABP 系列(6):数据库配置 版权护体作者:痴者工良,微信公众号转载文章需要 <NCC开源社区>同意. 目录 浅入 ABP 系列(6):数据库配置 创建标准的 EFCore 数据库 ...
- 当 GraphQL 遇上图数据库,便有了更方便查询数据的方式
人之初,性本鸽. 大家好,我叫储惠龙(实名上网),你可以叫我小龙人,00 后一枚.目前从事后端开发工作. 今天给大家带来一个简单的为 NebulaGraph 提供 GraphQL 查询支持的 DEMO ...
- C++ STL之 map 学习笔记
•何为 map? map 是 STL 的一个关联容器,它提供一对一的数据处理,map 中存放的是一个 key-value键值对,其类型可以自己定义: 第一个可以称为关键字,每个关键字在 map 中只能 ...
- Failed to instantiate [applets.nature.mapper.LogInfoMapper]: Specified class is an interface-项目启动报错
一.问题由来 周日下午项目在进行测试时,有些东西需要临时修改,自己已经打好一个包部署到测试服务器进行部署.在测试过程中发现一个问题,就是 现在的代码跑起来是没问题的,只是其他人又的东西还没做,所以暂时 ...
- arch安装xfce4的时候,出现无法设置开机启动的问题
sudo systemctl enable lightdm Failed to enable unit: File /etc/systemd/system/display-manager.serv ...
- C语言中的强制转换
许久没有遇到的问题 C语言真是博大精深,越使用它,就越发感觉到它的威力和恐怖,最近在做算法的时候,遇到了一个强转的错误,把人折腾的够受,这次要好好梳理一下了,希望下次不能再犯此类的问题. 强制转换 ...
- 关于使用Kotlin开发SpringBoot项目使用@Transactional和@Autowired的报错问题
原文地址: 关于使用Kotlin开发SpringBoot项目使用@Transactional和@Autowired的报错问题 - Stars-One的杂货小窝 问题描述 最近在开发一个订单模块,需要出 ...
- epoll反应堆理解
https://www.aliyundrive.com/s/oBvP7BcjsCS https://blog.csdn.net/weixin_36750623/article/details/8354 ...
- 配置Tomcat服务器
一:修改服务器端口 访问tomcat主页的时候,输入的是localhost:8080,说明tomcat的端口是8080,那么怎么修改端口号呢? 我们要先认识配置文件 用浏览器打开tomcat下conf ...