【EasyExcel】EasyExcel导出表格包含合计行、自定义样式、自适应列宽

目录

  • 0 EasyExcel简介
  • 1 Excel导出工具类
    • 设置自定义表头样式
    • 设置自适应列宽
    • 添加合计行
  • 2 调用导出工具类导出Excel表
  • 3 测试结果

0 EasyExcel简介

在数据处理和报表生成的过程中,Excel是一个非常常用的工具。特别是在Java开发中,EasyExcel库因其简单高效而备受欢迎。

EasyExcel是阿里巴巴开源的一个Excel处理库,特别适用于大数据量的Excel文件的读写。它的优点在于使用简单、性能高效,特别适合在Java项目中处理Excel文件。

1 Excel导出工具类

Excel导出工具类ExcelUtil类代码如下:

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import lombok.Data;
import org.apache.poi.ss.usermodel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.List;@Data
public class ExcelUtil{public static void downloadExcelWithHead(HttpServletResponse response, List<?> list, String sheetName, List<List<String>> rowHead) throws IOException {if (list.isEmpty()) {throw new IllegalArgumentException("列表不能为空!");}Class<?> clazz = list.get(0).getClass();response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharacterEncoding("utf-8");String fileName = URLEncoder.encode(sheetName, "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), clazz).excelType(ExcelTypeEnum.XLSX).build();// 创建 ExcelWriterBuilderExcelWriterBuilder excelWriterBuilder = EasyExcel.write(response.getOutputStream(), clazz).autoCloseStream(true).needHead(true);excelWriterBuilder.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy());excelWriterBuilder.useDefaultStyle(false);// 创建 WriteSheet 并设置动态标题行WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).head(rowHead) // 设置标题行.registerWriteHandler(setCellStyle()) // 设置表头样式.registerWriteHandler(new CustomCellWriteUtil()) // 设置列宽自适应.build();// 写入数据excelWriter.write(list, writeSheet);excelWriter.finish();}}

设置自定义表头样式

其中,downloadExcelWithHead()中调用setCellStyle()方法用于设置表头样式。setCellStyle()方法的代码如下:

    public static HorizontalCellStyleStrategy setCellStyle() {// 表头策略WriteCellStyle headWriteCellStyle = new WriteCellStyle();// 背景设置为白色headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.index);headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);headWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);//边框headWriteCellStyle.setBorderBottom(BorderStyle.THIN);headWriteCellStyle.setBorderLeft(BorderStyle.THIN);headWriteCellStyle.setBorderRight(BorderStyle.THIN);headWriteCellStyle.setBorderTop(BorderStyle.THIN);//自动换行headWriteCellStyle.setWrapped(true);WriteFont headWriteFont = new WriteFont();headWriteFont.setBold(true);headWriteFont.setFontName("宋体");headWriteFont.setFontHeightInPoints((short)12);headWriteCellStyle.setWriteFont(headWriteFont);// 内容的策略WriteCellStyle contentWriteCellStyle = new WriteCellStyle();// 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);// 背景白色contentWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);//边框contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);contentWriteCellStyle.setBorderRight(BorderStyle.THIN);contentWriteCellStyle.setBorderTop(BorderStyle.THIN);//自动换行contentWriteCellStyle.setWrapped(true);//文字WriteFont contentWriteFont = new WriteFont();// 字体大小contentWriteFont.setFontHeightInPoints((short)12);contentWriteFont.setFontName("宋体");contentWriteCellStyle.setWriteFont(contentWriteFont);return new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);}

设置自适应列宽

自适应列宽通过CustomCellWriteUtil类设置,CustomCellWriteUtil类的代码如下:

import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.CellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.ss.usermodel.Cell;import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** excel自适应列宽*/
public class CustomCellWriteUtil extends AbstractColumnWidthStyleStrategy {private static final int MAX_COLUMN_WIDTH = 255;private Map<Integer, Map<Integer, Integer>> CACHE = new HashMap(8);public CustomCellWriteUtil() {}protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {boolean needSetWidth = isHead || !CollectionUtils.isEmpty(cellDataList);if (needSetWidth) {Map<Integer, Integer> maxColumnWidthMap = (Map) CACHE.get(writeSheetHolder.getSheetNo());if (maxColumnWidthMap == null) {maxColumnWidthMap = new HashMap(16);CACHE.put(writeSheetHolder.getSheetNo(), maxColumnWidthMap);}Integer columnWidth = this.dataLength(cellDataList, cell, isHead);if (columnWidth >= 0) {if (columnWidth > 255) {columnWidth = 255;}Integer maxColumnWidth = (Integer) ((Map) maxColumnWidthMap).get(cell.getColumnIndex());if (maxColumnWidth == null || columnWidth > maxColumnWidth) {((Map) maxColumnWidthMap).put(cell.getColumnIndex(), columnWidth);writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), 7250);}}}}private Integer dataLength(List<WriteCellData<?>> cellDataList, Cell cell, Boolean isHead) {if (isHead) {return cell.getStringCellValue().getBytes().length;} else {CellData cellData = (CellData) cellDataList.get(0);CellDataTypeEnum type = cellData.getType();if (type == null) {return -1;} else {switch (type) {case STRING:return cellData.getStringValue().getBytes().length;case BOOLEAN:return cellData.getBooleanValue().toString().getBytes().length;case NUMBER:return cellData.getNumberValue().toString().getBytes().length;default:return -1;}}}}
}

添加合计行

合计行用于展示数据的总和或其他统计信息。在Controller中调用downloadExcelWithHead()方法导出Excel时,添加合计行和自定义表头形式。

2 调用导出工具类导出Excel表

此处以导出产品明细表为例,新建产品表如下:

在这里插入图片描述

entity、mapper、service层省略,在Controller层中添加一个导出产品明细表接口,代码如下:

import com.z.entity.Product;
import com.z.service.ProductService;
import com.z.util.ConvertUtil;
import com.z.util.ExcelUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
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.util.ArrayList;
import java.util.List;@RestController
@RequestMapping("/product")
public class ProductController {@Autowiredprivate ProductService productService;@PostMapping("/export")public void export(HttpServletResponse response) throws IOException {List<Product> dataList = productService.list();if(null == dataList || dataList.isEmpty()){throw new RuntimeException("数据为空,导出失败!");}// 计算合计double totalProductCost = dataList.stream().mapToDouble(data -> data.getProductCost() != null ? data.getProductCost() : 0.0).sum();int totalProductNum = dataList.stream().mapToInt(data -> data.getProductNum() != null ? data.getProductNum() : 0).sum();// 创建合计行Product totalRow = new Product();totalRow.setId("合计");totalRow.setProductCost(totalProductCost);totalRow.setProductNum(totalProductNum);// 添加合计行到列表dataList.add(totalRow);// 创建自定义表头List<List<String>> rowHead = createHead();// 导出 Excel(带标题列,带合计列)ExcelUtil.downloadExcelWithHead(response, dataList, "产品明细表", rowHead);}/*** 设置Excel头* @return*/private List<List<String>> createHead() {List<List<String>> list = new ArrayList<>();// 第一列表头List<String> headRow1 = new ArrayList<>();headRow1.add("产品明细表报表");headRow1.add("test");headRow1.add("产品序号");list.add(headRow1);// 第二列表头List<String> headRow2 = new ArrayList<>();headRow2.add("产品明细表报表");headRow2.add("备注:"+"此处可调用方法取值");headRow2.add("产品编号");list.add(headRow2);// 第三列表头List<String> headRow3 = new ArrayList<>();headRow3.add("产品明细表报表");headRow3.add("备注:"+"此处可调用方法取值");headRow3.add("产品名称");list.add(headRow3);// 第四列表头List<String> headRow4 = new ArrayList<>();headRow4.add("产品明细表报表");headRow4.add("无");headRow4.add("产品进价");list.add(headRow4);// 第五列表头List<String> headRow5 = new ArrayList<>();headRow5.add("产品明细表报表");headRow5.add("测试");headRow5.add("产品库存");list.add(headRow5);return list;}

其中,在使用createHead()方法设置Excel头时,可以调用service层中的方法,自定义显示特定值。

3 测试结果

最终使用postman调用该导出接口,导出的表格结果如下:

在这里插入图片描述

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

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

相关文章

2024年11月09号Drawing Memory Models Review 2

So lets start with a piece of code that well be thinking about and take a few seconds to read it carefully and try to explain, in your own words, what this piece of code does.

【HarmonyOS】鸿蒙应用低功耗蓝牙BLE的使用心得 (二)

【HarmonyOS】鸿蒙应用低功耗蓝牙BLE的使用心得 &#xff08;二&#xff09; 一、前言 目前鸿蒙应用的实现逻辑&#xff0c;基本都是参考和移植Android端来实现。针对BLE低功耗蓝牙来说&#xff0c;在鸿蒙化的实现过程中。我们发现了&#xff0c;鸿蒙独有的优秀点&#xff0c…

2024年【流动式起重机司机】模拟考试及流动式起重机司机证考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 流动式起重机司机模拟考试考前必练&#xff01;安全生产模拟考试一点通每个月更新流动式起重机司机证考试题目及答案&#xff01;多做几遍&#xff0c;其实通过流动式起重机司机模拟考试题很简单。 1、【多选题】( )和…

混合搜索与多重嵌入:一次有趣又毛茸茸的猫咪搜索之旅!(二)

这是继上一篇文章 “混合搜索与多重嵌入&#xff1a;一次有趣又毛茸茸的猫咪搜索之旅&#xff01;&#xff08;一&#xff09;” 的续篇。这这篇文章中&#xff0c;我们讲使用本地 Elasticsearch 部署来完成整个演示。这是一个简单的 Python Web 应用程序&#xff0c;展示了可…

算法【Java】—— 动态规划之路径问题

前言 本文章终点解析第一道题目【不同路径】和最后一道题目【地下城游戏】的动态规划思路&#xff0c;中间几道题目会很快过完&#xff0c;大家如果不熟悉动态规划的思路可以重点看一下这两道题目的解析。 不同路径 https://leetcode.cn/problems/unique-paths 解析&#xf…

FPGA实现串口升级及MultiBoot(五)通过约束脚本添加IPROG实例

本文目录索引 一个指令和三种方式通过约束脚本添加Golden位流工程MultiBoot位流工程验证example1总结代码缩略词索引: K7:Kintex 7V7:Vertex 7A7:Artix 7MB:MicroBlaze上一篇文章种总结了MultiBoot 关键技术,分为:一个指令、二种位流、三种方式、四样错误。针对以上四句话我…

jmeter基础02_下载安装jmeter

&#xff08;安装包windows、mac、Linux通用&#xff09; Step1. 官网下载 官网地址&#xff1a;https://jmeter.apache.org/download_jmeter.cgi 官网可见最新版本的jmeter和要求的jdk版本&#xff0c;先说结论&#xff1a;建议下载Binaries-zip格式包即可。 安装包有2大类&am…

理解鸿蒙app 开发中的 context

是什么 Context是应用中对象的上下文&#xff0c;其提供了应用的一些基础信息&#xff0c;例如resourceManager&#xff08;资源管理&#xff09;、applicationInfo&#xff08;当前应用信息&#xff09;、dir&#xff08;应用文件路径&#xff09;、area&#xff08;文件分区…

Linux:git的了解和基础使用(保姆级教程)

文章目录 引言一、git是什么1.1 版本控制器git1.2 git的历史 二、git的使用2.1 安装git2.2 创建gitee账号2.3 git三板斧2.3.1 add2.3.2 commit2.3.3 push 三. git的补充总结 引言 git是一款软件&#xff0c;它用于帮助我们来管理代码以及文件&#xff0c;掌握并使用git可以很有…

探索LINQ在C#中的应用:从基本查询到数据联接

LINQ&#xff08;语言集成查询&#xff09;是微软为.NET框架开发的一种强大功能&#xff0c;于2007年作为C# 3.0和Visual Basic .NET 9.0的一部分引入。LINQ的诞生旨在提供一种一致且直观的方式来查询和操作数据&#xff0c;无论数据来源是内存中的集合、数据库还是XML文档。 …

鸿蒙UI开发——实现环形文字

1、背 景 有朋友提问&#xff1a;您好关于鸿蒙UI想咨询一个问题 如果我想实现展示环形文字是需要通过在Text组件中设置transition来实现么&#xff0c;还是需要通过其他方式来实现。 针对这位粉丝朋友的提问&#xff0c;我们做一下解答。 2、实现环形文字效果 ❓ 什么是环形…

搭建轻量级文件服务器Dufs

前言 Dufs是什么&#xff1f; 答&#xff1a;是一款轻量级文件管理服务器&#xff0c;类似于FTP服务器但又比FTP更好用易于管理。 Dufs有什么特性&#xff1f; 答&#xff1a; ‌静态文件服务…

【软考】系统分析师第二版 新增章节 第20章微服务系统分析与设计

微服务系统是一类基于微服务架构风格的分布式系统&#xff0c;它将应用程序拆分成多个独立的小型服务&#xff0c;每个服务都运行在独立的进程中&#xff0c;并采用轻量级通信协议进行通信。这些服务可以由不同的团队开发、不同的编程语言编写&#xff0c;并且可以按需部署。微…

基于SSM的校园美食交流系统【附源码】

基于SSM的校园美食交流系统 效果如下&#xff1a; 管理员主页面 用户主页面 美食信息页面 美食资讯页面 修改密码页面 论坛中心页面 研究背景 随着高校信息化建设的不断推进&#xff0c;校园生活日益丰富多样&#xff0c;学生对于美食的需求与探索也愈发旺盛。然而&#xff…

PICO+Unity MR空间网格

官方链接&#xff1a;空间网格 | PICO 开发者平台 注意&#xff1a;该功能只能打包成APK在PICO 4 Ultra上真机运行&#xff0c;无法通过串流或PICO developer center在PC上运行。使用之前要开启视频透视。 在 Inspector 窗口中的 PXR_Manager (Script) 面板上&#xff0c;勾选…

斗破QT编程入门系列之前言:认识Qt:获取与安装(四星斗师)

本系列是在学习完C之后&#xff0c;然后通过Qt构建界面来&#xff0c;赋予枯燥的代码新的样貌&#xff0c;这样我们才能开发出更人性化的程序&#xff0c;同时会进一步提高初学者对编程的兴趣&#xff0c;大家加油&#xff0c;斗破Qt来了。 斗破Qt目录&#xff1a; 斗破Qt编程…

PyTorch核心概念:从梯度、计算图到连续性的全面解析(三)

文章目录 Contiguous vs Non-Contiguous TensorTensor and ViewStrides非连续数据结构&#xff1a;Transpose( )在 PyTorch 中检查Contiguous and Non-Contiguous将不连续张量&#xff08;或视图&#xff09;转换为连续张量view() 和 reshape() 之间的区别总结 参考文献 Contig…

家庭宽带如何开启公网ipv4和ipv6

好久没更新了&#xff0c;最近在家里折腾nas。一来自己有下电影的习惯&#xff0c;二来手机的icloud容量也不够了。所以买了群晖的423,但是nas要想用的畅快&#xff0c;外网访问必不可少。所以我之前研究了下&#xff0c;打家里的电信快带打通了外网。 一般nas的服务商基本都会…

【Linux】Ansible集中化运维工具(详解)安装、常用模块、playbook脚本

文章目录 一、Ansible安装及远程控制1、关闭防火墙和SELinux2、安装ansible3、配置SSH无密码登录1、在管理机上生成一对密钥2、将公钥下发到远程主机3、保管密钥 4、主机目录 二、常用模块1、setup模块2、copy模块3、file模块4、shell模块5、script模块6、ping模块7、group模块…

基于 RNN 的语言模型

基于 RNN 的语言模型 循环神经网络&#xff08;Recurrent Neural Network, RNN&#xff09;是一类网络连接中包含环路的 神经网络的总称。 给定一个序列&#xff0c;RNN 的环路用于将历史状态叠加到当前状态上。沿着时间维度&#xff0c;历史状态被循环累积&#xff0c;并作为…