Excel 合并列数据

场景

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

代码

maven 依赖

XML 复制代码
        <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>

主代码类

java 复制代码
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;
    }
}

合并项辅助类

java 复制代码
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;
}

导出测试类

java 复制代码
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;
}
相关推荐
开开心心就好1 小时前
高效Excel合并拆分软件
开发语言·javascript·c#·ocr·排序算法·excel·最小二乘法
沉到海底去吧Go21 小时前
【行驶证识别成表格】批量OCR行驶证识别与Excel自动化处理系统,行驶证扫描件和照片图片识别后保存为Excel表格,基于QT和华为ocr识别的实现教程
自动化·ocr·excel·行驶证识别·行驶证识别表格·批量行驶证读取表格
Abigail_chow2 天前
EXCEL如何快速批量给两字姓名中间加空格
windows·microsoft·excel·学习方法·政务
xiaohezi2 天前
Rag chunk 之:Excel 文档解析
excel
weixin_472339462 天前
python批量解析提取word内容到excel
python·word·excel
3 天前
Unity与Excel表格交互热更方案
unity·游戏引擎·excel
金融小白数据分析之路3 天前
Excel高级函数使用FILTER、UNIQUE、INDEX
excel
未来之窗软件服务3 天前
Excel表格批量下载 CyberWin Excel Doenlaoder 智能编程-——玄武芯辰
excel·批量下载·仙盟创梦ide·东方仙盟
阿斯加德的IT3 天前
Power Automate: 从Excel 选择列,每200条生成一个CSV文件并保存在sharepoint文档库
低代码·excel
步达硬件3 天前
【转bin】EXCEL数据转bin
excel