Java 将数据导出到Excel并发送到在线文档

news2024/7/4 6:04:40

一、需求

现将列表数据,导出到excel,并将文件发送到在线文档,摒弃了以往的直接在前端下载的老旧模式。

二、pom依赖

        <!-- redission -->
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
            <version>3.14.0</version>
            <exclusions>
                <exclusion>
                    <groupId>org.redisson</groupId>
                    <artifactId>redisson-spring-data-23</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-data-20</artifactId>
            <version>3.14.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.83</version>
        </dependency>
        <!-- easyexcel 主要依赖  这一个基本上就够了-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>2.1.4</version>
        </dependency>

        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>

三、定义表实体

import com.fasterxml.jackson.annotation.JsonFormat;

import java.util.Date;
import java.util.Objects;

/**
 * @Author: 
 * @Description
 * @Date: 下午5:18 2023/10/26
 */
public class EntityData {
    private String name;
    private String code;
    private Double score;
    private Integer age;
    private String phone;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date createTime;

    public EntityData() {
    }

    public EntityData(String name, String code, Double score, Integer age, String phone, Date createTime) {
        this.name = name;
        this.code = code;
        this.score = score;
        this.age = age;
        this.phone = phone;
        this.createTime = createTime;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public Double getScore() {
        return score;
    }

    public void setScore(Double score) {
        this.score = score;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        EntityData that = (EntityData) o;
        return Objects.equals(name, that.name) &&
                Objects.equals(code, that.code) &&
                Objects.equals(score, that.score) &&
                Objects.equals(age, that.age) &&
                Objects.equals(phone, that.phone) &&
                Objects.equals(createTime, that.createTime);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, code, score, age, phone, createTime);
    }

    @Override
    public String toString() {
        return "EntityData{" +
                "name='" + name + '\'' +
                ", code='" + code + '\'' +
                ", score=" + score +
                ", age=" + age +
                ", phone='" + phone + '\'' +
                ", createTime=" + createTime +
                '}';
    }
}

四、定义写入Excel实体

import com.alibaba.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.annotation.JsonFormat;

import java.util.Date;
import java.util.Objects;

/**
 * @Author:
 * @Description
 * @Date: 下午5:18 2023/10/26
 */
public class ExcelData {


    @ExcelProperty(value = "姓名")
    private String name;

    @ExcelProperty(value = "学号")
    private String code;

    @ExcelProperty(value = "分数")
    private Double score;

    @ExcelProperty(value = "统计时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date createTime;

    public ExcelData() {
    }

    public ExcelData(String name, String code, Double score, Date createTime) {
        this.name = name;
        this.code = code;
        this.score = score;
        this.createTime = createTime;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public Double getScore() {
        return score;
    }

    public void setScore(Double score) {
        this.score = score;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ExcelData excelData = (ExcelData) o;
        return Objects.equals(name, excelData.name) &&
                Objects.equals(code, excelData.code) &&
                Objects.equals(score, excelData.score) &&
                Objects.equals(createTime, excelData.createTime);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, code, score, createTime);
    }

    @Override
    public String toString() {
        return "ExcelData{" +
                "name='" + name + '\'' +
                ", code='" + code + '\'' +
                ", score=" + score +
                ", createTime=" + createTime +
                '}';
    }
}

五、定义接口

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author: 
 * @Description
 * @Date: 下午4:45 2023/10/26
 */
@RestController
@RequestMapping("/file")
public interface FileApi {

    @GetMapping(path = "/export")
    ResponseData<String> export();

}

六、定义service

import com.alibaba.excel.EasyExcel;
import com.example.exception.CustomException;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @Author:
 * @Description
 * @Date: 下午4:45 2023/10/26
 */
@Service
public class FileService implements FileApi {

    @Resource
    private RedissonClient redissonClient; //这里使用redisson分布式锁 需要导入pom依赖和spring配置
    private static final String DOWNLOAD_EXCEL_SHEETS_KEY = "download:";
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;

    @Override
    public ResponseData<String> export() {
        //TODO 条件允许的话获取当前登录人信息作为redis key 的一部分,请自行填充
        String token = "";
        //加锁 防重复下载
        RLock lock = redissonClient.getLock(DOWNLOAD_EXCEL_SHEETS_KEY + token);
        try {
            if (lock.isLocked()) {
                throw new CustomException("您当前有导出中的任务尚未完成,请稍后再试!");
            }
            //这里使用看门狗机制 等待5秒,-1即开启看门狗
            boolean flag = lock.tryLock(5, -1, TimeUnit.SECONDS);
            //占用失败,抛出异常
            if (!flag) {
                throw new CustomException("锁定导出失败");
            }
            //模拟查询列表数据,可以从数据库查询
            List<EntityData> list = new ArrayList<>();
            list.add(new EntityData("张三", "001", 78.72, 11, "159888888888", new Date()));
            list.add(new EntityData("李四", "002", 45.87, 12, "159888888777", new Date()));
            list.add(new EntityData("王五", "003", 83.5, 13, "159888888666", new Date()));
            //判断列表数据是否为空
            if (CollectionUtils.isEmpty(list)) {
                throw new CustomException("列表没有数据!");
            }
            //异步导出 注意这里使用的异步操作,如果需要一些本地变量,如用户token信息,需要当参数透传
            taskExecutor.submit(() -> this.convertTExpConfirmationSheetExcel(list, "user"));
        } catch (InterruptedException ee) {
            Thread.currentThread().interrupt();
        } catch (CustomException eee) {
            throw new CustomException(eee.getMessage());
        } catch (Exception e) {
            throw new CustomException("导出出错");
        } finally {
            lock.unlock();
        }
        return ResponseData.ok("请稍后到XXXX查看");
    }

    /**
     * 确认单列表导出逻辑处理
     *
     * @param data
     * @param currentUser
     */
    private void convertTExpConfirmationSheetExcel(List<EntityData> data, String currentUser) {
        List<ExcelData> excelDataList = new ArrayList<>();
        //将数据拼装为导出数据
        for (EntityData sheet : data) {
            ExcelData excelData = new ExcelData();
            BeanUtils.copyProperties(sheet, excelData);
            excelDataList.add(excelData);
        }
        SimpleDateFormat slf = new SimpleDateFormat("yyyyMMddHHmmss");
        String time = slf.format(new Date());
        String fileName = String.format("数据导出%s.xlsx", time);
        String filePath = "";
        if (System.getProperty("os.name").toLowerCase().contains("mac")) {
            filePath = "/Users/admin/Downloads" + File.separator + fileName;
        } else {
            //配置服务器磁盘地址
//            filePath = "/home" + File.separator + "temp" + File.separator + fileName;
        }
        // 2、生成本地 excel
        EasyExcel.write(filePath, ExcelData.class).sheet("数据导出").doWrite(excelDataList);
        // 上传oss
        try (InputStream inputStream = new FileInputStream(new File(filePath))) {
            //TODO 调用上传服务

        } catch (Exception e) {
            throw new CustomException("长传导出异常");
        } finally {
            //删除临时文件
            try {
                org.apache.commons.io.FileUtils.forceDelete(new File(filePath));
            } catch (IOException e) {
                System.out.println("删除文件异常" + e);
            }
        }
    }
}

注意:本地测试需要先注释掉这段代码
try {
org.apache.commons.io.FileUtils.forceDelete(new File(filePath));
} catch (IOException e) {
System.out.println(“删除文件异常” + e);
}

七、配置线程池

这里用到了异步操作,需要配置线程池参数

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

@Configuration
public class ExecutorConfig {

    private static final int CORE_POOL_SIZE = 30;
    private static final int MAX_POOL_SIZE = CORE_POOL_SIZE * 2 + 1;

    @Bean(name="taskExecutor")
    public ThreadPoolTaskExecutor taskExecutor(){
        ThreadPoolTaskExecutor poolTaskExecutor = new ThreadPoolTaskExecutor();
        /**
         * 此方法返回可用处理器的虚拟机的最大数量; 不小于1
         * int core = Runtime.getRuntime().availableProcessors();
         */
        //设置核心线程数
        poolTaskExecutor.setCorePoolSize(CORE_POOL_SIZE);
        //设置最大线程数
        poolTaskExecutor.setMaxPoolSize(MAX_POOL_SIZE);
        //除核心线程外的线程存活时间
        poolTaskExecutor.setKeepAliveSeconds(3);
        //如果传入值大于0,底层队列使用的是LinkedBlockingQueue,否则默认使用SynchronousQueue
        poolTaskExecutor.setQueueCapacity(40);
        //线程名称前缀
        poolTaskExecutor.setThreadNamePrefix("thread-execute");
        //设置拒绝策略
        poolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return poolTaskExecutor;

    }
}

八、配置环境参数

注意:换成自己redis的服务器地址
server.port=8888
spring.redis.database = 1
spring.redis.host = localhost
spring.redis.port = 6379
spring.redis.password =123456
spring.redis.jedis.pool.max-active = 8
spring.redis.jedis.pool.max-wait = -1ms
spring.redis.jedis.pool.min-idle = 0

九、测试类

1、启动项目
在这里插入图片描述

2、浏览器访问地址:http://localhost:8888/file/export
在这里插入图片描述

十、结果

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

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

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

相关文章

AI 引擎系列 1 - 从 AI 引擎工具开始(2022.1 更新)

AI 引擎系列 1 - 从 AI 引擎工具开始&#xff08;2022.1 更新&#xff09; AI 引擎系列简介 在这篇题为 Versal 自适应 SoC AI 引擎入门的文章中&#xff0c;我介绍了一些 Versal™ 自适应 SoC 器件中存在的 AI 引擎 (AIE) 阵列。本系列是全新的 AI 引擎系列博文&#xff0c;我…

LeetCode--2.两数相加

文章目录 1 题目描述2 解题思路2.1 代码实现 1 题目描述 给你两个 非空 的链表, 表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的, 并且每个节点只能存储 一位 数字 请你将两个数相加, 并以相同形式返回一个表示和的链表 你可以假设除了数字 0 之外, 这两个数都…

maya2023安装

1、解压压缩包&#xff0c;点击setup安装&#xff0c;除修改安装路径外&#xff0c;其他都是都是下一步&#xff0c;安装后最好重启系统 破解步骤 关闭杀毒&#xff0c;防止误删1.安装Autodesk软件&#xff0c;但是不要启动&#xff0c;安装完成后重启电脑 2.安装破解文件夹里…

图神经网络论文笔记(一)——北邮:基于学习解纠缠因果子结构的图神经网络去偏

作者 &#xff1a;范少华 研究方向 &#xff1a;图神经网络 论文标题 &#xff1a;基于学习解纠缠因果子结构的图神经网络去偏 论文链接 &#xff1a;https://arxiv.org/pdf/2209.14107.pdf        https://doi.org/10.48550/arXiv.2209.14107 大多数图神经网络(GNNs)通…

JAVA实现校园二手交易系统 开源

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 二手商品档案管理模块2.3 商品预约管理模块2.4 商品预定管理模块2.5 商品留言板管理模块2.6 商品资讯管理模块 三、实体类设计3.1 用户表3.2 二手商品表3.3 商品预约表3.4 商品预定表3.5 留言表3.6 资讯…

软考系统架构师知识点集锦四:信息安全技术基础知识

一、考情分析 二、考点精讲 2.1信息加解密技术 2.1.1对称加密 概念:对称加密(又称为私人密钥加密/共享密钥加密) : 加密与解密使用同一密钥。特点:加密强度不高&#xff0c;但效率高;密钥分发困难。 (大量明文为了保证加密效率一般使用对称加密) 常见对称密钥加密算法:DES:…

行政快递管理高效化教程

能不能做好因公寄件管理&#xff0c;影响着企业内部运转的效率。我们知道&#xff0c;基本上每家企业的因公寄件&#xff0c;是由行政部门来统筹管理的...... 企业员工只知道&#xff0c;在公司寄快递&#xff0c;找行政。殊不知行政快递管理&#xff0c;不仅仅是“寄件”这么…

操作失误损失60亿美元,Excel还能是电脑上的常驻将军吗?

2013年&#xff0c;摩根大通交易员excel操作失误&#xff0c;造成公司损失60亿美元&#xff01;近40年来&#xff0c;excel一直是办公电脑上的常驻将军&#xff0c;甚至我们现在对表格的印象就是excel&#xff0c;为什么excel这么容易错误&#xff0c;这些年我们还是一直使用ex…

TVRNet网络PyTorch实现

文章目录 文章地址网络各层结构代码实现 文章地址 An End-to-End Traffic Visibility Regression Algorithm文章通过训练搜集得到的真实道路图像数据集&#xff08;Actual Road dense image Dataset, ARD&#xff09;&#xff0c;通过专业的能见度计和多人标注&#xff0c;获得…

C++重载 强制类型转换运算符

文章目录 1.函数调用运算符重载2.强制类型转换运算符重载2.1对运算符的认识2.2类型强制转换运算符 1.函数调用运算符重载 class Display { public:void operator()(string text){cout << text << endl;}}; class Add { public:int operator()(int v1, int v2){ret…

在Win11上部署ChatGLM2-6B详细步骤--(上)准备工作

一&#xff1a;简单介绍 ChatGLM-6B是清华大学知识工程和数据挖掘小组&#xff08;Knowledge Engineering Group (KEG) & Data Mining at Tsinghua University&#xff09;发布的一个开源的对话机器人。根据官方介绍&#xff0c;这是一个千亿参数规模的中英文语言模型。并…

C++继承总结(下)——菱形继承

一.什么是菱形继承 菱形继承是多继承的一种特殊情况&#xff0c;一个类有多个父类&#xff0c;这些父类又有相同的父类或者祖先类&#xff0c;那么该类就会有多份重复的成员&#xff0c;从而造成调用二义性和数据冗余。 class Person {public:Person(){cout << "P…

新手小白怎么选择配音软件?

现在的配音软件软件很多&#xff0c;各种类型的都比较多&#xff0c;对于新手小白来说不知该如何选择&#xff0c;今天就来给你分享几款好用的配音软件。不论是制作短视频还是制作平常音频都完全可以。 第一款&#xff1a;悦音配音 这是一款专业的视频配音软件&#xff0c;多端…

内存马概念

内存马概念 文章目录 内存马概念木马演变内存使用条件内存缺点JAVA Web三大组件Listener:监听器servelet请求流程内存马分类内存演示内存马植入方式案例shiro反序列化漏洞植入内存马 木马演变 内存使用条件 1. 禁止外联 2. 文件监控、查杀 3. spring Boot&#xff0c;不支持js…

【已解决】goland每次都自动删除我import的包

需要2步&#xff1a; 第一步&#xff1a;取消Optimize imports on the fly勾选 第二步&#xff1a;取消Optimize imports

IO进程及相关函数

什么是环境变量 http://t.csdnimg.cn/nPrMu 进程&#xff1a;是程序执行的一次执行过程&#xff0c;是动态&#xff0c;涉及到资源分配&#xff0c;包含创建、调度、执行 程序&#xff1a;存放在磁盘空间上的一个二进制文件&#xff0c;是指令集合&#xff0c;是静态的&#xf…

MacOS系统Chrome开发者模式下载在线视频

操作流程 # step1. 进入开发者模式 command option i # step2. 在搜索栏中搜索 getHttpVideoInfo.do?关键词 # step3. 在Preview的Json界面中找到video&#xff0c;然后选择不同resolution & duration的视频片段&#xff1b; # step4. 选择合适的video::chapters, 选择…

【鸿蒙软件开发】ArkTS基础组件之Marquee(文字跑马灯)、QRCode(二维码生成)

文章目录 前言一、Marquee组件1.1 子组件1.2 创建Marquee组件参数 1.3 属性1.4 事件1.5 示例代码 二、QRCode2.1 子组件2.2 接口2.3 参数2.4 属性2.5 事件2.6 示例代码 总结 前言 Marquee组件&#xff1a;跑马灯组件&#xff0c;用于滚动展示一段单行文本&#xff0c;仅当文本…

python+requests接口自动化测试框架

1、首先&#xff0c;我们先来理一下思路。 正常的接口测试流程是什么&#xff1f; 脑海里的反应是不是这样的&#xff1a; 确定测试接口的工具 —> 配置需要的接口参数 —> 进行测试 —> 检查测试结果&#xff08;有的需要数据库辅助&#xff09; —> 生成测试报…

算法通关村第三关-白银挑战双指针思想

大家好我是苏麟 , 今天带来算法第三关 . 本期大纲 元素奇偶移动专题 元素奇偶移动专题 描述 : 给你一个整数数组 nums&#xff0c;将 nums 中的的所有偶数元素移动到数组的前面&#xff0c;后跟所有奇数元素。 返回满足此条件的 任一数组 作为答案。 题目 : LeetCode 905.…