springboot导出(POI)

news2024/11/22 22:20:48

POI官方文档

引入依赖

        <!--POI-->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>4.1.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>4.1.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml-schemas</artifactId>
            <version>4.1.2</version>
        </dependency>

定义注解

        我们结合自定义注解,让导出使用起来更方便简洁且更容易扩展。

@ExcelField

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelField {

    /**
     * 字段名
     */
    String name() default "";

    /**
     * 字段顺序
     */
    int order() default 1;

    /**
     * 单元格宽度
     */
    int width() default 100;

    /**
     * 日期格式
     */
    String dateFormat() default "yyyy-MM-dd HH:mm:ss";
}

@ExcelHeader 

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelHeader {

    /**
     * 文件名称
     * @return
     */
    String fileName() default "导出文件";

    /**
     * sheet页名称
     * @return
     */
    String sheetName() default "sheet1";

    /**
     * 表头是否加粗
     * @return
     */
    boolean headBold() default false;

    /**
     * 表头颜色
     * @return
     */
    IndexedColors headColor() default IndexedColors.GREEN;
}

编写POI导出工具类

public class ExcelExportUtil {

    /*
     * @description: 导出 <br>
     * @create: 2023/9/12 16:28 <br>
     * @param response
     * @param data
     * @param clazz
     * @return void
     */
    public static<T> void export(HttpServletResponse response, List<T> data, Class<T> clazz){
        if(ObjectUtils.isEmpty(response) || ObjectUtils.isEmpty(data)){
            return;
        }
        //解析表头
        ExcelHeader excelHeader = getExcelHeader(clazz);
        if(ObjectUtils.isEmpty(excelHeader)){
            return;
        }
        //解析字段
        List<String> keyList = new ArrayList<>();
        List<ExcelField> excelFieldList = new ArrayList<>();
        getExcelFields(clazz, keyList, excelFieldList);
        if(ObjectUtils.isEmpty(keyList)){
            return;
        }
        //创建workbook,SXSSFWorkbook支持大数据量导出
        Workbook workbook = new SXSSFWorkbook();
        //创建sheet
        Sheet sheet = workbook.createSheet(excelHeader.sheetName());
        //创建表头
        Row row = createHeader(workbook, sheet, excelHeader, excelFieldList);
        //写入数据
        setData(data, sheet, keyList, excelFieldList);
        //输出文件
        try {
            String fileName = URLEncoder.encode(excelHeader.fileName(), "UTF-8");
            response.setContentType("application/octet-stream");
            response.setHeader("content-disposition", "attachment;filename=" + new String(fileName.getBytes("ISO8859-1")));
            response.setHeader("filename", fileName);
            workbook.write(response.getOutputStream());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                workbook.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /*
     * @description: 设置数据 <br>
     * @create: 2023/9/13 9:33 <br>
     * @param data
     * @param sheet
     * @param keyList
     * @return void
     */
    private static<T> void setData(List<T> data, Sheet sheet, List<String> keyList, List<ExcelField> excelFieldList){
        List<Map<String, Object>> dataList = convertDataToJson(data);
        Map<String, Object> rowData;
        String dataKey;
        Object value;
        ExcelField excelField;
        for (int i = 0; i < dataList.size(); i++) {
            Row row = sheet.createRow(i+1);
            rowData = dataList.get(i);
            for (int j = 0; j < keyList.size(); j++) {
                dataKey = keyList.get(j);
                value = rowData.get(dataKey);
                if(ObjectUtils.isEmpty(value)){
                    continue;
                }
                Cell cell = row.createCell(j);
                cell.setCellValue(value.toString());
            }
        }
    }

    /*
     * @description: 创建表头 <br>
     * @create: 2023/9/12 17:28 <br>
     * @param workbook
     * @param sheet
     * @param excelFieldList
     * @return org.apache.poi.ss.usermodel.Row
     */
    private static Row createHeader(Workbook workbook, Sheet sheet, ExcelHeader excelHeader,List<ExcelField> excelFieldList){
        //创建行
        Row row = sheet.createRow(0);
        //创建行样式
        CellStyle cellStyle = workbook.createCellStyle();
        //单元格颜色
        cellStyle.setFillForegroundColor(excelHeader.headColor().getIndex());
        cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        //水平居中
        cellStyle.setAlignment(HorizontalAlignment.CENTER);
        //字体
        Font font =  workbook.createFont();
        font.setBold(excelHeader.headBold());
        font.setFontName("宋体");
        cellStyle.setFont(font);
        for (int i = 0; i < excelFieldList.size(); i++) {
            ExcelField excelField = excelFieldList.get(i);
            Cell cell = row.createCell(i);
            cell.setCellValue(excelField.name());
            cell.setCellStyle(cellStyle);
            sheet.setColumnWidth(i+1, excelField.width() * 10 );
        }
        return row;
    }

    /*
     * @description: 获取excel头注解信息 <br>
     * @create: 2023/9/12 10:28 <br>
     * @param clazz
     * @return com.springboot.demo.base.annotation.ExcelHeader
     */
    private static<T> ExcelHeader getExcelHeader(Class<T> clazz){
        ExcelHeader excelHeader = clazz.getAnnotation(ExcelHeader.class);
        return excelHeader;
    }

    /*
     * @description: 获取excel字段注解信息 <br>
     * @create: 2023/9/12 10:31 <br>
     * @param clazz
     * @return java.util.List<com.springboot.demo.base.annotation.ExcelField>
     */
    private static<T> void getExcelFields(Class<T> clazz, List<String> keyList, List<ExcelField> excelFieldList){
        Field[] fields = clazz.getDeclaredFields();
        if(ObjectUtils.isEmpty(fields)){
            return;
        }
        Map<String, String> keyMap = new HashMap<>();
        for(Field field : fields){
            ExcelField excelField = field.getAnnotation(ExcelField.class);
            if(ObjectUtils.isNotEmpty(excelField)){
                keyMap.put(excelField.name(), field.getName());
                excelFieldList.add(excelField);
            }
        }
        if(ObjectUtils.isNotEmpty(excelFieldList)){
            excelFieldList = excelFieldList.stream().sorted(Comparator.comparing(ExcelField::order)).collect(
                Collectors.toList());
        }
        for (ExcelField excelField : excelFieldList) {
            keyList.add(keyMap.get(excelField.name()));
        }
    }

    /*
     * @description: 将数据转未json <br>
     * @create: 2023/9/13 10:00 <br>
     * @param data
     * @return java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
     */
    private static<T> List<Map<String, Object>> convertDataToJson(List<T> data){
        ObjectMapper objectMapper = new ObjectMapper();
        //日期格式
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        //设置时区
        objectMapper.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        //序列化-忽略null值的属性
        objectMapper.setSerializationInclusion(Include.NON_NULL);
        //序列化-允许序列化空对象
        objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        List<Map<String, Object>> dataList = objectMapper.convertValue(data, List.class);
        return dataList;
    }
}

测试

Test.java
@Data
@ExcelHeader(fileName = "导出文件.xlsx")
public class Test {

    @ExcelField(name = "字段1", width = 500, order = 1)
    private String field1 = "撒大声地撒分都是";

    @ExcelField(name = "字段2", width = 400, order = 2)
    private Integer field2 = 11;

    @ExcelField(name = "字段3", width = 300, order = 5)
    private Double field3;

    @ExcelField(name = "字段4", width = 700, order = 10)
    private BigDecimal field4 = new BigDecimal("12312312312.222");

    @ExcelField(name = "字段5", width = 600, order = 3)
    private Date field5 = new Date();
}

TestController.java

@Api(tags = "测试")
@RestController
@RequestMapping("/test")
public class TestController {

    @ApiOperation("test")
    @PostMapping("/test")
    public void test(HttpServletResponse response){
        Test test = new Test();
        List<Test> list = new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            list.add(test);
        }
        ExcelExportUtil.export(response, list, Test.class);
    }
}

输出结果

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

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

相关文章

Spring Cloud Alibaba:Nacos服务治理平台

文章目录 什么是Nacos&#xff1f;使用Nacos进行服务注册与发现服务注册服务发现 负载均衡分析与拓展安全性性能监控日志记录 &#x1f389;欢迎来到架构设计专栏~Spring Cloud Alibaba&#xff1a;Nacos服务治理平台 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;✨博客主页&…

学习笔记|矩阵按键控制原理|数值转化为键码|密码锁|STC32G单片机视频开发教程(冲哥)|第十四集:矩阵按键原理及实践

文章目录 1.矩阵按键是什么2.矩阵按键的控制原理3.矩阵按键程序的编写将数值转化为键码完整代码&#xff1a;demo.c&#xff1a;key.c:key.h: 密码锁&#xff08;简易版&#xff09;需求分析&#xff1a; 总结课后练习&#xff1a; 1.矩阵按键是什么 这个矩阵按键也是我们这个…

网上管理系统的分析及设计---应用UML建模

目 录 第1章 系统需求 第2章 需求分析 2.1 识别参与者 2.2 识别用例 2.3 用例的事件流描述 第3章 静态结构模型 3.1 定义系统对象 3.2 定义用户界面类 3.3 建立类图 第4章 动态行为模型 4.1 创建系统顺序图&#xff08;协作图&#xff09; 4.2 创建系统…

网络爬虫-----初识爬虫

目录 1. 什么是爬虫&#xff1f; 1.1 初识网络爬虫 1.1.1 百度新闻案例说明 1.1.2 网站排名&#xff08;访问权重pv&#xff09; 2. 爬虫的领域&#xff08;为什么学习爬虫 ?&#xff09; 2.1 数据的来源 2.2 爬虫等于黑客吗&#xff1f; 2.3 大数据和爬虫又有啥关系&…

Java低代码:jvs-list (子列表)表单回显及触发逻辑引擎配置说明

一、子列表【新增】表单默认回显主列表关联字段 子列表新增表单可使用表单回显配置&#xff0c;在新增表单中默认回显&#xff0c;如图效果 1、子列表中进入新增页面配置 2、切换到表单设置&#xff0c;选择回显设置&#xff0c;进入回显逻辑引擎。 3、在画布中拖入【对象变量…

记录一次对登录接口的性能测试

测试环境 客户端: win10 这里可以用linux,但没用,因为想直观查看结果。 被测环境:linux X86 4核CPU16G内存 被测接口:登录接口,没有做数据驱动。 场景设计 设置线程数19,持续时间5分钟,并用后端监听器监听结果,使用grafana+prometheus监控服务器资源。 测试执行 …

fabic如何将绘图原点移到画布中心

情况说明&#xff1a; fabic默认绘图原点为left&#xff1a;0&#xff0c;top&#xff1a;0 后端给我的内容是按照x&#xff0c;y返回的&#xff0c;需要将坐标系移到fabic画布的中心位置&#xff0c;找了下网上合适的砖&#xff0c;想一句命令直接设置&#xff0c;结果没有。…

二叉排序树(BST)的算法分析以及基本操作(结点的查询,插入,删除)

1.二叉排序树的定义 二叉排序树&#xff0c;又称二叉查找树&#xff08;BST&#xff0c;Binary Search Tree) 默认不允许两个结点的关键字相同。 1.二叉排序树的性质: 任意一棵二叉排序树的子树的结点大小都满足“左小右大”。 左子树上所有结点的关键字均小于根结点的关键…

廉价的全闪存雷电 NAS 折腾笔记:NUC9 操作系统踩坑

上一篇文章中&#xff0c;分享了关于低成本全闪存 NAS 的个人方案选择。 本篇文章&#xff0c;来聊聊硬件相关部分&#xff0c;以及软件的基础配置部分&#xff0c;也聊聊雷电组网的踩坑之旅。 写在前面 我使用的设备是 NUC9i5QNX&#xff0c;这台设备的硬件基础规格&#x…

【软件测试】selenium3

自动化测试的概念 自动化测试指软件测试的自动化&#xff0c;在预设状态下运行应用程序或者系统&#xff0c;预设条件包括正常和异常&#xff0c;最 后评估运行结果。将人为驱动的测试行为转化为机器执行的过程。 自动化测试就相当于将人工测试手段进行转换&#xff0c;让代码…

国产视觉检测设备崛起,以AI机器视觉及自研算法破解智造难题

机器视觉作为人工智能的前沿分支之一&#xff0c;被称为智能制造的“智慧之眼”&#xff0c;在工业领域中&#xff0c;能够代替人工完成识别、测量、定位、检测等工作&#xff0c;以实现对设备精密控制及产线智能化、自动化升级。 同时&#xff0c;深度学习和3D视觉的技术升级…

Java本地开发环境搭建

概述 Java语言是企业级应用软件开发语言&#xff0c;本文主要描述Java开发环境的搭建。 如上所示&#xff0c;TIOBE提供2023年9月份全球开发语言的排行榜&#xff0c;其中&#xff0c;Java排名第四&#xff0c;而Python已经跃升到第一位&#xff0c;因为&#xff0c;Python是人…

芯科蓝牙BG27开发笔记6-精简第一个程序

1. 这些IO的控制代码在哪里&#xff1f; 还是蓝牙点灯程序&#xff1a; 首先需要对pinout做一些精简&#xff1a; 为了简化工程&#xff0c;去掉了不必要的IO。 至于PTI接口是什么&#xff0c;怎么用&#xff0c;不知道&#xff0c;现在不考虑&#xff1a; 但是提出以下问题…

第6章_freeRTOS入门与工程实践之创建FreeRTOS工程

本教程基于韦东山百问网出的 DShanMCU-F103开发板 进行编写&#xff0c;需要的同学可以在这里获取&#xff1a; https://item.taobao.com/item.htm?id724601559592 配套资料获取&#xff1a;https://rtos.100ask.net/zh/freeRTOS/DShanMCU-F103 freeRTOS系列教程之freeRTOS入…

应该下那个 ActiveMQ

最近在搞 ActiveMQ 的时候&#xff0c;发现有 2 个 ActiveMQ 可以下载。 应该下那个呢&#xff1f; JMS 即Java Message Service&#xff0c;是JavaEE的消息服务接口。 JMS主要有两个版本&#xff1a;1.1和2.0。 2.0和1.1相比&#xff0c;主要是简化了收发消息的代码。 所谓…

Redis——其他数据类型介绍

概要介绍 Redis中有10种不同的数据类型。之前的blog中介绍了Redis中常见的五大数据类型&#xff1a;String&#xff0c;List&#xff0c;Hash&#xff0c;Set&#xff0c;ZSet。而Redis中还有许多其他的数据类型&#xff0c;一般在特定的场景中使用 Stream 首先介绍一下什么…

笔记本多拓展出一个屏幕

一、首先要知道&#xff0c;自己的电脑有没有Type-c接口&#xff0c;支持不支持VGA 推荐&#xff1a; 自己不清楚&#xff0c;问客服&#xff0c;勤问。 二、显示屏与笔记本相连&#xff0c;通过VGA 三、连接好了&#xff0c;需要去配置 网址&#xff1a;凑合着看&#xff…

代码随想录算法训练营Day42 | 动态规划(4/17) 0-1背包问题理论基础 LeetCode 416.分割等和子集

开始背包问题的练习&#xff01; 1. 背包问题的理论基础 对于面试的话&#xff0c;其实掌握01背包&#xff0c;和完全背包&#xff0c;就够用了&#xff0c;最多可以再来一个多重背包。这里附上代码随想录的图&#xff0c;可以对背包问题进行一个分类。 1.1 十分重要的基础&a…

Java class 文件安全加密工具对比与ClassFinal实战

文章目录 前言常见加密方案对比XJarProGuardClassFinal ClassFinal实战纯命令方式maven插件方式 写在最后 前言 相信不少的同学开发的软件都是用户商业化&#xff0c;对于这些商业运营的项目很多都会直接部署在客户方&#xff0c;这样就可能会导致项目源码泄露。当然&#xff…

每日一题~中序后序遍历构造二叉树

题目描述&#xff1a; 思路分析&#xff1a; 后序遍历分析图 中序遍历分析图 不难看出后序遍历的结果中的最后一个元素就是根节点&#xff0c;倒数第二个元素则是根节点的右子树的根节点&#xff0c;而倒数第三个元素是右子树的新右子树的根节点&#xff0c;依次类推。我们可…