Excel 合并列数据

场景

要求每行数据的每个字段的内容不能以 [2,3,33,22] 形式展示 要求独立成列形式如下

代码

maven 依赖

        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.17</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.17</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-scratchpad</artifactId>
            <version>3.17</version>
        </dependency>

 主代码类

package org.fri.controller;

import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.util.CellRangeAddress;
import org.fri.entity.ExportExample;
import org.fri.entity.MergeVo;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

@RequestMapping(value = "/excel")
@RestController
@Slf4j
public class ExcelController {

    @RequestMapping(value = "/export")
    public void exportExcel(HttpServletResponse response) throws NoSuchFieldException, IllegalAccessException, InstantiationException {
        ExportExample q = new ExportExample("漩涡鸣人", 20, "男", "火影,吊车尾,后宫之术创始人", "隐分身,仙术,螺旋丸");
        ExportExample y = new ExportExample("宇智波 佐助", 27, "男", "宇智波一族", "装B");
        ExportExample f = new ExportExample("千手扉间", 100, "男", "火影,禁术编写者", "水遁,黑暗术");
        LinkedHashMap<String, String> title = new LinkedHashMap<>();
        title.put("name","名称");
        title.put("age","年龄");
        title.put("sex","性别");
        title.put("roles","角色");
        title.put("technique","技能");
        List<ExportExample> list = Arrays.asList(q, y, f);
        exportExcel(list, ExportExample.class,title, response);
    }


    public <T> void exportExcel(List<T> list, Class<T> T,LinkedHashMap<String, String> title,HttpServletResponse response) throws NoSuchFieldException, IllegalAccessException, InstantiationException {
        T t = T.newInstance();
        LinkedHashMap<String, MergeVo> merged = new LinkedHashMap<>();
        Field[] fields = t.getClass().getDeclaredFields();

        //查询出所有列值
        for (Field field : fields) {
            field.setAccessible(true);
            merged.put(field.getName(), new MergeVo(field.getName(), 0, 1));
        }

        //计算所需要合并列的最大项
        for (T s : list) {
            for (String key : merged.keySet()) {
                Field field = t.getClass().getDeclaredField(key);
                field.setAccessible(true);
                String value = field.get(s).toString();
                if (merged.get(key).getTitleMaxColumNumber() < value.split(",").length) {
                    merged.get(key).setTitleMaxColumNumber(value.split(",").length);
                }
            }
        }
        //计算没列的开始位置
        int j = 0;
        for (Map.Entry<String, MergeVo> et : merged.entrySet()) {
            et.getValue().setStartRowIndex(j);
            j = j + et.getValue().getTitleMaxColumNumber();
        }
        HSSFWorkbook workBook = null;
        OutputStream out = null;
        try {
            workBook = new HSSFWorkbook();
            HSSFSheet sheet = workBook.createSheet();
            HSSFRow titleRows = sheet.createRow(0);

            /*//设置表头样式
            CellStyle colorStyle = workBook.createCellStyle();
            colorStyle.setFillForegroundColor(IndexedColors.LIGHT_BLUE.getIndex());
            colorStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
            Font font = workBook.createFont();
            font.setBold(true);
            font.setFontHeightInPoints((short) 16);
            // 设置字体大小为 16*/
            // 构建表头
            merged.forEach((key1, value) -> {
                merged(merged, sheet, titleRows, key1, title.get(key1));
            });
            // 构建数据
            int rowNumbers = 0;
            for (T e : list) {
                rowNumbers++;
                HSSFRow nextRow = sheet.createRow(rowNumbers);
                for (String key1 : merged.keySet()) {
                    Field field = t.getClass().getDeclaredField(key1);
                    field.setAccessible(true);
                    String value = field.get(e).toString();
                    merged(merged, sheet, nextRow, key1, value);
                }
            }
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
            String dateNow = formatter.format(LocalDateTime.now());
            String fileName = dateNow + ".xls";
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/x-msdownload");
            response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
            out = response.getOutputStream();
            workBook.write(out);


        } catch (IOException e) {
            log.error(e.getMessage());
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (workBook != null) {
                    workBook.close();
                }
            } catch (IOException e) {
                log.error(e.getMessage());
            }
        }
    }

    /**
     * 合并规则设定
     *
     * @param mergeVoMap 表头配置信息
     * @param sheet      所属sheet
     * @param row        所属行
     * @param key        所属key
     * @param value      值
     */
    private void merged(LinkedHashMap<String, MergeVo> mergeVoMap, HSSFSheet sheet, HSSFRow row, String
            key, String value) {
        MergeVo mergeVo = mergeVoMap.get(key);
        String[] split = value.replace("[", "").replace("]", "").split(",");
        if (mergeVo.getTitleMaxColumNumber() > 1) {
            if (split.length > 1) {
                int length = split.length;
                List<int[]> ints = splitIntoSegments(mergeVo.getStartRowIndex(), mergeVo.getStartRowIndex() + mergeVo.getTitleMaxColumNumber(), length);
                for (int j = 0; j < ints.size(); j++) {
                    int[] anInt = ints.get(j);
                    row.createCell(anInt[0]).setCellValue(split[j]);
                    if (anInt[1] - anInt[0] > 0) {
                        sheet.addMergedRegion(new CellRangeAddress(row.getRowNum(), row.getRowNum(), anInt[0], anInt[1]));
                    }
                }
            } else {
                row.createCell(mergeVo.getStartRowIndex()).setCellValue(value);
                sheet.addMergedRegion(new CellRangeAddress(row.getRowNum(), row.getRowNum(), mergeVo.getStartRowIndex(), mergeVo.getStartRowIndex() + mergeVo.getTitleMaxColumNumber() - 1));
            }
        } else {
            row.createCell(mergeVo.getStartRowIndex()).setCellValue(value);
        }
    }

    /**
     * 列合并分割分配
     *
     * @param s
     * @param e
     * @param x
     * @return
     */
    public static List<int[]> splitIntoSegments(int s, int e, int x) {
        int i = e - s;
        List<int[]> segments = new ArrayList<>();
        int baseLength = i / x; // 每段的基本长度
        int remainder = i % x;   // 剩余的数值
        int start = 0;          // 起始值

        for (int k = 1; k <= x; k++) {
            int length = baseLength; // 当前段的长度
            if (k <= remainder) {
                length += 1; // 分配剩余的数值
            }
            int end = start + length - 1; // 结束值
            segments.add(new int[]{start + s, end + s}); // 添加到结果列表
            start = end + 1; // 更新下一段的起始值
        }
        return segments;
    }
}

 合并项辅助类

package org.fri.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class MergeVo {
    private String key;
    private int startRowIndex;
    private int titleMaxColumNumber;
}

 导出测试类

package org.fri.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author Lenovo
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ExportExample {
    private String name;
    private Integer age;
    private String sex;
    private String roles;
    private String technique;
}

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

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

相关文章

从零到一:基于Rook构建云原生Ceph存储的全面指南(下)

接上篇&#xff1a;《从零到一&#xff1a;基于Rook构建云原生Ceph存储的全面指南&#xff08;上&#xff09;》 链接: link 六.Rook部署云原生CephFS文件系统 6.1 部署cephfs storageclass cephfs文件系统与RBD服务类似&#xff0c;要想在kubernetes pod里使用cephfs&#…

人工智能之深度学习的革命性突破

深度学习的革命性突破 深度学习是机器学习的一个子领域&#xff0c;通过模拟人脑神经网络的结构和功能&#xff0c;实现对复杂数据的高效处理。近年来&#xff0c;深度学习在计算机视觉、自然语言处理、语音识别等领域取得了革命性突破。本文将深入探讨深度学习的核心架构、突…

C#快速排序QuickSort将递归算法修改为堆栈Stack非递归方式

我们知道,方法的调用是采用Stack的方式[后进先出:LIFO], 在DeepSeek中快速搜索C#快速排序, 搜索结果如图: 我们会发现是采用递归的方式 . 递归的优点: 简单粗暴,类似于直接写数学公式,因代码量较少,易于理解.递归与循环迭代的运行次数都是一致的 递归的缺点: 占用大量的内…

Django开发入门 – 3.用Django创建一个Web项目

Django开发入门 – 3.用Django创建一个Web项目 Build A Web Based Project With Django By JacksonML 本文简要介绍如何利用最新版Python 3.13.2来搭建Django环境&#xff0c;以及创建第一个Django Web应用项目&#xff0c;并能够运行Django Web服务器。 创建该Django项目需…

SQL布尔盲注、时间盲注

一、布尔盲注 布尔盲注&#xff08;Boolean-based Blind SQL Injection&#xff09;是一种SQL注入技术&#xff0c;用于在应用程序不直接显示数据库查询结果的情况下&#xff0c;通过构造特定的SQL查询并根据页面返回的不同结果来推测数据库中的信息。这种方法依赖于SQL查询的…

【Python网络爬虫】爬取网站图片实战

【Python网络爬虫】爬取网站图片实战 Scrapying Images on Website in Action By Jackson@ML *声明:本文简要介绍如何利用Python爬取网站数据图片,仅供学习交流。如涉及敏感图片或者违禁事项,请注意规避;笔者不承担相关责任。 1. 创建Python项目 1) 获取和安装最新版…

【docker知识】快速找出服务器中占用内存较高的容器

本文由Markdown语法编辑器编辑完成。 1.背景&#xff1a; 近期在处理现场问题&#xff0c;观察服务器时&#xff0c;会遇到某些进程占用较高内存的情况。由于我们的服务&#xff0c;基本上都是以容器的方式在运行&#xff0c;因此就需要找到&#xff0c;到底是哪个容器&#…

图数据库neo4j进阶(一):csv文件导入节点及关系

CSV 一、load csv二、neo4j-admin import<一>、导入入口<二>、文件准备<三>、命令详解 一、load csv 在neo4j Browser中使用Cypher语句LOAD CSV,对于数据量比较大的情况,建议先运行create constraint语句来生成约束 create constraint for (s:Student) req…

10. Hbase Compaction命令

一. 什么是Compaction 在 HBase 中&#xff0c;频繁进行数据插入、更新和删除操作会生成许多小的 HFile&#xff0c;当 HFile 数量增多时&#xff0c;会影响HBase的读写性能。此外&#xff0c;垃圾数据的存在也会增加存储需求。因此&#xff0c;定期进行 Compact操作&#xff…

【工业场景】用YOLOv8实现火灾识别

火灾识别任务是工业领域急需关注的重点安全事项,其应用场景和背景意义主要体现在以下几个方面: 应用场景:工业场所:在工厂、仓库等工业场所中,火灾是造成重大财产损失和人员伤亡的主要原因之一。利用火灾识别技术可以及时发现火灾迹象,采取相应的应急措施,保障人员安全和…

软件开发 | GitHub企业版常见问题解读

什么是GitHub企业版&#xff1f; GitHub企业版是一个企业级软件开发平台&#xff0c;专为现代化开发的复杂工作流程而设计。 作为可扩展的平台解决方案&#xff0c;GitHub企业版使组织能够无缝集成其他工具和功能&#xff0c;并根据特定需求定制开发环境&#xff0c;提高整体…

CEF132 编译指南 MacOS 篇 - depot_tools 安装与配置 (四)

1. 引言 在 CEF132&#xff08;Chromium Embedded Framework&#xff09;的编译过程中&#xff0c;depot_tools 扮演着举足轻重的角色。这套由 Chromium 项目精心打造的脚本和工具集&#xff0c;专门用于获取、管理和更新 Chromium 及其相关项目&#xff08;包括 CEF&#xff…

NLP Word Embeddings

Word representation One-hot形式 在上一周介绍RNN类模型时&#xff0c;使用了One-hot向量来表示单词的方式。它的缺点是将每个单词视为独立的&#xff0c;算法很难学习到单词之间的关系。 比如下面的例子&#xff0c;即使语言模型已经知道orange juice是常用组合词&#xf…

python实现YouTube关键词爬虫(2025/02/11)

在当今数字化时代&#xff0c;YouTube作为全球最大的视频分享平台之一&#xff0c;拥有海量的视频资源。无论是进行市场调研、内容创作还是学术研究&#xff0c;能够高效地获取YouTube上的相关视频信息都显得尤为重要。今天&#xff0c;我将为大家介绍一个基于Python实现的YouT…

Jenkins 配置 Git Parameter 四

Jenkins 配置 Git Parameter 四 一、开启 项目参数设置 勾选 This project is parameterised 二、添加 Git Parameter 如果此处不显示 Git Parameter 说明 Jenkins 还没有安装 Git Parameter plugin 插件&#xff0c;请先安装插件 Jenkins 安装插件 三、设置基本参数 点击…

自然语言处理NLP入门 -- 第三节词袋模型与 TF-IDF

目标 了解词袋模型&#xff08;BoW&#xff09;和 TF-IDF 的概念通过实际示例展示 BoW 和 TF-IDF 如何将文本转换为数值表示详细讲解 Scikit-learn 的实现方法通过代码示例加深理解归纳学习难点&#xff0c;并提供课后练习和讲解 3.1 词袋模型&#xff08;Bag of Words, BoW&a…

C++模板编程——typelist的实现

文章最后给出了汇总的代码&#xff0c;可直接运行 1. typelist是什么 typelist是一种用来操作类型的容器。和我们所熟知的vector、list、deque类似&#xff0c;只不过typelist存储的不是变量&#xff0c;而是类型。 typelist简单来说就是一个类型容器&#xff0c;能够提供一…

fastadmin 接口请求提示跨域

问题描述 小程序项目&#xff0c;内嵌h5页面&#xff0c;在h5页面调用后端php接口&#xff0c;提示跨域。网上查找解决方案如下&#xff1a; 1&#xff0c;设置header // 在入口文件index.php直接写入直接写入 header("Access-Control-Allow-Origin:*"); header(&q…

只需三步!5分钟本地部署deep seek——MAC环境

MAC本地部署deep seek 第一步:下载Ollama第二步:下载deepseek-r1模型第三步&#xff1a;安装谷歌浏览器插件 第一步:下载Ollama 打开此网址&#xff1a;https://ollama.com/&#xff0c;点击下载即可&#xff0c;如果网络比较慢可使用文末百度网盘链接 注&#xff1a;Ollama是…

idea 错误: 找不到或无法加载主类 @C:\Users\admin\AppData\Local\Temp\idea_arg_file1549212448

idea 错误: 找不到或无法加载主类 C:\Users\admin\AppData\Local\Temp\idea_arg_file1549212448 该错误往往和左下角爱弹出的如下提示是一个意思 Error running ‘PayV3Test1.testTransferBatchesBatchId’ Error running PayV3Test1.testTransferBatchesBatchId. Command lin…