java动态导出excel头

news2024/11/22 21:49:14

java动态导出excel头

    • java根据动态头导出excel文件
    • 一、需求背景
      • 1、调用接口将表头传给给后端
      • 2、请求结果展示
      • 3、核心代码
        • 1、工具类,注意异常抛出类如报错,需自定义异常类
        • 2、标题设置类
        • 3、单元各简单设置类
        • 4、controller接收参数

java根据动态头导出excel文件

一、需求背景

用户可选择列表中列展示,当选择好之后点击导出,excel中只导出用户选择列的数据

1、调用接口将表头传给给后端

在这里插入图片描述

2、请求结果展示

在这里插入图片描述

3、核心代码

pom包
在这里插入图片描述

1、工具类,注意异常抛出类如报错,需自定义异常类

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import cn.hutool.core.util.ReflectUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.mbcloud.cloud.commons.exception.ApiException;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

@Component
@Slf4j
public class ExcelUtil {

    /**
     * 从 sheet 中获取指定行列的单元格值
     *
     * @param sheet        表单
     * @param rowNumber    行号
     * @param columnNumber 列号
     * @return 统一返回字符串类型,null 表示找不到
     */
    public static String getCellValue(Sheet sheet, int rowNumber, int columnNumber) {

        Row row = sheet.getRow(rowNumber);
        if (null == row) {
            return null;
        }
        Cell cell = row.getCell(columnNumber);
        if (null == cell) {
            return null;
        }

        // 只处理数字、文本、公式结果为数字、文本的,其余认为错误
        switch (cell.getCellTypeEnum()) {
            case NUMERIC:
                // 保留两位小数,并处理科学计数法
                DecimalFormat df = new DecimalFormat("0.00");
                return df.format(cell.getNumericCellValue());
            case STRING:
                return cell.getStringCellValue();
            case FORMULA:
                switch (cell.getCachedFormulaResultTypeEnum()) {
                    case STRING:
                        return cell.getStringCellValue();
                    case NUMERIC:
                        NumberFormat nf = NumberFormat.getInstance();
                        nf.setGroupingUsed(false);
                        return String.valueOf(nf.format(cell.getNumericCellValue()));
                    default:
                        return null;
                }
            default:
                return null;
        }
    }

    /**
     * 根据模板导出数据 单个sheet
     *
     * @param response     返回对象
     * @param dataList     导出的数据集合
     * @param object       填充对象
     * @param fileName     文件名称
     * @param templateName 模板名称
     * @throws Exception
     */
    public void exportTemplateExcel(HttpServletResponse response, List<?> dataList, Object object,
                                    String fileName, String templateName) throws Exception {
        InputStream inputStream = this.getClass().getResourceAsStream(templateName);
        FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
        ExcelWriter excelWriter = EasyExcelFactory.write(getOutputStream(fileName, response)).withTemplate(inputStream).build();
        WriteSheet writeSheet0 = EasyExcelFactory.writerSheet(0).build();
        excelWriter.fill(object, fillConfig, writeSheet0);
        excelWriter.fill(dataList, fillConfig, writeSheet0);
        excelWriter.finish();
    }

    /**
     * 构建输出流
     *
     * @param fileName 文件名称
     * @param response 输出流
     * @return
     * @throws Exception
     */
    private OutputStream getOutputStream(String fileName, HttpServletResponse response) throws Exception {
        URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
        return response.getOutputStream();
    }

    /**
     * 文件格式校验
     *
     * @param file 文件
     */
    public  void checkFile(MultipartFile file) throws ApiException{
        if (file == null) {
            throw new ApiException("500", "文件不能为空");
        }
        String filename = file.getOriginalFilename();
        if (StringUtils.isEmpty(filename)) {
            throw new ApiException("500", "文件不能为空");
        }
        if (!filename.endsWith(".xls") && !filename.endsWith(".xlsx")) {
            throw new ApiException("500", "请上传.xls文件或者.xlsx文件");
        }
    }

    /**
     * 动态表头生成excel
     * @param headers 要生成的表头
     * @param dataList 数据
     * @param response
     * @param fileName 文件名称
     * @param titleName title名称
     * @param <T>
     */
    public static <T> void dynamicExportExcel(List<ExcelHeader> headers, List<T> dataList, HttpServletResponse response, String fileName, String titleName) {
        long startTime = System.currentTimeMillis();
        List<List<T>> allList = new ArrayList<>();
        for (T detail : dataList) {
            allList.addAll(dataList(headers, detail));
        }
        try (ServletOutputStream outputStream = response.getOutputStream()) {
            String name = com.sun.deploy.net.URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + name + ".xlsx");//设置响应头
            response.setHeader("mime","application/vnd.ms-excel");
            EasyExcel.write(outputStream).head(headers(headers))
                    //表格标题占位
                    .relativeHeadRowIndex(1)
                    //文件样式
                    .registerWriteHandler(new CustomTitleWriteHandler(headers.size(),titleName))
                    .registerWriteHandler(new CellStyle())
                    .sheet(fileName).doWrite(allList);
        } catch (IOException e) {
            log.error("生成动态EXL失败,字段", e);
        }
        long endTime = System.currentTimeMillis();
        log.info("动态导出耗时:{}", endTime - startTime);
    }

    //excel表头
    public static List<List<String>> headers(List<ExcelHeader> excelHeaders) {
        List<List<String>> headers = new ArrayList<>();
        for (ExcelHeader header : excelHeaders) {
            List<String> head = new ArrayList<>();
            head.add(header.getHeadName());
            headers.add(head);
        }
        return headers;
    }

    /**
     * 要导出的字段
     *
     * @param exportFields 表头集合
     * @param obj          数据对象
     * @return 集合
     */
    @SneakyThrows
    public static <T> List<List<T>> dataList(List<ExcelHeader> exportFields, T obj) {
        List<List<T>> list = new ArrayList<>();
        List<T> data = new ArrayList<>();
        List<String> propList = exportFields.stream().map(ExcelHeader::getFieldName).collect(Collectors.toList());
        //先根据反射获取实体类的class对象
        Class<?> objClass = obj.getClass();
        //设置实体类属性的集合
        Field[] fields = ReflectUtil.getFields(objClass);
        for (String prop : propList) {
            //循环实体类对象集合
            for (Field field : fields) {
                field.setAccessible(true);
                //判断实体类属性跟特定字段集合名是否一样
                if (field.getName().equals(prop)) {
                    T object = (T) field.get(obj);
                    //获取属性对应的值
                    if(null == object){
                        object = (T) "--";
                    }else{
                        if(object instanceof LocalDate){
                            object = (T) DateUtil.localDateToString((LocalDate)object);
                        }
                        if(object instanceof LocalDateTime){
                            object = (T) DateUtil.localDateTimeToString((LocalDateTime)object);
                        }
                    }
                    data.add(object);
                }
            }
        }
        list.add(data);
        return list;
    }

}

2、标题设置类

import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;

public class CustomTitleWriteHandler implements SheetWriteHandler {
    /**
     * 标题
     */
    private final String fileName;

    /**
     * 字段个数
     */
    private final Integer count;

    public CustomTitleWriteHandler(Integer count,String fileName) {
        this.fileName = fileName;
        this.count = count;
    }

    @Override
    public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {

    }

    @Override
    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
        // 获取clazz所有的属性
        Workbook workbook = writeWorkbookHolder.getWorkbook();
        Sheet sheet = workbook.getSheetAt(0);
        Row row1 = sheet.createRow(0);
        row1.setHeight((short) 800);
        Cell cell = row1.createCell(0);
        //设置标题
        cell.setCellValue(fileName);
        CellStyle cellStyle = workbook.createCellStyle();
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        cellStyle.setAlignment(HorizontalAlignment.CENTER);
        Font font = workbook.createFont();
        font.setBold(true);
        font.setFontHeight((short) 400);
        font.setFontName("宋体");
        cellStyle.setFont(font);
        cell.setCellStyle(cellStyle);
        sheet.addMergedRegionUnsafe(new CellRangeAddress(0, 0, 0, count-1));
    }
}

3、单元各简单设置类

import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;

import java.util.List;

public class CellStyle extends AbstractColumnWidthStyleStrategy {

    @Override
    protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<CellData> cellDataList, Cell cell, Head head,
                                  Integer relativeRowIndex, Boolean isHead) {
        // 简单设置
        Sheet sheet = writeSheetHolder.getSheet();
        sheet.setColumnWidth(cell.getColumnIndex(), 5000);
    }

}

4、controller接收参数

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

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ExcelHeader {
    /**
     * 要导出的字段名称英文
     */
    private String fieldName;

    /**
     * 要导出的表头名称中文
     */
    private String headName;
    /**
     * 排序
     */
    private Integer order;
    /**
     * 是否展示
     */
    private Boolean display;

}

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

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

相关文章

大势Inside |《倾斜摄影测量实景三维建模技术规程》发布

2023年6月21日&#xff0c;由广西壮族自治区自然资源产品质量检验中心、广西科学院、武汉大学提出&#xff0c;武汉大势智慧科技有限公司、武汉大学、广西科学院等27家单位起草的广西人工智能学会团体标准《倾斜摄影测量实景三维建模技术规程》正式发布。 此前&#xff0c;广西…

今天给大家分享几款非常实用的小工具

在当今数字化的时代&#xff0c;我们离不开各种智能设备和应用程序。然而&#xff0c;有时候我们可能会感到需要一些简单而实用的小工具来帮助我们更高效地完成日常任务或提升生活品质。今天我将与大家分享几款非常实用的小工具&#xff0c;这些工具可以在我们的生活中发挥积极…

Vue3+ElementPlus el-tree递归获取当前选中节点的所有子节点ID (适用所有场景)

点击节点触发两遍此方法问题 将@check-change改成@check即可~ 然后说下选中当前节点去获取其节点下的所有子节点的ID问题,网上搜了许多没有合适自己的方法,项目需求是单选,用了父子不关联的方法实现的单选,需要做下控制就是父节点不允许点击的情况下的子节点也不允许点击…

程序员如何高质量重构代码?

有道无术&#xff0c;术尚可求也&#xff0c;有术无道止于术。你好&#xff0c;我是程序员雪球&#xff0c;今天和你聊聊程序员重构代码那些事。 程序员重构代码的重要性不言而喻&#xff0c;但如何进行有效的重构呢&#xff1f;下面是一些建议和指导。 为什么要重构&#xff…

宝塔安装勾股OA系列服务

勾股oa地址 勾股OA办公系统—开源的OA办公系统 一、服务器配置 二、安装宝塔 1.下载宝塔面板、设置宝塔面板、增加网站。 yum install -y wget && wget -O install.sh https://download.bt.cn/install/install_6.0.sh && sh install.sh ed8484bec 根据提示…

Elasticsearch 倒排索引原理

看下面这个表格里的文档内容&#xff1a; 如果我这时候想要在这么多文档中查找带有 比亚迪 的我要怎么查&#xff0c;传统这个查询里面我想查这个比亚迪的话。就是先在文档1里面搜索一下有没有 比亚迪&#xff0c;没有&#xff0c;我在到文档2中查找比亚迪&#xff0c;还是没有…

go-zero系列-限流(并发控制)

参考文章&#xff1a;https://go-zero.dev/docs/tutorials/service/governance/limiter 步骤&#xff1a; 1、压测工具hey下载安装&#xff1a; go install github.com/rakyll/hey (会安装到GOPATH/bin目录下)2、在yaml配置文件中加入&#xff1a; #最大连接数 MaxConns: 10…

数字化时代:虚拟数字人的智能进化与生活变革

我们需要实现对人工智能的有效监管。政府应该与科技公司合作&#xff0c;建立监管框架&#xff0c;确保人工智能的发展能够在保护人类利益的基础上进行。人工智能的快速发展带来了巨大的机遇&#xff0c;但同时也伴随着一些潜在的风险。如果没有适当的监管措施&#xff0c;人工…

【华为OD机试】完全二叉树非叶子部分后序遍历【2023 B卷|200分】

【华为OD机试】-真题 !!点这里!! 【华为OD机试】真题考点分类 !!点这里 !! 题目描述: 给定一个以顺序储存结构存储整数值的完全二叉树序列(最多1000个整数), 请找出此完全二叉树的所有非叶子节点部分,然后采用后序遍历方式将此部分树(不包含叶子)输出。 1、只有一个…

[RocketMQ] Broker 消息刷盘服务源码解析 (十二)

同步刷盘: 在消息真正持久化至磁盘后RocketMQ的Broker端才会真正返回给Producer端一个成功的ACK响应。异常刷盘: 能够充分利用OS的PageCache的优势, 只要消息写入PageCache即可将成功的ACK返回给Producer端。消息刷盘采用后台异步线程提交的方式进行, 降低了读写延迟和提高了MQ…

LT15 取消TO 显示 转储请求项目 WH XXX 0001 不存在

LT15取消TO的时候&#xff0c;收到的错误收件箱信息 这个实际就是一个BUG&#xff0c;目前是无解的。 最后SAP官方使用debug处理掉的&#xff08;如果自己艺高人胆大的话也可以处理&#xff09; 以下为官方处理后的回复&#xff1a; the document has been cancelled. In L…

cobaltStrike克隆网站

试验目的 使用CS克隆网站获取键盘试验实验准备 kali cs实验步骤 启动cs服务端 sudo su切换root权限 进入cs目录 使用chmod 获取目录内最高权限 ./teamserver 192.168.24.131 12456 启动服务端[./teamserverip设置密码] 启动客户端登录并建立监听 打开新终端 切换进入cs目录 .…

百万网友AI导师李沐离职投身大模型,B站“组会”还会有吗?(文末赠书)

目录 1 求学之路&#xff1a;全能学霸2 AI之路&#xff1a;与深度学习结缘3 一战封神&#xff1a;亚马逊首席科学家4 动手学习深度学习 前阵子“沐神”李沐离开亚马逊、加入创业公司BosonAI的消息&#xff0c;引起了业内比较广泛的讨论。 而BosonAI的创始人正好是他的博士生导师…

基于Springboot的漫画网站(包论文)

原理和技术有: B/S、java技术和MySQL数据库原理和技术有: B/S、java技术和MySQL数据库原理和技术有: B/S、java技术和MySQL数据库 困扰管理层的许多问题当中,漫画信息管理一定是不敢忽视的一块。但是管理好漫画网站又面临很多麻烦需要解决,如何在工作琐碎,记录繁多的情况下将漫…

Layui之动态选项卡iframe使用(附源码)

目录 一、前言 1.什么是Tab选项卡 2.什么是iframe标签 3.使用iframe标签 二、案例实现 1.需求分析 ①在线Layui示例寻找合适的选项卡 ②点击左侧右侧没有url属性 ③点击左侧列表右侧内容多开问题 ④优化公共文件 2.Dao层的优化 3.JSP页面搭建 4.案例演示 5.总结 …

DevOps平台-图形化流水线调研总结

DevOps平台是企业级持续集成和持续交付工具&#xff0c;通过构建自动化、集成自动化、验证自动化、部署自动化&#xff0c;完成从开发到上线CICD过程。通过持续向团队提供及时反馈&#xff0c;让交付过程高效顺畅。 对以下产品做了一些调研:

win+shift+s截屏失效问题解决

windows自带截图键(shift win s)不知道为何一开始能用,过段时间便失灵了,每次都得重启电脑才能恢复?以下是无需重启电脑的恢复方式: 方式一 、 Fnwin 如果上面的没用 方式二、打开任务管理器 选择Windows资源管理器重启 ctrl alt . 或者 任务栏右键选择任务管理器

Moonbeam赞助波卡黑客松亚洲区,促进互连合约应用发展

波卡黑客松亚洲区于7月3日开跑&#xff01;Moonbeam将在本次黑客松提供两个赛题&#xff0c;促进Connected Contract应用发展&#xff0c;优选者将于9月6日在首尔进行发表。 波卡黑客松亚洲区于7月3日正式开启&#xff0c;由波卡生态系统中的众协议共同举办&#xff0c;一同召…

基于linux下的高并发服务器开发(第一章)- 动态库的制作1.6

01 / 什么是库 命名规则&#xff1a; Linux:libxxx.so lib:前缀&#xff08;固定&#xff09; xxx:库的名字&#xff0c;自己起 .so:后缀&#xff08;固定&#xff09; 在Linux下是一个可执行文件 Windows:libxxx.dll 动态库的制作: gcc 得到 .o 文件&#xff0c;得到和位置无关…