excel单元格合并策略

news2024/12/27 13:29:08

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的样式


@Override
    public 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 {


    @Override
    public void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Integer integer, Integer integer1, Boolean aBoolean) {

    }

    @Override
    public void afterRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer integer, Boolean aBoolean) {

    }

    @Override
    public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer integer, Boolean aBoolean) {
        if (row.getRowNum() > 1) {
            return;
        }
        // 获取当前sheet
        Sheet 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;
    }


    @Override
    public void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Integer integer, Integer integer1, Boolean aBoolean) {

    }

    @Override
    public void afterRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer integer, Boolean aBoolean) {

    }

    @Override
    public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer integer, Boolean aBoolean) {
        // 如果是标题,则直接返回
        if (aBoolean) {
            return;
        }

        // 获取当前sheet
        Sheet 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.coloradmin.cn/o/1075887.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

管理Linux的联网

1. RHEL9版本特点 在RHEL7版本中&#xff0c;同时支持network.service和NetworkManager.service&#xff08;简称NM&#xff09;。 在RHEL8上默认只能通过NM进行网络配置&#xff0c;包括动态ip和静态ip,若不开启NM&#xff0c;否则无法使用网络 RHEL8依然支持network.service&…

【工具软件】Nativefier——把网页打包成exe软件

官方文档 安装 npm install nativefier -g使用 在 nativefier 后加上需要转换的网站地址, 比如: nativefier "https://blog.csdn.net/IAIPython?typeblog"第一次打包需要下载 Eletron 框架, 很慢… 运行完毕, 会生成一个应用, 路径一般为C:\Users\用户名… 如图…

前后端分离项目-基于springboot+vue的图书馆管理系统的设计与实现(内含代码+文档+报告)

博主介绍&#xff1a;✌全网粉丝10W,前互联网大厂软件研发、集结硕博英豪成立工作室。专注于计算机相关专业毕业设计项目实战6年之久&#xff0c;选择我们就是选择放心、选择安心毕业✌ &#x1f345;由于篇幅限制&#xff0c;想要获取完整文章或者源码&#xff0c;或者代做&am…

Servlet开发步骤

标准Java Web工程结构 pom.xml中提供servlet依赖 1.创建java类&#xff0c;继承HttpServlet 2.重写service方法&#xff0c;处理请求&#xff0c;生成响应 3.配置web.xml&#xff0c;绑定访问地址 Servlet接收请求参数 request.getParameter() 接收单个参数 request.ge…

区块链游戏的开发框架

链游&#xff08;Blockchain Games&#xff09;是基于区块链技术构建的游戏。它们与传统游戏有一些显著不同之处&#xff0c;因此需要特定的开发框架和工具。以下是一些用于链游开发的开发框架及其特点&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专…

一站式 API 管理和测试工具:PostCat 轻松完成接口调测 | 开源日报 No.49

rubickCenter/rubick Stars: 5.0k License: MIT Rubick 是一个基于 electron 开源工具箱的项目&#xff0c;它允许用户自由集成丰富插件来创建最终桌面效率工具。该项目以 Dota 英雄中的 Rubick 为名&#xff0c;因为他可以使用其他英雄作为插件完成任务。以下是 Rubick 的主要…

ant-design-vue 实现表格表头纵排列

结果如图&#xff1a; 区域&#xff0c;成功率&#xff0c;清单率为表头&#xff0c;右侧为动态的数据 废话不多说直接上代码&#xff1a; 1.先声明表格&#xff0c;使用框架自带a-table&#xff0c;核心点就在data和columns上 <div style"margin-bottom: 60px;"…

OpenVPN客户端安装测试

文章目录 一 OpenVPN客户端安装二 OpenVPN客户端设置三 OpenVPN客户端测试 一 OpenVPN客户端安装 OpenVPN有很多客户端&#xff0c;本文采用windows系统的OpenVPN Connect 3.4.2 (64-bit) 客户端进行安装和测试。 下载 下载地址&#xff1a;https://www.filehorse.com/downloa…

【算法与数据结构】二叉树的三种遍历代码实现(下)—— 非递归方式实现(大量图解)

上篇&#xff1a;【算法与数据结构】二叉树的三种遍历代码实现&#xff08;上&#xff09;—— 用递归序知识点讲解_Hacynn的博客-CSDN博客https://blog.csdn.net/zzzzzhxxx/article/details/133609612?spm1001.2014.3001.5502 目录 前言 1、先序遍历 1.1、详细图解描述 …

品牌被低价侵权了怎么处理

各品牌在销售过程中&#xff0c;会不断拓展销售渠道&#xff0c;主要分为线上和线下两个类型&#xff0c;线下渠道的低价侵权相较于线上会难发现一些&#xff0c;线上低价可以通过实时监测的方式&#xff0c;发现低价链接&#xff0c;再针对链接中的不同侵权情况进行处理。 力维…

【算法练习Day16】找树左下角的值路径总和 从中序与后序遍历序列构造二叉树

​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 找树左下角的值路径总和从中…

PDF编辑和OCR文字识别工具ABBYY FineReader PDF

ABBYY FineReader PDF是一款专业的OCR文字识别和PDF编辑工具&#xff0c;可以帮助用户更好地处理和管理PDF文档。以下是ABBYY FineReader PDF的一些特点&#xff1a; 1. 文字识别精准&#xff1a;ABBYY FineReader PDF具有强大的OCR文字识别功能&#xff0c;可以将PDF中的文字…

大数据学习(2)Hadoop-分布式资源计算hive(1)

&&大数据学习&& &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 承认自己的无知&#xff0c;乃是开启智慧的大门 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4dd;支持一下博>主哦&#x…

浅谈风力发电场集中监控系统解决方案

作为清洁能源之一&#xff0c;风力发电场近几年装机容量快速增长。8月17日&#xff0c;国家能源局发布1-7月份全国电力工业统计数据。截至7月底&#xff0c;全国累计发电装机容量约27.4亿千瓦&#xff0c;同比增长11.5%。其中&#xff0c;太阳能发电装机容量约4.9亿千瓦&#x…

绝地求生大吃鸡攻略,让你成为顶级战士!

近年来&#xff0c;绝地求生越来越受到玩家们的喜爱&#xff0c;吃鸡成为了很多人的娱乐方式。作为一个资深吃鸡玩家&#xff0c;今天我要和大家分享一些提高战斗力的干货&#xff0c;以及一些方便吃鸡作图与查询的实用工具。 首先&#xff0c;提高战斗力是吃鸡游戏中最重要的一…

青菜学蒸馒头

作为一个会写代码的厨师&#xff0c;做好一笼松软可口的馒头那是必修的基本功&#xff0c;今天我就来试验一把&#xff0c;具体过程如下&#xff1a; 一、材料准备 1、200克面粉 2、2克干酵母粉 3、35度左右温开水一碗 4、白糖少许 二、制作步骤 1、面粉的选择 面粉的种…

html调用手机打电话、发短信网页源码/热门挪车自动拨打电话、发送短信html源码

源码介绍&#xff1a; 这个是自动拨打发送挪车短信电话源码&#xff0c;纯html临时停车挪车网站源码。利用html拨打电话、发送短信链接&#xff0c;js拨打电话。可以html调用手机打电话、发短信功能。使用H5移动HTML特殊链接实现打电话,发短信,发邮件的功能&#xff0c;非常方…

回归算法全解析!一文读懂机器学习中的回归模型

目录 一、引言回归问题的重要性文章目的和结构概览 二、回归基础什么是回归问题例子&#xff1a; 回归与分类的区别例子&#xff1a; 回归问题的应用场景例子&#xff1a; 三、常见回归算法3.1 线性回归数学原理代码实现输出例子&#xff1a; 3.2 多项式回归数学原理代码实现输…

2023年中国汽车后市场行业研究报告

第一章 行业概况 1.1 定义 汽车后市场行业在中国的快速崛起&#xff0c;反映了汽车产业链的完善和消费者需求的多样化。这个行业涵盖了汽车销售后&#xff0c;围绕汽车使用过程中涌现的各类服务和交易活动。它不仅为消费者提供了汽车使用过程中所需的全方位服务&#xff0c;也…

【C/C++笔试练习】常见进制转换、宏的定义和特点、sizeof与strlen、字符串函数、统计回文、连续最大和

文章目录 C/C笔试练习1.常见进制转换&#xff08;1&#xff09;进制前缀&#xff08;2&#xff09;进制转换 2.宏的定义和特点&#xff08;3&#xff09;宏的定义&#xff08;4&#xff09;有关宏的计算 3.sizeof与strlen&#xff08;5&#xff09;sizeof和strlen的差别 4.字符…