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

一、需求

现将列表数据,导出到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.mfbz.cn/a/107735.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

UE5 C++自定义Http节点获得Header数据

一、新建C文件 选择All Classes&#xff0c;选择父类BlueprintFunctionLibrary&#xff0c;命名为SendHttpRequest。 添加Http支持 代理回调的参数使用DECLARE_DYNAMIC_DELEGATE_TwoParam定义&#xff0c;第一参数是代理类型&#xff0c;后面是参数1类型&#xff0c;参数1&…

APP自动化测试 ---- Appium介绍及运行原理

在面试APP自动化时&#xff0c;有的面试官可能会问Appium的运行原理&#xff0c;以下介绍Appium运行原理。 一、Appium介绍 1.Appium概念 Appium是一个开源测试自动化框架&#xff0c;可用于原生&#xff0c;混合和移动Web应用程序测试。它使用WebDriver协议驱动IOS&#xf…

33:深入浅出x86中断机制

背景 我们知道使用0x10号中断&#xff0c;可以在屏幕上打印一个字符。 问题 系统中的 中断 究竟是什么&#xff1f; 生活中的例子 来看一个生活中例子&#xff1a; 小狄的工作方式 在处理紧急事务的时候&#xff0c;不回应同事的技术求助。老板的召唤必须回应&#xff0c;…

C/C++面试常见问题——const关键字的作用和用法

首先我们需要一下const关键字的定义&#xff0c;const名叫常量限定符&#xff0c;当const修饰变量时&#xff0c;就是在告诉编译器该变量只可访问不可修改&#xff0c;而编译器对于被const修饰的变量有一个优化&#xff0c;编译器不会专门为其开辟空间&#xff0c;而是将变量名…

linux入门---多线程的控制

目录标题 线程库pthread_create如何一次性创建多个线程线程的终止线程的等待线程取消分离线程如何看待其他语言支持的多线程线程id的本质线程的局部存储线程的封装 线程库 要想控制线程就得使用原生线程库也可以将其称为pthread库&#xff0c;这个库是遵守posix标准的&#xf…

【AD9361 数字接口CMOS LVDSSPI】B 并行数据之CMOS 续

续【AD9361 数字接口CMOS &LVDS&SPI】B 并行数据之CMOS 数据总线空闲和周转周期 &#xff08;CMOS&#xff09; P0_D[11&#xff1a;0]和P1_D[11&#xff1a;0]总线信号通常由BBP或AD9361有源驱动。在任何空闲期间&#xff0c;两个组件都会忽略数据总线值。但是&…

【Linux】权限完结

个人主页点击直达&#xff1a;小白不是程序媛 系列专栏&#xff1a;Linux被操作记 目录 前言 chown指令 chgrp指令 文件类型 file指令 目录的权限 粘滞位 umask指令 权限总结 前言 上篇文章我们说到对于一个文件所属者和所属组都是同一个人时&#xff0c;使用所属者身…

计算机操作系统重点概念整理-第五章 文件管理【期末复习|考研复习】

第五章 文件管理 【期末复习|考研复习】 计算机操作系统系列文章传送门&#xff1a; 第一章 计算机系统概述 第二章 进程管理 第三章 进程同步 第四章 内存管理 第五章 文件管理 第六章 输出输出I/O管理 文章目录 第五章 文件管理 【期末复习|考研复习】前言五、文件管理5.1 文…

使用pycharm远程调试

使用pycharm 专业版&#xff0c; 在设置解释器中&#xff0c;具备ssh 解释器功能&#xff1b; 一般在本地无法调试远程端代码&#xff0c;机械性的scp传输文件十分影响工作效率&#xff0c;PyCharm的Pro支持远程Run&#xff0c;Debug&#xff0c;等可视化的功能。 操作系统&…

自动驾驶之—2D到3D升维

前言&#xff1a; 最近在学习自动驾驶方向的东西&#xff0c;简单整理一些学习笔记&#xff0c;学习过程中发现宝藏up 手写AI 3D卷积 3D卷积的作用&#xff1a;对于2DCNN&#xff0c;我们知道可以很好的处理单张图片中的信息&#xff0c;但是其对于视频这种由多帧图像组成的图…

FPGA_状态机工作原理

FPGA_状态机介绍和工作原理 状态机工作原理Mealy 状态机模型Moore 状态机模型状态机描述方式代码格式 总结 状态机工作原理 状态机全称是有限状态机&#xff08;Finite State Machine、FSM&#xff09;&#xff0c;是表示有限个状态以及在这些状态之间的转移和动作等行为的数学…

Istio 运行错误 failed to update resource with server-side apply for obj 问题解决

Istio 环境 kubernetes version: v1.18.2 istio version: v1.10.0运行之后 istio-operator 的日志就抛出下面错误&#xff0c;而且会一直重启 # kubectl get iop -A NAMESPACE NAME REVISION STATUS AGE istio-system iop-pro-cluster…

JVM进阶(1)

一)JVM是如何运行的&#xff1f; 1)在程序运行前先将JAVA代码转化成字节码文件也就是class文件&#xff0c;JVM需要通过类加载器将字节码以一定的方式加载到JVM的内存运行时数据区&#xff0c;将类的信息打包分块填充在运行时数据区&#xff1b; 2)但是字节码文件是JVM的一套指…

高三高考免费试卷真题押题知识点合集

发表于安徽 温馨提示&#xff1a;有需要的真题试卷可联系本人&#xff0c;百卷内上免费资源。 感觉有用的下方三连&#xff0c;谢谢 ​ 。 免费版卷有6-60卷每卷平均4-30页 高三免费高三地理高三英语高三化学高三物理高三语文高三历史高三政治高三数学高三生物 付费版卷有1…

适用于 Mac 或 Windows 的 4 种最佳 JPEG/PNG图片 恢复软件

您的计算机或外部存储驱动器上很可能有大量 JPEG /PNG图片照片&#xff0c;但不知何故&#xff0c;您意识到一些重要的 JPEG /PNG图片文件丢失或被删除&#xff0c;它们对您来说意义重大&#xff0c;您想要找回它们. 4 种最佳 JPEG/PNG图片 恢复软件 要成功执行 JPEG /PNG图片…

面试题复盘-2023/10/20

目录 笔试题面试题&#xff08;未完待续&#xff09; 笔试题 一.多选题 A:map的key是const,不可更改 B:STL中的快速排序比一般的快速排序速度更快&#xff0c;是因为中值排序法 C:list的插入效率是O(1) D:vector的容量只能增大不能减小 解析&#xff1a; B: STL中的sort函数的…

父子项目打包发布至私仓库

父子项目打包发布至私仓库 1、方法一 在不需要发布至私仓的模块上添加如下代码&#xff1a; <plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-deploy-plugin</artifactId><configuration><skip>true</s…

SpringBoot内置工具类之断言Assert的使用与部分解析

先例举一个service的demo中用来验证参数对象的封装方法&#xff0c;使用了Assert工具类后是不是比普通的 if(xxx) { throw new RuntimeException(msg) } 看上去要简洁多了&#xff1f; 断言Assert工具类简介 断言是一个判断逻辑&#xff0c;用来检查不该发生的情况&#xff…

san.js源码解读之模版解析(parseTemplate)篇——readIdent函数

一、源码分析 /*** 读取ident* 这里的 ident 指标识符(identifier)&#xff0c;也就是通常意义上的变量名* 这里默认的变量名规则为&#xff1a;由美元符号($)、数字、字母或者下划线(_)构成的字符串** inner* param {Walker} walker 源码读取对象* return {string}*/ functio…

EtherNet Ip工业RFID读写器与欧姆龙PLC 配置示例说明

一、准备阶段 POE交换机欧姆龙PLC 支持EtherNet Ip协议CX-Programmer 9.5配置软件 二、配置读卡器 1、打开软件 2、选择网卡&#xff0c;如果多网卡的电脑请注意对应所接的网卡&#xff0c;网卡名一般为“Network adapter Realtek PCIe GBE Family” 3、点击“选择网卡”&…