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.hqwc.cn/news/129807.html

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

相关文章

小谈设计模式(24)—命令模式

小谈设计模式&#xff08;24&#xff09;—命令模式 专栏介绍专栏地址专栏介绍 命令模式角色分析命令&#xff08;Command&#xff09;具体命令&#xff08;ConcreteCommand&#xff09;接收者&#xff08;Receiver&#xff09;调用者&#xff08;Invoker&#xff09;客户端&am…

华为云云耀云服务器L实例评测|使用redis事务和lua脚本

文章目录 云服务器的类型云服务优点redis一&#xff0c;关系型数据库&#xff08;sqlserver&#xff0c;mysql&#xff0c;oracle&#xff09;的事务隔离机制说明&#xff1a;redis事务机制 lualua脚本好处&#xff1a;一&#xff0c;怎么在redis中使用lua脚本二&#xff0c;脚…

基于安卓android微信小程序宠物交易小程序

运行环境 开发语言&#xff1a;Java 框架&#xff1a;ssm JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.3.9 小程序框架&…

【RabbitMQ】docker rabbitmq集群 docker搭建rabbitmq集群

docker rabbitmq集群 docker搭建rabbitmq集群 RabbitMQ提供了两种常用的集群模式 1.普通集群模式 2.镜像集群模式 普通集群模式只能同步主节点上的交换机和队列信息&#xff0c;但对于队列中的消息不做同步&#xff0c;主节点宕机也不能进行切换&#xff08;故障转移&#xff…

新增TOP!10月SCI/SSCI/EI刊源表已更新!

2023年10月SCI/SSCI/EI期刊目录更新 2023年10月份刊源表已更新&#xff01;计算机领域新增TOP期刊、SSCI、EI新增多本好刊&#xff0c;重点期刊如下&#xff0c;相关领域作者注意投稿截止时间&#xff01; 01 计算机领域 02 医学与制药领域 03 工程综合领域 04 环境生物化学地…

区块链技术在金融领域的应用场景

区块链技术在金融领域具有广泛的应用场景&#xff0c;它可以提供更安全、透明、高效和可信的金融服务。以下是一些区块链金融的主要应用场景&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 1.数字货币…

SpringBoot 如何配置 OAuth2 认证

在Spring Boot中配置OAuth2认证 OAuth2是一种用于授权的开放标准&#xff0c;允许应用程序安全地访问用户的资源。Spring Boot提供了强大的支持&#xff0c;使得在应用程序中配置OAuth2认证变得非常容易。本文将介绍如何在Spring Boot中配置OAuth2认证&#xff0c;以便您可以在…

光伏发电预测(GRU模型,Python代码)

运行效果&#xff1a;光伏发电预测&#xff08;GRU模型&#xff0c;Python代码&#xff09;_哔哩哔哩_bilibili 所有库的版本&#xff1a; 1.数据集&#xff08;连续10年不间断采集三个光伏电站的发电量及天气情况&#xff0c;每隔半个小时采集一次信息&#xff0c;因此&…

【HTML5】语义化标签记录

前言 防止一个页面中全部都是div&#xff0c;或者ul li&#xff0c;在html5推出了很多语义化标签 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 常用语义化案例 一般我用的多的是header&#xff0c;main&#xff0c;footer 这些标签不难理解&#x…

vue3 集成 tailwindcss

tailwindcss 介绍 Tailwind CSS 是一个流行的前端框架&#xff0c;用于构建现代、响应式的网页和 Web 应用程序。它的设计理念是提供一组可复用的简单、低级别的 CSS 类&#xff0c;这些类可以直接应用到 HTML 元素上&#xff0c;从而加速开发过程并提高样式一致性。 主要特点…

Windows服务器获取本地文件夹文件

1、直接复制粘贴 通过远程连接到这个服务器&#xff0c;然后本机到服务器能直接粘贴复制文件上去 注&#xff1a;首先服务器要先开启远程桌面哦 2、Windows远程连接 有的不能复制粘贴的&#xff0c;可以用第二种方法。 ①、windowsR,输入mstsc ②、点击“选项”按钮&#x…

Rust Pin UnPin Async Await

原文地址 为了保证概念的严谨性&#xff0c;翻译时保留了英文原文。 In this post, we explore cooperative multitasking and the async/await feature of Rust. We take a detailed look at how async/await works in Rust, including the design of the Future trait, the…