语言 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合并数据导出(一对多)的更多相关文章

  1. 数据的动态合并和导出至EXCEL

    最近一段时间都在处理数据的动态合并和导出EXCEL的问题,写个demo记录下,希望和我碰到同样问题的博友可以顺利解决:后面会提供demo下载链接. (VS2012,ASP.NET) 一.主要解决以下问 ...

  2. php 数据导出到excel 2种带有合并单元格的导出

    具体业务层面 可能会有所不同.以下两种方式涉及的合并单元格地方有所不同,不过基本思路是一致的. 第一种是非插件版本.可能更容易理解点,基本思路就是 组装table 然后 读取 输出到excel上.缺点 ...

  3. 使用VUE+SpringBoot+EasyExcel 整合导入导出数据

    使用VUE+SpringBoot+EasyExcel 整合导入导出数据 创建一个普通的maven项目即可 项目目录结构 1 前端 存放在resources/static 下 index.html &l ...

  4. EasyExcel实现文件导出

    官网:https://www.yuque.com/easyexcel/doc/easyexcel 导出 准备工作 引入依赖 <!--EasyExcel相关依赖--> <depende ...

  5. 百度地图里面搜索到的公司商家电话导出表格?怎样将把百度地图里面搜索到的公司 电话 地址 等数据导出excel里?

    好多人在问:如何将百度地图里面搜索到的公司商家电话导出表格?怎样将把百度地图里面搜索到的公司 电话 地址 等数据导出excel里? 现在,很多人都在网络上找商家,联系业务. 百度地图里有很多的商家联系 ...

  6. asp.net将数据导出到excel

    本次应用datatable导出,若用gridview(假设gridview设为了分页显示)会出现只导出当前页的情况. protected void btnPrn_Click(object sender ...

  7. Java使用POI实现数据导出excel报表

    Java使用POI实现数据导出excel报表 在上篇文章中,我们简单介绍了java读取word,excel和pdf文档内容 ,但在实际开发中,我们用到最多的是把数据库中数据导出excel报表形式.不仅 ...

  8. Delphi 数据导出到Excel

    好多办公软件特别是财务软件,都需要配备把数据导出到Excel,下面就来介绍两种数据导出方法 1.ADODB导出查询结果(此方法需要安装Excel) 2.二维表数据导出(根据Excel文件结构生成二进制 ...

  9. 树结构关系的数据导出为excel

    该文针对的是关于树结构的数据的导出,每一个节点都可以创建不定数的子节点,在选择好某个节点进行导出 时,会把该节点以及子节点的数据都导出来.导出后的excel的格式大概如下图的形式,这个是一个比较理想 ...

  10. java实现Excel数据导出

    java实现Excel数据导出: 目前,比较常用的实现Java导入.导出Excel的技术有两种Jakarta POI和Java Excel Jakarta POI 是一套用于访问微软格式文档的Java ...

随机推荐

  1. 【Azure Key Vault】Key Vault能不能生成DigiCert证书?能不能自动 Rotate 证书呢?

    问题描述 因为Azure Key Vault服务上保管的证书可以轻松的与其他Azure服务集成使用,所以需要知道 Key Vault 能不能生成 DigiCert 证书?能不能自动 Rotate 证书 ...

  2. 【Azure 应用服务】Azure Data Factory中调用Function App遇见403 - Forbidden

    问题描述 在Azure Data Factory (数据工厂)中,调用同在Azure中的Function App函数,却出现403 - Forbidden错误. 截图如下: 问题解答 访问Azure ...

  3. 【Azure 存储服务】关于Azure Storage Account(存储服务) 基于AAD用户的权限设定以及SAS key的管理问题

    问题描述 如何查到一个Storage Account曾经创建过多少SAS key,这些Key是否可以回收和限定?能否基于AAD身份对 Container / Folder 进行权限的设定和管理? 问题 ...

  4. 浅析图数据库 Nebula Graph 数据导入工具——Spark Writer

    从 Hadoop 说起 近年来随着大数据的兴起,分布式计算引擎层出不穷.Hadoop 是 Apache 开源组织的一个分布式计算开源框架,在很多大型网站上都已经得到了应用.Hadoop 的设计核心思想 ...

  5. linux基本知识汇总1(基础命令) 20000字汇总

    $$$$ 命令选项查看方式1.内建命令(help)格式: help + 内建命令#### help 命令 // 命令使用说明 2.外部命令(–help)一般是 Linux 命令自带的帮助信息,并不是所 ...

  6. 没想到,JDBC 驱动会偷偷修改 sql_mode 的会话值

    最近碰到一个 case,值得分享一下. 现象就是一个 update 操作,在 mysql 客户端中执行提示 warning,但在 java 程序中执行却又报错. 问题重现 mysql> crea ...

  7. Effective C++ 第一章:让自己习惯C++

    Effective C++ 第一章:让自己习惯C++ 引言 最近在阅读这本<effective C++ 改善程序与设计的55个具体做法>这本书,为了以后忘记的时候回顾,写一些笔记,每次笔记 ...

  8. Jmeter如何分布式执行脚本?

    Jmeter分布式执行原理: JMeter分布式执行时,选择其中一台作为调度机(master),其他机器作为执行机(slave): master会在本地编辑好jmx压测脚本,执行时,master将jm ...

  9. 统一身份认证系统 OpenLDAP 完整部署

    0)LDAP 介绍 LDAP 是什么?在那些地方用会用到 LDAP? LDAP英文名称:Lightweight Directory Access Protocol 轻型目录访问协议. 常用在单点登录, ...

  10. Python-使用openpyxl读取excel内容

    1. 本篇文章目标 将下面的excel中的寄存器表单读入并构建一个字典 2. openpyxl的各种基本使用方法 2.1 打开工作簿 wb = openpyxl.load_workbook('test ...