Java使用poi导出excel针对不同数据列配置设置不同单元格格式(适用于通用导出excel数据)

这篇具有很好参考价值的文章主要介绍了Java使用poi导出excel针对不同数据列配置设置不同单元格格式(适用于通用导出excel数据)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

背景

公司大部分业务都是查询相关的业务, 所以建了一个项目专门做数据查询, 数据中转等抽象通用的业务, 有一天给我安排了一个功能, 做excel导出, 配置好查询sql和表头字段映射后即可导出excel, 无需修改代码
后来因为导出数据要求保留几位小数或者转换成百分比等设置单元格格式需要支持配置化, 由于做数据中转有些系统需要的数据是不需要约束小数的, 所以数据层面不能做约束, 否则就不是真正意义上的通用了

第一版

项目中使用了hutool工具类库, 封装了很多的方法, 大大的降低了开发成本
第一版代码, 想着hutool工具里面有个ExcelUtil的类, 里面的方法对使用poi导出excel进行了封装简化于是就这么写了

实现方案

此处以商品订单为例, 不考虑一笔订单多个商品的情况, 不做单元格合并操作
这里使用的Hutool版本是5.8.15

<dependency>
      <groupId>cn.hutool</groupId>
      <artifactId>hutool-all</artifactId>
      <version>5.8.15</version>
</dependency>

BaseFileUtils.java

public abstract class BaseFileUtils {

    /**
     * 创建xlsx表格
     * @param fileName 文件名
     * @param headList 列头信息
     * @param dataList 数据集
     * @param response /
     */
    public static void writeXlsxByData(String fileName, List<Object> headList, List<List<Object>> dataList, HttpServletResponse response) {
        //创建xlsx格式
        ExcelWriter writer = ExcelUtil.getBigWriter();
        for (int i = 0; i < dataList.size(); i++) {
            writer.setRowHeight(i, 30);
        }
        for (int i = 0; i < headList.size(); i++) {
            writer.setColumnWidth(i, 30);
        }

        writer.writeHeadRow(headList);
        // 一次性写出内容,使用默认样式,强制输出标题
        writer.write(dataList, false);
        writeXlsx2Response(response, writer, fileName);
    }

    /**
     * 将excel写出
     * @param response /
     * @param writer excel信息
     * @param fileName 文件名
     */
    private static void writeXlsx2Response(HttpServletResponse response, ExcelWriter writer, String fileName) {
        //out为OutputStream,需要写出到的目标流
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        response.setHeader("Content-Disposition","attachment;filename=" + fileName);
        try {
            writer.flush(response.getOutputStream(), true);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 关闭writer,释放内存
        writer.close();
    }
}

FileService.java

@Service
public class FileServiceImpl implements IFileService {

    @Override
    public void exportExcel(HttpServletResponse response) {
        //  列头信息
        List<Object> headList = new ArrayList<>(Arrays.asList("订单号", "商品名称", "单价", "数量", "总价", "占收入百分比"));
        //  数据集
        List<Object> data1 = new ArrayList<>();
        data1.add("3123ab3412c3");
        data1.add("鼠标");
        data1.add(new BigDecimal("89.9"));
        data1.add(1);
        data1.add(new BigDecimal("89.9"));
        data1.add(new BigDecimal("0.1"));
        List<Object> data2 = new ArrayList<>();
        data2.add("3123ab3412c4");
        data2.add("键盘");
        data2.add(new BigDecimal("298.9"));
        data2.add(2);
        data2.add(new BigDecimal("597.8"));
        data2.add(new BigDecimal("0.321300"));
        List<Object> data3 = new ArrayList<>();
        data3.add("3123ab3412c5");
        data3.add("显卡");
        data3.add(new BigDecimal("2048.6"));
        data3.add(1);
        data3.add(new BigDecimal("2048.6"));
        data3.add(new BigDecimal("0.5423"));
        List<Object> data4 = new ArrayList<>();
        data4.add("3123ab3412c6");
        data4.add("显示器");
        data4.add(new BigDecimal("1999.9"));
        data4.add(1);
        data4.add(new BigDecimal("1999.9"));
        data4.add(new BigDecimal("0.36740"));
        List<List<Object>> dataList = new ArrayList<>(Arrays.asList(data1, data2, data3, data4));
        BaseFileUtils.writeXlsxByData("订单信息", headList, dataList, response);

    }

FileController.java

@RestController
@RequestMapping("/file")
public class FileController {
    @Resource
    private IFileService fileService;

    @GetMapping("/excel")
    public void exportExcel(HttpServletResponse response) {
        fileService.exportExcel(response);
    }

}

导出结果
java导出excel设置数字类型,笔记,excel,java到此第一版的实现已经完成了

第二版

第二版需要支持单元格格式配置话, 这里的配置是在列头名称的配置那里一起配置写入
原本的列头就只是一个普通字符串"订单号", "商品名称"`, "单价", ...
现在需要额外配置格式的需要改成json字符串, 自定义一些规则, 例如:

{
	"text": "总价",
	"excel_format": {
		number_format: "0.0"
	}
}

{
	"text": "商品名称",
	"excel_format": {
		ground_color: "red"
	}
}

{
	"text": "占收入百分比",
	"excel_format": {
		number_format: "0.00%"
	}
}

理想中的方案

当时因为是用了Hutool的工具包做的, 于是就想着看看这个工具里面是不是有封装一些修改单元格格式的工具方法, 于是找到了以下方法
java导出excel设置数字类型,笔记,excel,java这个是ExcelWriter对象的方法, 该方法可以获取对应的一些样式集
通过一下四个方法
java导出excel设置数字类型,笔记,excel,java根据需要的格式调用上述四个方法
所以基于第一版进行修改如下:
修改writeXlsxByData方法

/**
     * 创建xlsx表格
     *
     * @param fileName 文件名
     * @param headList 列头信息
     * @param dataList 数据集
     * @param response /
     */
    public static void writeXlsxByData(String fileName, List<Object> headList, List<List<Object>> dataList, HttpServletResponse response) {
        //创建xlsx格式
        ExcelWriter writer = ExcelUtil.getBigWriter();
        for (int i = 0; i < dataList.size(); i++) {
            writer.setRowHeight(i, 30);
        }
        List<Object> newHeadList = new ArrayList<>();
        for (int i = 0; i < headList.size(); i++) {
            writer.setColumnWidth(i, 30);
            //  由于不知道这个列头的信息是普通字符串的, 还是JSON字符串, 所以这里通过强转捕获的形式来区分, 当然也可以使用字符串判断, 具体可以根据列头规则定义
            try {
                JSONObject jsonObject = JSONObject.parseObject((String) headList.get(i));
                String text = jsonObject.getString("text");
                newHeadList.add(text);
                JSONObject excelFormat = jsonObject.getJSONObject("excel_format");
                if (excelFormat != null) {
                    String numberFormat = excelFormat.getString("number_format");
                    String ratioFormat = excelFormat.getString("ratio_format");
                    StyleSet styleSet = writer.getStyleSet();
                    CellStyle cellStyle = null;
                    //  数字格式化
                    if (StringUtils.isNotBlank(numberFormat)) {
                        cellStyle = styleSet.getCellStyleForNumber();
                        cellStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat(numberFormat));

                    }
                    //  百分比格式化
                    if (StringUtils.isNotBlank(ratioFormat)) {
                        cellStyle = styleSet.getCellStyleForNumber();
                        cellStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat(ratioFormat));
                    }
                    writer.setColumnStyleIfHasData(i, 1, cellStyle);

                }
            } catch (JSONException ignored) {
                newHeadList.add(headList.get(i));
            }

        }

        writer.writeHeadRow(newHeadList);
        // 一次性写出内容,使用默认样式,强制输出标题
        writer.write(dataList, false);
        writeXlsx2Response(response, writer, fileName);
    }

将刚刚写在service上的测试数据也改成配置格式

public void exportExcel(HttpServletResponse response) {
        //  列头信息
        List<Object> headList = new ArrayList<>(Arrays.asList(
                "订单号",
                """
                {
                	"text": "商品名称",
                	"excel_format": {
                		ground_color: "red"
                	}
                }
                """,
                "单价",
                "数量",
                """
                {
                	"text": "总价",
                	"excel_format": {
                		number_format: "0.0"
                	}
                }
                """,
                """
                {
                	"text": "占收入百分比",
                	"excel_format": {
                		"ratio_format": "0.00%"
                	}
                }
                """));
        //  数据集
        List<Object> data1 = new ArrayList<>();
        data1.add("3123ab3412c3");
        data1.add("鼠标");
        data1.add(new BigDecimal("89.9"));
        data1.add(1);
        data1.add(new BigDecimal("89.9"));
        data1.add(new BigDecimal("0.1"));
        List<Object> data2 = new ArrayList<>();
        data2.add("3123ab3412c4");
        data2.add("键盘");
        data2.add(new BigDecimal("298.9"));
        data2.add(2);
        data2.add(new BigDecimal("597.8"));
        data2.add(new BigDecimal("0.321300"));
        List<Object> data3 = new ArrayList<>();
        data3.add("3123ab3412c5");
        data3.add("显卡");
        data3.add(new BigDecimal("2048.6"));
        data3.add(1);
        data3.add(new BigDecimal("2048.6"));
        data3.add(new BigDecimal("0.5423"));
        List<Object> data4 = new ArrayList<>();
        data4.add("3123ab3412c6");
        data4.add("显示器");
        data4.add(new BigDecimal("1999.9"));
        data4.add(1);
        data4.add(new BigDecimal("1999.9"));
        data4.add(new BigDecimal("0.36740"));
        List<List<Object>> dataList = new ArrayList<>(Arrays.asList(data1, data2, data3, data4));
        BaseFileUtils.writeXlsxByData("订单信息", headList, dataList, response);

    }

最后导出结果如下
java导出excel设置数字类型,笔记,excel,java看到结果发现虽然格式设置是没问题了, 但是只有最后一个设置的格式生效, 并且所有设置单元格的列都生效了百分比的格式, 很明显这不是理想中的结果
后面试过了好多方案都以失败告终了, 可能是这个每一次设置的样式都是全局生效的, 所以此时决定放弃使用Hutool封装的方法了, 还是老老实实的用原生POI做了

可实行的方案

导入poi依赖

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

在BaseFileUtils.java中新写方法

    /**
     * 创建excel文件写入数据并导出
     * @param fileName 文件名
     * @param headList 列头
     * @param dataList 数据集
     * @param response /
     */
    public static void writeXlsxForPoi(String fileName, List<Object> headList, List<List<Object>> dataList, HttpServletResponse response) {
        Workbook wb = WorkbookUtil.createBook(true);
        Sheet sheet = wb.createSheet();
        //  设置列宽默认为25
        sheet.setDefaultColumnWidth(25);
        //  创建第一行表头
        Row headRow = sheet.createRow(0);
        //  创建的单元格格式
        CellStyle headCellStyle = wb.createCellStyle();
        CellStyle dataCellStyle = wb.createCellStyle();
        //  构建列头格式
        buildHeadCellStyle(headCellStyle);
        //  构建数据单元格格式
        buildDataCellStyle(dataCellStyle);
        //  设置第一行--列名
        setHeadLine(headList, headRow, headCellStyle);
        //  填充数据
        setDataInfo(dataList, headList, sheet, dataCellStyle, wb);
        //  写出excel
        buildExcelDocument(fileName, wb, response);
    }

    /**
     * 设置数据行信息
     * @param dataList 数据值
     * @param sheet /
     * @param dataCellStyle 格式信息
     */
    private static void setDataInfo(List<List<Object>> dataList, List<Object> headList, Sheet sheet, CellStyle dataCellStyle, Workbook wb) {
        Cell cell;
        for (int i = 0; i < dataList.size(); i++) {
            Row row = sheet.createRow(i + 1);
            List<Object> data = dataList.get(i);
            for (int j = 0; j < data.size(); j++) {

                cell = row.createCell(j);
                Object value = data.get(j);

                if (value != null) {
                    if (value instanceof Date) {
                        cell.setCellValue(value.toString());
                    }else if (value instanceof BigDecimal) {
                        cell.setCellValue(((BigDecimal) value).doubleValue());
                    } else if (value instanceof Double) {
                        cell.setCellValue(Double.parseDouble(value.toString()));
                    }else {
                        cell.setCellValue(value.toString());
                    }
                }
                //  新建一个cellStyle, 将需要的样式信息复制过来, 用同一个样式对象最后会只生效最后一个
                CellStyle cellStyle = wb.createCellStyle();
                cellStyle.cloneStyleFrom(dataCellStyle);
                try {
                    JSONObject jsonObject = JSONObject.parseObject((String) headList.get(j));
                    JSONObject excelFormat = jsonObject.getJSONObject("excel_format");
                    if (excelFormat != null) {
                        String numberFormat = excelFormat.getString("number_format");
                        String ratioFormat = excelFormat.getString("ratio_format");
                        String groundColor = excelFormat.getString("ground_color");
                        if (StringUtils.isNotBlank(numberFormat)) {

                            cellStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat(numberFormat));
                        }
                        if (StringUtils.isNotBlank(ratioFormat)) {
                            cellStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat(ratioFormat));
                        }
                        if (StringUtils.isNotBlank(groundColor)) {
                            //  设置单元格颜色
                            cellStyle.setFillForegroundColor(HSSFColor.HSSFColorPredefined.RED.getIndex());
                            //  设置填充样式(实心填充),不设置填充样式不会有颜色
                            cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
                        }
                    }
                } catch (JSONException ignored) {
                }
                cell.setCellStyle(cellStyle);
            }
        }
    }
    /**
     * 设置第一行数据--列头
     * @param headList 列头数据
     * @param row 行信息
     * @param headCellStyle 格式信息
     */
    private static void setHeadLine(List<Object> headList, Row row, CellStyle headCellStyle) {
        Cell cell;
        for (int i = 0; i < headList.size(); i++) {
            cell = row.createCell(i);
            Object obj = headList.get(i);
            try {
                JSONObject jsonObject = JSONObject.parseObject((String) obj);
                cell.setCellValue(jsonObject.getString("text"));
                cell.setCellStyle(headCellStyle);
            } catch (JSONException e) {
                cell.setCellValue(headList.get(i).toString());
                cell.setCellStyle(headCellStyle);
            }
        }
    }

    /**
     * 构建第一行--列头格式信息
     * @param cellStyle 格式信息
     */
    private static void buildHeadCellStyle(CellStyle cellStyle) {
        //  设置单元格居中
        cellStyle.setAlignment(HorizontalAlignment.CENTER);
        //  设置单元格颜色
        cellStyle.setFillForegroundColor(HSSFColor.HSSFColorPredefined.GREY_25_PERCENT.getIndex());
        //  设置填充样式(实心填充),不设置填充样式不会有颜色
        cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);

        //设置边框
        cellStyle.setBorderBottom(BorderStyle.THIN);
        cellStyle.setBorderLeft(BorderStyle.THIN);
        cellStyle.setBorderRight(BorderStyle.THIN);
        cellStyle.setBorderTop(BorderStyle.THIN);

    }

    /**
     * 构建数据行格式信息
     * @param dataCellStyle 格式信息
     */
    private static void buildDataCellStyle(CellStyle dataCellStyle) {
        //  设置单元格居中
        dataCellStyle.setAlignment(HorizontalAlignment.CENTER);

        //设置边框
        dataCellStyle.setBorderBottom(BorderStyle.THIN);
        dataCellStyle.setBorderLeft(BorderStyle.THIN);
        dataCellStyle.setBorderRight(BorderStyle.THIN);
        dataCellStyle.setBorderTop(BorderStyle.THIN);

    }

    /**
     * 响应写出excel
     * @param fileName 文件名
     * @param wb 工作簿
     * @param response HttpServletResponse
     */
    private static void buildExcelDocument(String fileName, Workbook wb, HttpServletResponse response){
        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename="+ fileName);
            OutputStream outputStream = response.getOutputStream();
            wb.write(outputStream);
            outputStream.flush();
            outputStream.close();
            wb.close();
        } catch (IOException e) {
            logger.error(e.getMessage(),e);

        }
    }

最后将FileService.java中调用writeXlsxByData()方法改为调用writeXlsxForPoi()方法即可;
导出结果
java导出excel设置数字类型,笔记,excel,java正是理想中的结果

主要的关键点在于每一次设置样式都要创建一个新的样式对象, 否则仍会出现第一个方案中全局生效最后一个设置的样式一样的结果, 若是有需要默认的全局样式可以通过cellStyle.cloneStyleFrom()方法将原有的格式进行克隆保留原有样式, 使用第一种方案的时候或许也可以以此改良, 有兴趣的可以试试!

结束

本次记录到此结束, 总的来说也算是有一点点小小的进步吧, 可能有不对的地方或者是有其他更好的方案希望各位大佬多多指点!文章来源地址https://www.toymoban.com/news/detail-723819.html

到了这里,关于Java使用poi导出excel针对不同数据列配置设置不同单元格格式(适用于通用导出excel数据)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • java poi导入Excel、导出excel

    java poi导入Excel、导出excel ReadPatientExcelUtil PoiUtils FileUtils

    2024年02月15日
    浏览(25)
  • Java Poi导出Excel表格详解

    一、导出下面的表格 二、流程详解         1、导出excel需要先将数据准备好         2、创建工作傅对象SXSSFWorkbook         3、使用工作傅对象创建sheet对象(工作页)         4、使用sheet对象创建行对象row(行对象)         5、使用row对象创建cell对象(单元格

    2024年02月10日
    浏览(33)
  • java poi实现Excel多级表头导出

    最近碰到一个导出,比较繁琐,也查询了许多博客,在其中一篇博客的基础上修改,实现了最终想要的效果。话不多说,直接上效果图 1.主代码: 2.合并单元格 3.设置表头单元格的宽度 4.填充数据(注:我这里的数据格式是ListMapString, Object类型,可以根据自己的实际情况来封

    2024年02月03日
    浏览(32)
  • Java原生POI实现的Excel导入导出(简单易懂)

    首先是Controller入口方法 这个接口在postman上传参是下面这样的: 注意里面的参数名称要和接口上的一致,不然会拿不到值 还有file那里key的类型要选file类型的,这样就可以在后面value里面选择文件 然后是Service方法 首先是Controller入口 strJson是用来接受其它参数的,一般导出的

    2024年02月11日
    浏览(32)
  • Java excel poi 使用HSSFWorkbook 导出的excel wps能打开office打不开问题解决 Excel无法打开xx.xlsx,因为文件格式或扩展名无效......

    1.在开发代码中涉及到报表导出 xlsx文件 office打不开问题 JavaPOI导出Excel有三种形式,他们分别是 1.HSSFWorkbook 2.XSSFWorkbook 3.SXSSFWorkbook。 pom文件如下 检查创建sheet代码如下 代码中用了 HSSFworkbook 去创建Sheet 导致office打不开原因就在这里 HSSFworkbook 解释如下: HSSFWorkbook:是操作Exc

    2024年02月16日
    浏览(25)
  • Java POI (2)—— Excel文件的上传与导出(实例演示)

             这里是一个demo的流程图,下面按照这个流程图做了一个简单的实现,有部分判断没有加上,实际操作中,可以根据自己的需求进行增加或者修改。并且此处还是在接受文件传入后将文件进行了下载,保存到本地的操作,这个要按照具体情况具体分析,看需求是否

    2024年02月11日
    浏览(33)
  • Java POI导出Excel时,合并单元格没有边框的问题

    今天用POI导出Excel的时候,发现导出的单元格确少边框,最后发现有2个方案可以解决。 CellRangeAddress的4个参数分别表示:起始行号,终止行号, 起始列号,终止列号

    2024年02月14日
    浏览(31)
  • Java根据excel模版导出Excel(easyexcel、poi)——含项目测试例子拿来即用

    一般列表导出以及个性化样式设置请看下面的文章: JAVA导出Excel通用工具类——第一篇:详细介绍POI 导出excel的多种复杂情况,包括动态设置筛选、动态合并横向(纵向)单元格等多种复杂情况. JAVA导出Excel通用工具——第二篇:使用EasyExcel导出excel的多种情况的例子介绍.

    2024年04月29日
    浏览(29)
  • java poi导出excel单元格设置自定义背景颜色(任意颜色)

    一、思考过程(看代码的移步第二点) 现有方法 现有资料多为使用 IndexedColors 设置颜色, 但是IndexedColors能设置的颜色有限 ,而需求中所要颜色都是花里胡哨的,需要真正的自定义; 而颜色的本质是rgb ,所以只要我们能自己设置rgb的值就能获取任意想要的颜色了; 源码分

    2023年04月10日
    浏览(32)
  • Java POI导出Word、Excel、Pdf文档(可在线预览PDF)

    1、导入依赖Pom.xml        dependency             groupIdorg.apache.poi/groupId             artifactIdpoi/artifactId             version3.14/version         /dependency 2、Controller   3、Service a、pdfService b、wordService c、excelService  4、Utils 5、模板截图   6、前端

    2024年02月08日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包