excel单元格合并策略

excel单元格合并策略

证明1+1=2?
要证明1+1=2这个问题,首先我们要找到问题的关键。所谓问题的关键呢,就是关键的问题,那么如何找到问题的关键就是这个问题的关键。
比如说,你有一个苹果,我也有一个苹果,如果我把我的苹果给你,当然我是不可能给你的,所以你把你的苹果给我的话,我可能会吃不完,但是我可以明天吃啊。
总而总之,言而言之,要证明1+1=2这个问题,关键就是我们就得先找到问题的关键。所以如何找到问题的关键就是关键的问题。
综上所知,你应该知道为什么1+1=2了吧。

上一篇我们讲了excel动态列的导出,今天我们继续来填之前挖下的坑。

所以补一下excel的单元格合并策略

上一篇在这里excel动态列的导出

依赖

我们这里依然使用的是easyexcel来做导出

<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.2.6</version>
</dependency>

先看效果吧

给两个效果吧,在接下来的代码中会顺序讲解这两个效果的实现过程。

第一个效果是只有标题第一行的单元格合并,并且内容靠右
在这里插入图片描述


在这里插入图片描述

第二个效果是标题合并,第二行的数据要随着导出的数据所在公司的名称和日期进行变化
标题下的内容需要进行 一对多 指定单元格的合并

第一种效果

先看一下导出的excel对象,截了其中一部分字段
使用value= {标题,子标题}的形式定义了第一级第二级的标题 ,第一级的内容需要相同,相同的内容会自动合并成一个单元格。

@Data
public class ImportPmsPriceSeaExcelDto {@ExcelProperty(value = {"填写须知:\n" +"1. 请勿修改表格结构;\n" +"2. 带*字段为必填项;\n" +"3. 开船日,截关日:填写数字,多个使用[/]隔开;\n" +"4. 生效日期,失效日期:请按YYYY-MM-DD的格式填写,如2023-01-01\n" +"5. 航程,免堆期:请填写数字,例如 2\n" +"6. 推荐价格:请填入「是」、「否」,若不填则默认为「否」;","合约号"})private String ctrNo;@ExcelProperty(value = {"填写须知:\n" +"1. 请勿修改表格结构;\n" +"2. 带*字段为必填项;\n" +"3. 开船日,截关日:填写数字,多个使用[/]隔开;\n" +"4. 生效日期,失效日期:请按YYYY-MM-DD的格式填写,如2023-01-01\n" +"5. 航程,免堆期:请填写数字,例如 2\n" +"6. 推荐价格:请填入「是」、「否」,若不填则默认为「否」;","开船日*"})@ColumnWidth(20)private String sailingWeekdays;@ExcelProperty(value = {"填写须知:\n" +"1. 请勿修改表格结构;\n" +"2. 带*字段为必填项;\n" +"3. 开船日,截关日:填写数字,多个使用[/]隔开;\n" +"4. 生效日期,失效日期:请按YYYY-MM-DD的格式填写,如2023-01-01\n" +"5. 航程,免堆期:请填写数字,例如 2\n" +"6. 推荐价格:请填入「是」、「否」,若不填则默认为「否」;","截关日"})private String customsCutoffWeekdays;
}

定义完导出对象后,我们就可以接着写导出了。
为了控制第一行标题的样式,我们使用了 .registerWriteHandler(new PmsPriceSeaTemplateMergeStrategy()) 自定义合并策略,来控制excel的样式


@Overridepublic void exportPmsPriceSeaTemplate(HttpServletResponse response) throws IOException {response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("utf8");response.setHeader("Content-disposition", "attachment;filename=" + "全部数据.xlsx");List<ImportPmsPriceSeaExcelDto> excelVoList = createImportPmsPriceSeaExcelDto();EasyExcel.write(response.getOutputStream()).head(ImportPmsPriceSeaExcelDto.class).excelType(ExcelTypeEnum.XLSX).registerWriteHandler(new PmsPriceSeaTemplateMergeStrategy()).sheet("运单模板").doWrite(excelVoList);}

自定义策略类

接着定义自定义策略
titleHandle()方法中,我们将标题的所有列,设置了内容靠左换行字体大小



/*** @Author: tfxing* @Description: RowWriteHandler*/
public class PmsPriceSeaTemplateMergeStrategy implements RowWriteHandler {@Overridepublic void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Integer integer, Integer integer1, Boolean aBoolean) {}@Overridepublic void afterRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer integer, Boolean aBoolean) {}@Overridepublic void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer integer, Boolean aBoolean) {if (row.getRowNum() > 1) {return;}// 获取当前sheetSheet sheet = writeSheetHolder.getSheet();titleHandle(sheet);titleHandle2(sheet);}private void titleHandle2(Sheet sheet) {Row row = sheet.getRow(1);if(null == row) {return;}row.setHeightInPoints(45);}private void titleHandle(Sheet sheet) {Workbook workbook = sheet.getWorkbook();Font font = workbook.createFont();CellStyle cellStyle = workbook.createCellStyle();// 内容靠左cellStyle.setAlignment(HorizontalAlignment.LEFT);cellStyle.setFont(font);// 是否换行cellStyle.setWrapText(true);Row row = sheet.getRow(0);for (int i = 0; i < 24; i++) {Cell cell0 = row.getCell(i);if(null == cell0) {continue;}cell0.setCellStyle(cellStyle);}// 设置字体大小row.setHeightInPoints(125);}}

第二种效果

第一种效果的实现还是挺简单的是吧,那么要来实现第二种效果吧

复习一下

在这里插入图片描述

同样的我们先定义一下导出的对象,同样是截取了其中一部分

@Data
public class AcctSettingExcelVo {@ExcelProperty({"凭证列表","公司名称","日期"})@ColumnWidth(12)private String vchDateStr;@ExcelProperty({"凭证列表","公司名称","凭证字号"})@ColumnWidth(20)private String vchWordStr;@ExcelProperty({"凭证列表","公司名称","凭证类型"})@ColumnWidth(20)private String vchTypeStr;@ExcelProperty({"凭证列表","公司名称","摘要"})@ColumnWidth(12)private String enTryDesc;
}

直接看合并策略吧

通过构造器传参,将三个关键的参数传递到类中。map,companyName,glpName,这三个参数分别是,需要合并的行列的map,公司名称,日期

map的处理是在调用处处理的的,我这里的处理过程就是通过将将数据需要合并的列和行解析出来,map的key就是行的下标value就是列的下标

具体实现我这里就不放出来了,每个人的业务不一样逻辑也不一样,大家自己想办法写吧。

通过titlehandle()方法将第二行的数据替换成companyNameglpName,公司名称和日期。

		Workbook workbook = sheet.getWorkbook();Font font = workbook.createFont();font.setBold(true); // 字体加粗font.setFontHeightInPoints((short)14); // 字体大小CellStyle cellStyle = workbook.createCellStyle();cellStyle.setAlignment(HorizontalAlignment.LEFT); // 内容居左cellStyle.setFont(font);// 前7行的内容设置为公司,内容相同时单元格会自动合并,并设置上风格 内容居左for (int i = 0; i < 7; i++) {Cell cell0 = sheet.getRow(1).getCell(i);cell0.setCellValue(companyName);cell0.setCellStyle(cellStyle);}CellStyle cellStyle1 = workbook.createCellStyle();cellStyle1.setAlignment(HorizontalAlignment.RIGHT); // 内容居右cellStyle1.setFont(font);// 第7行后的数据内容设置为日期,并设置上风格 内容居右for (int i = 7; i < 12; i++) {Cell cell7 = sheet.getRow(1).getCell(i);cell7.setCellValue(glpName);cell7.setCellStyle(cellStyle1);}

**decimalHandle()**方法是将小数转为千分位数显示的格式,三分一个分隔符。例如:10,010


前三行和最后两行需要单元格合并,

将map中的行和列取出来作为合并的参数。

new CellRangeAddress(rowNum, lastRowNum, i, i) 这个对象中的四个参数分别是:第一行,最后一行,第一列,最后一列

在我们往期写的一篇博客中有详细说明,在这里

Integer lastRowNum = map.get(rowNum);
if(-1 == lastRowNum) {return;
}for (int i = 0; i < 3; i++) {//合并单元格区域只有一个单元格时,不合并if (rowNum == lastRowNum && i == i) {return;}CellRangeAddress cellRangeAddress = new CellRangeAddress(rowNum, lastRowNum, i, i);sheet.addMergedRegionUnsafe(cellRangeAddress);
}for (int i = 10; i < 12; i++) {//合并单元格区域只有一个单元格时,不合并if (rowNum == lastRowNum && i == i) {return;}CellRangeAddress cellRangeAddress1 = new CellRangeAddress(rowNum, lastRowNum, i, i);sheet.addMergedRegionUnsafe(cellRangeAddress1);
}
}

自定义策略详细代码


package com.yunwuyun.easy.settlement.strategy;import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.write.handler.RowWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.yunwuyun.easy.commons.utils.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;import java.lang.reflect.Field;
import java.util.*;/*** @Author: Carl* @Date: 2022/12/10/10:20* @Description: RowWriteHandler*/
public class CustomMergeStrategy1 implements RowWriteHandler {private Map<Integer,Integer> map = new HashMap<>();private String companyName;private String glpName;public CustomMergeStrategy1(Map<Integer,Integer> map,String companyName,String glpName) {this.map = map;this.companyName = companyName;this.glpName = glpName;}@Overridepublic void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Integer integer, Integer integer1, Boolean aBoolean) {}@Overridepublic void afterRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer integer, Boolean aBoolean) {}@Overridepublic void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer integer, Boolean aBoolean) {// 如果是标题,则直接返回if (aBoolean) {return;}// 获取当前sheetSheet sheet = writeSheetHolder.getSheet();int rowNum = row.getRowNum();titleHandle(sheet,companyName,glpName);decimalHandle(sheet,integer,aBoolean);if (rowNum <= 2) {return;}Integer lastRowNum = map.get(rowNum);if(-1 == lastRowNum) {return;}//合并单元格区域只有一个单元格时,不合并for (int i = 0; i < 3; i++) {//合并单元格区域只有一个单元格时,不合并if (rowNum == lastRowNum && i == i) {return;}CellRangeAddress cellRangeAddress = new CellRangeAddress(rowNum, lastRowNum, i, i);sheet.addMergedRegionUnsafe(cellRangeAddress);}for (int i = 10; i < 12; i++) {//合并单元格区域只有一个单元格时,不合并if (rowNum == lastRowNum && i == i) {return;}CellRangeAddress cellRangeAddress1 = new CellRangeAddress(rowNum, lastRowNum, i, i);sheet.addMergedRegionUnsafe(cellRangeAddress1);}}private void titleHandle(Sheet sheet, String companyName, String glpName) {Workbook workbook = sheet.getWorkbook();Font font = workbook.createFont();font.setBold(true);font.setFontHeightInPoints((short)14);CellStyle cellStyle = workbook.createCellStyle();cellStyle.setAlignment(HorizontalAlignment.LEFT);cellStyle.setFont(font);for (int i = 0; i < 7; i++) {Cell cell0 = sheet.getRow(1).getCell(i);cell0.setCellValue(companyName);cell0.setCellStyle(cellStyle);}CellStyle cellStyle1 = workbook.createCellStyle();cellStyle1.setAlignment(HorizontalAlignment.RIGHT);cellStyle1.setFont(font);for (int i = 7; i < 12; i++) {Cell cell7 = sheet.getRow(1).getCell(i);cell7.setCellValue(glpName);cell7.setCellStyle(cellStyle1);}}/*** 金额列处理* @param sheet* @param integer* @param aBoolean*/private void decimalHandle(Sheet sheet, Integer integer, Boolean aBoolean) {if(!aBoolean) {Workbook workbook = sheet.getWorkbook();CellStyle cellStyle = workbook.createCellStyle();cellStyle.setAlignment(HorizontalAlignment.RIGHT);Cell cell = sheet.getRow(integer+3).getCell(6);cell.setCellStyle(cellStyle);handleDecimalValue(cell);Cell cell8 = sheet.getRow(integer+3).getCell(8);cell8.setCellStyle(cellStyle);handleDecimalValue(cell8);Cell cell9 = sheet.getRow(integer+3).getCell(9);cell9.setCellStyle(cellStyle);handleDecimalValue(cell9);}}private void handleDecimalValue(Cell cell) {String stringCellValue = cell.getStringCellValue();String[] split = stringCellValue.split("\\.");String preValue = split[0];char[] chars = preValue.toCharArray();String str = "";for (int i = chars.length - 1,j=1; i >= 0; i--,j++) {str += chars[i];if(j % 3 == 0 && i != 0) {str += ",";}}str = StringUtils.reverse(str);str = str+"."+split[1];cell.setCellValue(str);}}

下一篇咱们来写一下(我还没想好)吧

(相别容易见时难,别后相思独凄然,千山万水总是情,点个关注行不行)

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Adobe Premiere Pro:掌控视频剪辑的魔法之手,让你的创作腾飞!

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是尘缘&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f449;点击这里&#xff0c;就可以查看我的主页啦&#xff01;&#x1f447;&#x…

DC-DC模块升压电源直流隔离低压升高压正负输出变换器

特点 效率高达 80%以上1*1英寸标准封装电源正负双输出稳压输出工作温度: -40℃~85℃阻燃封装&#xff0c;满足UL94-V0 要求温度特性好可直接焊在PCB 上 应用 HRA 0.2~8W 系列模块电源是一种DC-DC升压变换器。该模块电源的输入电压分为&#xff1a;4.5~9V、9~18V、及18~36V、36…

基于YOLOv5的火灾烟雾检测系统

目录 1&#xff0c;YOLOv5算法原理介绍 2&#xff0c;代码实现 3&#xff0c;结果展示 1&#xff0c;YOLOv5算法原理介绍 YOLOv5是目前应用广泛的目标检测算法之一&#xff0c;其主要结构分为两个部分&#xff1a;骨干网络和检测头。 骨干网络采用的是CSPDarknet53&#xff…

②. GPT错误:图片尺寸写入excel权限错误

꧂问题最初 ꧁ input输入图片路径 print图片尺寸 大小 长宽高 有颜色占比>0.001的按照大小排序将打印信息存储excel表格文件名 表格路径 图片大小 尺寸 颜色类型 占比信息input输入的是文件就处理文件 是文件夹&#x1f4c1;就处理文件。路径下的图片 1. 是处理本路径图片 …

比特币有助减少腐败;微软 Copilot 每月赔 20 美元;AIGC 明年会“洗冷水澡”丨 RTE 开发者日报 Vol.64

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE &#xff08;Real Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…

Ubuntu安装QQ

原文网址&#xff1a;2023在Ubuntu安装最新版QQ Linux v3.1.0 - 哔哩哔哩 作者&#xff1a;sprlightning https://www.bilibili.com/read/cv22100663/ 出处&#xff1a;bilibili 2022年末QQ推出了QQ Linux v3.0系列&#xff0c;目前最新版是今年2月24日推出的v3.1.0版本。注意…

用vscode进行远程主机开发

文章目录 插件操作步骤FQA 插件 Remote - SSH - 通过使用 SSH 打开远程计算机或者VM上的文件夹&#xff0c;来连接到任何位置。 操作步骤 使用Vscode利用Remote进行远端开发必须现在Vscode内安装插件 安装完成后&#xff0c;底部工具栏会出现一个绿色按钮&#xff0c;如下…

Python库学习(九):Numpy[续篇三]:数组运算

NumPy是用于数值计算的强大工具&#xff0c;提供了许多数组运算和数学函数&#xff0c;允许你执行各种操作&#xff0c;包括基本运算、统计计算、线性代数、元素级操作等 1.基本运算 1.1 四则运算 NumPy数组支持基本的四则运算&#xff08;加法、减法、乘法和除法&#xff09;…

IntelliJ IDEA失焦自动重启服务的解决方法

IDEA 热部署特性 热部署&#xff0c;即应用正属于运行状态时&#xff0c;我们对应用源码进行了修改更新&#xff0c;在不重新启动应用的情况下&#xff0c;可以能够自动的把更新的内容重新进行编译并部署到服务器上&#xff0c;使修改立即生效。 现象 在使用 IntelliJ IDEA运…

实现基于 GitLab 的数据库 CI/CD 最佳实践

数据库变更一直是整个应用发布过程中效率最低、流程最复杂、风险最高的环节&#xff0c;也是 DevOps 流程中最难以攻克的阵地。那我们是否能在具体的 CI/CD 流程中&#xff0c;像处理代码那样处理数据库变更呢&#xff1f; DORA 调研报告 DORA&#xff08;DevOps Research &am…

练[GYCTF2020]EasyThinking

[GYCTF2020]EasyThinking 文章目录 [GYCTF2020]EasyThinking掌握知识解题思路还得靠大佬正式开始 关键paylaod 掌握知识 ​ thinkphpV6任意文件操作漏洞&#xff0c;代码分析写入session文件的参数&#xff0c;源码泄露&#xff0c;使用蚁剑插件disable_functions绕过终端无回…

【算法设计与分析】— —单源最短路径的贪心算法

&#x1f383;欢迎大家前去观看我的算法设计与分析专栏&#xff1a; 算法设计与分析_IT闫的博客-CSDN博客 希望对大家有所帮助&#xff01; &#x1f383;个人专栏&#xff1a; &#x1f42c; 算法设计与分析&#xff1a;算法设计与分析_IT闫的博客-CSDN博客 &#x1f433;Java…

Spring 复习笔记

目录 第一步存 Bean第二步获取并使用 Bean依赖查找的方式ApplicationContext vs BeanFactory 更简单的存储 Bean1. 配合五大类注解使用2. 方法上添加注解 Bean 更简单的获取 Bean Spring IoC 容器管理的资源就是对象&#xff0c;这个对象也叫做 Bean。Spring 作为一个 IoC 容器…

zabbix自定义监控内容和自动发现

6 目录 一、自定义监控内容&#xff1a; 1.明确需要执行的 linux 命令 2.创建 zabbix 的监控项配置文件&#xff0c;用于自定义 key&#xff1a; 3. 在 Web 页面创建自定义监控项模板&#xff1a; 3.1 创建模板&#xff1a; 3.2 创建监控项&#xff1a; 3.3 创建触发器&#…

VxeTable 表格组件推荐

VxeTable 表格组件推荐 https://vxetable.cn 在前端开发中&#xff0c;表格组件是不可或缺的一部分&#xff0c;它们用于展示和管理数据&#xff0c;为用户提供了重要的数据交互功能。VxeTable 是一个优秀的 Vue 表格组件&#xff0c;它提供了丰富的功能和灵活的配置选项&…

关于优先队列的一点细节

在使用优先队列PriorityQueue时&#xff0c;默认的是升序排列&#xff0c;自己可以指定比较器改为降序排列&#xff0c;例如Collections.reverseOrder()等。 但是在我做力扣的过程中&#xff0c;简单的用一个list的addAll方法添加了优先队列里边所有元素&#xff0c;结果发现添…

【Spring】Spring MVC 程序开发

Spring MVC 程序开发 一. 什么是 Spring MVC1. MVC2. Spring、Spring Boot 与 Spring MVC 二. 创建 Spring MVC 项目1. 创建项目2. 用户和程序的映射3. 获取用户请求参数①. 获取单个参数②. 获取多个参数③. 传递对象④. 后端参数重命名&#xff08;后端参数映射&#xff09;R…

Django开发之进阶篇

Django进阶篇 一、Django学习之模板二、Django学习之中间件默认中间件自定义中间件 三、Django学习之ORM定义模型类生成数据库表操作数据库添加查询修改删除 一、Django学习之模板 在 Django 中&#xff0c;模板&#xff08;Template&#xff09;是用于生成动态 HTML&#xff…

vue-6

一、声明式导航-导航链接 1.需求 实现导航高亮效果 如果使用a标签进行跳转的话&#xff0c;需要给当前跳转的导航加样式&#xff0c;同时要移除上一个a标签的样式&#xff0c;太麻烦&#xff01;&#xff01;&#xff01; 2.解决方案 vue-router 提供了一个全局组件 router…