easyexcel合并单元格底色

一、效果图

二、导出接口代码

 @PostMapping("selectAllMagicExport")
    public void selectAllMagicExport(HttpServletRequest request, HttpServletResponse response) throws IOException {
        ServiceResult<SearchResult<TestMetLineFe2o3Export>> result = success(searcher.search(TestMetLineFe2o3Export.class, MapUtils.flat(request.getParameterMap())));
        SearchResult<TestMetLineFe2o3Export> searchResult = result.getData();
        List<TestMetLineFe2o3Export> dataList = searchResult.getDataList();

        // Excel格式:入厂日期相同日期合并

        // 设置响应头信息
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename=chatEduExport.xlsx");

        // 使用EasyExcel进行导出
        ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), TestMetLineFe2o3Export.class)
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                .registerWriteHandler(new ExcelFillCellMergeStrategy(1, new int[]{1, 4, 5, 6, 12, 14}))
                .build();
        WriteSheet writeSheet = EasyExcel.writerSheet("铁红").build();
        excelWriter.write(dataList, writeSheet);

        excelWriter.finish();
    }

三、拦截器


import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.handler.context.CellWriteHandlerContext;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.ciih.workshop.entity.TestMetLineFe2o3Export;
import com.ciih.workshop.utils.HexToRGB;
import com.ejlchina.searcher.BeanSearcher;
import lombok.Data;
import org.apache.poi.hssf.usermodel.HSSFPalette;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;

/**
 * 合并单元格
 */
@Component
@Data
public class ExcelFillCellMergeStrategy implements CellWriteHandler {
    @Resource
    private BeanSearcher searcher;
    // 先声明一个对象
    private static ExcelFillCellMergeStrategy excelFillCellMergeStrategy;

    //启动注入
    @PostConstruct
    public void init() {
        excelFillCellMergeStrategy = this;
        excelFillCellMergeStrategy.searcher = this.searcher;
    }

    /**
     * 合并字段的下标,如第一到五列new int[]{0,1,2,3,4}
     */
    private int[] mergeColumnIndex;
    /**
     * 从第几行开始合并,如果表头占两行,这个数字就是2
     */
    private int mergeRowIndex;

    public ExcelFillCellMergeStrategy() {
    }

    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 integer, Integer integer1, Boolean aBoolean) {

    }

    @Override
    public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell,
                                Head head, Integer integer, Boolean aBoolean) {

    }

    @Override
    public void afterCellDispose(CellWriteHandlerContext context) {
        // 当前单元格
        Cell cell = context.getCell();
        //当前行
        int curRowIndex = context.getCell().getRowIndex();
        //当前列
        int curColIndex = context.getCell().getColumnIndex();

        if (curRowIndex > mergeRowIndex) {
            for (int i = 0; i < mergeColumnIndex.length; i++) {
                if (curColIndex == mergeColumnIndex[i]) {
                    // 合并单元格
                    mergeWithPrevRow(context.getWriteSheetHolder(), context.getCell(), curRowIndex, curColIndex);
                    break;
                }
            }
        }

        // 设置内容居中
        WriteCellData<?> cellData = context.getFirstCellData();
        WriteCellStyle writeCellStyle = cellData.getOrCreateStyle();
        writeCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        writeCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);

        // 设置边框
        writeCellStyle.setBorderBottom(BorderStyle.THIN);
        writeCellStyle.setBorderLeft(BorderStyle.THIN);
        writeCellStyle.setBorderRight(BorderStyle.THIN);
        writeCellStyle.setBorderTop(BorderStyle.THIN);

        // 忽略表头
        if (cell.getRowIndex() > 0) {
            // 底色
            coloring(context, writeCellStyle, cell, curRowIndex, curColIndex);
        }
    }

    /**
     * 着色
     *
     * @param writeCellStyle
     * @param cell
     * @param curRowIndex    当前行
     * @param curColIndex    当前列
     */
    private void coloring(CellWriteHandlerContext context, WriteCellStyle writeCellStyle, Cell cell, int curRowIndex, int curColIndex) {
        // 设置单元格颜色
        // 拿到当前行的所有数据
        Cell curInDateCell = cell.getSheet().getRow(curRowIndex).getCell(0); // 唯一编号
        double id = curInDateCell.getNumericCellValue();
        // 完整数据
        HashMap<String, Object> flat = new HashMap<>();
        flat.put("id", (long) id);
        TestMetLineFe2o3Export fe2o3Export = excelFillCellMergeStrategy.searcher.searchFirst(TestMetLineFe2o3Export.class, flat);


        // 渲染入场批号的颜色
        if (cell.getColumnIndex() == 4) {
            coloringAction(fe2o3Export.getTestMetInnumStandardColor(), writeCellStyle);
            // 加批注
            noteAction(context, cell, fe2o3Export.getTestMetInnumStandardLevel());
        }
        // 氯根着色
        if (cell.getColumnIndex() == 7) {
            coloringAction(fe2o3Export.getLgStandardColor(), writeCellStyle);
            noteAction(context, cell, fe2o3Export.getLgStandardLevel());
        }
        // 水分着色
        if (cell.getColumnIndex() == 8) {
            coloringAction(fe2o3Export.getWaterStandardColor(), writeCellStyle);
            noteAction(context, cell, fe2o3Export.getWaterStandardLevel());
        }
        // 粒度着色
        if (cell.getColumnIndex() == 10) {
            coloringAction(fe2o3Export.getLdStandardColor(), writeCellStyle);
            noteAction(context, cell, fe2o3Export.getLdStandardLevel());
        }
        // Na2O着色
        if (cell.getColumnIndex() == 17) {
            coloringAction(fe2o3Export.getNa2oStandardColor(), writeCellStyle);
            noteAction(context, cell, fe2o3Export.getNa2oStandardLevel());
        }
        // Al2O3着色
        if (cell.getColumnIndex() == 19) {
            coloringAction(fe2o3Export.getAl2o3StandardColor(), writeCellStyle);
            noteAction(context, cell, fe2o3Export.getAl2o3StandardLevel());
        }
        // SiO2着色
        if (cell.getColumnIndex() == 20) {
            coloringAction(fe2o3Export.getSio2StandardColor(), writeCellStyle);
            noteAction(context, cell, fe2o3Export.getSio2StandardLevel());
        }
        // CaO着色
        if (cell.getColumnIndex() == 24) {
            coloringAction(fe2o3Export.getCaoStandardColor(), writeCellStyle);
            noteAction(context, cell, fe2o3Export.getCaoStandardLevel());
        }
        // Cr2O3着色
        if (cell.getColumnIndex() == 26) {
            coloringAction(fe2o3Export.getCr2o3StandardColor(), writeCellStyle);
            noteAction(context, cell, fe2o3Export.getCr2o3StandardLevel());
        }
        // MnO着色
        if (cell.getColumnIndex() == 27) {
            coloringAction(fe2o3Export.getMnoStandardColor(), writeCellStyle);
            noteAction(context, cell, fe2o3Export.getMnoStandardLevel());
        }
        // Fe2O3着色
        if (cell.getColumnIndex() == 28) {
            coloringAction(fe2o3Export.getFe2o3StandardColor(), writeCellStyle);
            noteAction(context, cell, fe2o3Export.getFe2o3StandardLevel());
        }
    }

    /**
     * 批注
     */
    private void noteAction(CellWriteHandlerContext context, Cell cell, String content) {
        if (StrUtil.isBlank(content)) {
            return;
        }
        Sheet sheet = context.getWriteSheetHolder().getSheet();
        ClientAnchor anchor = new XSSFClientAnchor();
        //关键修改
        anchor.setDx1(0);
        anchor.setDx2(0);
        anchor.setDy1(0);
        anchor.setDy2(0);
        anchor.setCol1(cell.getColumnIndex());
        anchor.setRow1(cell.getRowIndex());
        anchor.setCol2(cell.getColumnIndex());
        anchor.setRow2(cell.getRowIndex());

        Drawing<?> drawingPatriarch = sheet.createDrawingPatriarch();
        Comment cellComment = drawingPatriarch.createCellComment(anchor);

        cellComment.setString(new XSSFRichTextString(content));
        cell.setCellComment(cellComment);
    }

    /**
     * 着色动作
     */
    private void coloringAction(String color, WriteCellStyle writeCellStyle) {
        if (color == null) {
            return;
        }
        Integer r = null;
        Integer g = null;
        Integer b = null;

        //
        if (color.startsWith("#")) {
            int[] ints = HexToRGB.hexToRGB(color);
            r = ints[0];
            g = ints[1];
            b = ints[2];
        } else {
            List<String> all01 = ReUtil.findAll("(?<=\\().*?(?=\\))", color, 0);
            if (all01 != null && all01.size() > 0 && all01.get(0).split(",").length >= 3) {
                String[] split = all01.get(0).split(",");
                // RGB颜色转换
                r = Integer.parseInt(split[0].trim());
                g = Integer.parseInt(split[1].trim());
                b = Integer.parseInt(split[2].trim());
            }
        }

        if (r != null && g != null && b != null) {
            HSSFWorkbook wb = new HSSFWorkbook();
            HSSFPalette palette = wb.getCustomPalette();
            HSSFColor hssfColor = palette.findSimilarColor(r, g, b);
//                writeCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex());
            writeCellStyle.setFillForegroundColor(hssfColor.getIndex());
            writeCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
        }
    }

    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();

        // 如果是日期列,即第一列,只要相同就合并
        if (cell.getColumnIndex() == 1) {
            if (curData.equals(preData)) {
                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);
                }
            }
        } else {
            // 如果日期和批号与上一行的日期和批号相同。则进行当前行列的合并
            // 当前行的日期和批号
            Cell curInDateCell = cell.getSheet().getRow(curRowIndex).getCell(1);
            Object curInDate = curInDateCell.getCellTypeEnum() == CellType.STRING ? curInDateCell.getStringCellValue() : curInDateCell.getNumericCellValue();

            Cell curInNumCell = cell.getSheet().getRow(curRowIndex).getCell(4);
            Object curInNum = curInNumCell.getCellTypeEnum() == CellType.STRING ? curInNumCell.getStringCellValue() : curInNumCell.getNumericCellValue();
            // 上一行的日期和批号
            Cell preInDateCell = cell.getSheet().getRow(curRowIndex - 1).getCell(1);
            Object preInDate = preInDateCell.getCellTypeEnum() == CellType.STRING ? preInDateCell.getStringCellValue() : preInDateCell.getNumericCellValue();

            Cell preInNumCell = cell.getSheet().getRow(curRowIndex - 1).getCell(4);
            Object preInNum = preInNumCell.getCellTypeEnum() == CellType.STRING ? preInNumCell.getStringCellValue() : preInNumCell.getNumericCellValue();


            if (curInDate.equals(preInDate) && curInNum.equals(preInNum)) {

                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);
                }
            }
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/83389.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java虚拟机(JVM):垃圾收集算法

目录 一、分代收集理论 二、标记-清除算法 三、标记-复制算法 四、标记-整理算法 一、分代收集理论 分代收集理论建立在两个分代假说之上&#xff1a; 1、弱分代假说&#xff1a;绝大多数对象都是朝生夕灭的。 2、强分代假说&#xff1a;熬过越多次垃圾收集过程的对象就…

mysql 、sql server trigger 触发器

sql server mySQL create trigger 触发器名称 { before | after } [ insert | update | delete ] on 表名 for each row 触发器执行的语句块## 表名&#xff1a; 表示触发器监控的对象 ## before | after : 表示触发的时间&#xff0c;before : 表示在事件之前触发&am…

JVM的元空间了解吗?

笔者近期在面试的时候被问到了这个问题&#xff0c;元空间也是Java8当时的一大重大革新&#xff0c;之前暑期实习求职的时候有专门看过&#xff0c;但是近期秋招的时候JVM相关的内容确实有点生疏了&#xff0c;故在此进行回顾。 结构 首先&#xff0c;我们应了解JVM的堆结构&a…

深入理解python虚拟机:程序执行的载体——栈帧

栈帧&#xff08;Stack Frame&#xff09;是 Python 虚拟机中程序执行的载体之一&#xff0c;也是 Python 中的一种执行上下文。每当 Python 执行一个函数或方法时&#xff0c;都会创建一个栈帧来表示当前的函数调用&#xff0c;并将其压入一个称为调用栈&#xff08;Call Stac…

docker学习(十五)docker安装MongoDB

什么是MongoDB? MongoDB 是一个开源的、面向文档的 NoSQL 数据库管理系统&#xff0c;它以高性能、灵活的数据存储方式而闻名。与传统的关系型数据库不同&#xff0c;MongoDB 采用了一种称为 BSON&#xff08;Binary JSON&#xff09;的二进制 JSON 格式来存储数据。它是一种非…

(详解踩坑)GIT版本回滚git stash、git reset、git reset --hard、git revert

目录 背景 一、&#xff08;git log、git reflog&#xff09;查看git提交日志及命令历史 1.1 git log&#xff08;提交日志&#xff09; 1.2 git reflog&#xff08;命令历史&#xff09; 二、git reset&#xff08;回退到指定的版本&#xff0c;并且保留更改&#xff09; …

IDEA启动报错【java.sql.SQLSyntaxErrorException: ORA-00904: “P“.“PRJ_NO“: 标识符无效】

IDEA报错如下&#xff1a; 2023-08-17 11:26:15.535 ERROR [egrant-biz,b48324d82fe23753,b48324d82fe23753,true] 24108 --- [ XNIO-1 task-1] c.i.c.l.c.RestExceptionController : 服务器异常org.springframework.jdbc.BadSqlGrammarException: ### Error queryin…

leetcode 542. 01 Matrix(01矩阵)

矩阵中只有0&#xff0c;1值&#xff0c;返回每个cell到最近的0的距离。 思路&#xff1a; 0元素到它自己的距离是0&#xff0c; 只需考虑1到最近的0是多少距离。 BFS. 先把元素1处的距离更新为无穷大。 0的位置装入queue。 从每个0出发&#xff0c;走上下左右4个方向&…

axios / fetch 实现 stream 流式请求

axios 是一个支持node端和浏览器端的易用、简洁且高效的http库。本文主要介绍 axios 如何实现 stream 流式请求&#xff0c;注意这里需要区分 node 环境和浏览器环境。 一、node端 代码演示&#xff1a; const axios require(axios);axios({method: get,url: http://tiven.c…

【C# 基础精讲】使用async和await进行异步编程

在C#中&#xff0c;使用async和await关键字进行异步编程是一种强大的工具&#xff0c;可以在不阻塞主线程的情况下执行耗时操作&#xff0c;提高程序的并发性和响应性。本文将深入探讨async和await的基本概念、使用场景、编码规范以及一些示例&#xff0c;以帮助您更好地理解如…

RocketMQ双主双从同步集群部署

&#x1f388; 作者&#xff1a;互联网-小啊宇 &#x1f388; 简介&#xff1a; CSDN 运维领域创作者、阿里云专家博主。目前从事 Kubernetes运维相关工作&#xff0c;擅长Linux系统运维、开源监控软件维护、Kubernetes容器技术、CI/CD持续集成、自动化运维、开源软件部署维护…

定位服务器CPU爆满的具体原因

1、查询CPU消耗的进程 使用top命令查看系统的CPU和内存使用情况 CPU一列是线程占用百分比 2、具体查看某个占分比大的进程 以为PId:7355为例&#xff0c; 执行top -Hp 7355&#xff0c;线程按照CPU使用率排序。 3、将线程PID转化为16进制 执行printf %x 7391&#xff0c;将…

不含数字的webshell绕过

异或操作原理 1.首先我们得了解一下异或操作的原理 在php中&#xff0c;异或操作是两个二进制数相同时&#xff0c;异或(相同)为0&#xff0c;不同为1 举个例子 A的ASCII值是65&#xff0c;对应的二进制值是0100 0001 的ASCII值是96&#xff0c;对应的二进制值是 0110 000…

pdf格式文件下载不预览,云存储的跨域解决

需求背景 后端接口中返回的是pdf文件路径比如&#xff1a; pdf文件路径 &#xff08;https://wangzhendongsky.oss-cn-beijing.aliyuncs.com/wzd-test.pdf&#xff09; 前端适配是这样的 <ahref"https://wangzhendongsky.oss-cn-beijing.aliyuncs.com/wzd-test.pdf&…

Vscode详细安装教程

Vscode官网下载 官网地址&#xff1a;Download Visual Studio Code - Mac, Linux, Windows 通过链接可以直接跳转到下面的页面当中&#xff0c;支持的版本有Windows、Linux、Mac&#xff0c;可以选择适配自己电脑的版本&#xff0c;一般来说应该是Windows x64的。不要直接点W…

制作电商网站帮助中心,节省60%的咨询工作量

随着电子商务的快速发展&#xff0c;越来越多的企业选择在网上建立自己的电商平台。然而&#xff0c;一旦电商网站上线&#xff0c;就会面临一系列的问题和挑战。其中一个重要问题是如何有效管理和解答大量用户的咨询和问题&#xff0c;这对于提高用户体验和促进销售至关重要。…

Apache Doris IP变更问题详解

Apache Doris IP变更问题详解 一、背景二、环境硬件信息软件信息 三、FE恢复3.1 异常日志3.2 获取当前ip3.3 重置ip信息3.4 重置元数据记录3.5 元数据模式恢复3.6 重置fe集群节点3.7 关闭元数据模式重启fe 四、BE恢复4.1 获取当前ip4.2 重置ip信息4.3 重置be集群节点 一、背景 …

Java课题笔记~ Ajax

1.1 概述 AJAX (Asynchronous JavaScript And XML)&#xff1a;异步的 JavaScript 和 XML。 我们先来说概念中的 JavaScript 和 XML&#xff0c;JavaScript 表明该技术和前端相关&#xff1b;XML 是指以此进行数据交换。 1.1.1 作用 AJAX 作用有以下两方面&#xff1a; 与服…

矩形重叠问题

矩形重叠 文章目录 题目描述解题思路方法一方法二 题目描述 矩形以列表 [x1, y1, x2, y2] 的形式表示&#xff0c;其中 (x1, y1) 为左下角的坐标&#xff0c;(x2, y2) 是右上角的坐标。矩形的上下边平行于 x 轴&#xff0c;左右边平行于 y 轴。 如果相交的面积为 正 &#xff0…

中国电信秋招攻略,考试内容分析

电信秋招简介 每年的毕业生人数都在逐年递增&#xff0c;逐年递增就意味着竞争会越来越大&#xff0c;最好比别人做更充足的准备。要确定好就业方向以及就业的岗位&#xff0c;要了解各种各样的流程&#xff0c;做好一切自己能做到的准备。而对于有想法进入电信公司工作的人来…
最新文章