Java 超详细实现导入导出 (包含时间转换问题和样式)

序言

工作中遇到了导入导出问题,并且出现了导入或导出Excel时间格式变为数字的问题。通过学习解决实现了这些功能,记录总结分享给大家。本文将详细介绍如何使用 Java 编程语言和 Apache POI 库来实现这些功能。我们将通过一个示例项目演示如何从数据库中读取数据并将其导出为 Excel 文件,然后再从 Excel 文件中读取数据并导入回数据库。 

问题

导入或导出 Excel 时,时间格式变为数字的问题通常是由于 Excel 在处理日期时间时的内部表示方式所致。Excel会将日期时间数据存储为一个数字,该数字代表自 1900 年 1 月 1 日以来的天数(对于日期部分)或天数加上小数表示的时间部分。因此,如果不正确处理这些日期时间数据,Excel 可能会显示为日期时间的数字格式,而不是人类可读的日期时间格式。 

例:这是数据库时间 

 

导入之后

 

准备工作

在开始之前,确保你已经准备好以下环境和工具:

  • Java 开发环境(JDK11)
  • Maven 项目管理工具 (3.6.1)
  • IDE(例如 IntelliJ IDEA 或 Eclipse)
  • Apache POI 库
  • Mybatis-Plus / Mybatis 

1. 创建 Maven 项目并导入依赖

首先,创建一个 Maven 项目并在 pom.xml 文件中添加 Apache POI 的依赖:

        <!-- Apache POI -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>5.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>5.2.3</version> <!-- 版本号根据实际情况调整 -->
        </dependency>

2.实体类和数据库如下

@Data
@TableName("excel")
public class DataEntity {
    private Long id;
    private String name;
    private int age;
    private String email;
    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
    @TableField(value = "birthday")
    private LocalDate birthday;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @TableField(value = "currenttime")
    private LocalDateTime currentTime;
}

 3.yml配置连接数据库,用Mybatis-Plus / Mybatis 写Mapper,Service,Impl此处不再赘述

导出功能实现

1.编写导出功能的 Controller

创建一个 Spring MVC 的 Controller 类,实现数据导出到 Excel 的功能:

@RestController
@RequestMapping("/execl")
public class ExeclController {
    @Resource
    private DataService dataService;

    @GetMapping("/export")
    public ResponseEntity<byte[]> exportDataToExcel() throws IOException {

        //读取数据库全部数据
        List<DataEntity> dataList = dataService.list();

        // 创建一个工作簿
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("Data");

        // 创建表头
        Row headerRow = sheet.createRow(0);
        headerRow.createCell(0).setCellValue("ID");
        headerRow.createCell(1).setCellValue("Name");
        headerRow.createCell(2).setCellValue("Age");
        headerRow.createCell(3).setCellValue("Email");
        headerRow.createCell(4).setCellValue("Birthday");
        headerRow.createCell(5).setCellValue("CurrentTime");

        // 日期和时间格式化器
        // 将 LocalDate 和 LocalDateTime 转换为字符串格式
        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");


        // 创建日期单元格样式
        //CreationHelper 是 Apache POI 提供的一个帮助类,用于创建各种格式和样式。
        CreationHelper creationHelper = workbook.getCreationHelper();
        //CellStyle 是用于定义单元格样式的类。
        //workbook.createCellStyle() 方法用于创建一个新的单元格样式对象。
        //dateStyle.setDataFormat(...) 方法用于设置单元格的数据格式。
        //creationHelper.createDataFormat().getFormat("yyyy-MM-dd") 方法用于获取日期格式的代码,"yyyy-MM-dd" 是我们想要的日期格式。
        CellStyle dateStyle = workbook.createCellStyle();
        dateStyle.setDataFormat(creationHelper.createDataFormat().getFormat("yyyy-MM-dd"));
        CellStyle dateTimeStyle = workbook.createCellStyle();
        dateTimeStyle.setDataFormat(creationHelper.createDataFormat().getFormat("yyyy-MM-dd HH:mm:ss"));

        // 填充数据行
        int rowNum = 1;
        for (DataEntity data : dataList) {
            Row row = sheet.createRow(rowNum++);
            row.createCell(0).setCellValue(data.getId());
            row.createCell(1).setCellValue(data.getName());
            row.createCell(2).setCellValue(data.getAge());
            row.createCell(3).setCellValue(data.getEmail());
            // 格式化并设置日期,单元格样式
            Cell birthdayCell = row.createCell(4);
            birthdayCell.setCellValue(data.getBirthday().format(dateFormatter));
            birthdayCell.setCellStyle(dateStyle);

            // 格式化并设置日期,单元格样式
            Cell currentTimeCell = row.createCell(5);
            currentTimeCell.setCellValue(data.getCurrentTime().format(dateTimeFormatter));
            currentTimeCell.setCellStyle(dateTimeStyle);
        }

        // 调整列宽以适应内容
        for (int i = 0; i < 6; i++) {
            sheet.autoSizeColumn(i);
        }

        // 将工作簿写入字节数组输出流
        ByteArrayOutputStream
                outputStream = new ByteArrayOutputStream();
        //这个方法用于将工作簿(通常是Excel文件)的内容写入到一个OutputStream中
        workbook.write(outputStream);
        workbook.close();

        // 将字节数组输出流转换为字节数组
        byte[] bytes = outputStream.toByteArray();

        // 设置响应头
        //HttpHeaders 类:这个类是 Spring 提供的一个方便的 HTTP 头部管理工具类,可以用来设置各种 HTTP 头部字段。
        HttpHeaders headers = new HttpHeaders();
        //设置响应的内容类型(Content-Type)
        //application/vnd.openxmlformats-officedocument.spreadsheetml.sheet 是 Excel 文件的 MIME 类型,表示返回的是一个 Excel 文件。
        //MediaType.parseMediaType 方法:这个方法用来解析 MIME 类型字符串并返回一个 MediaType 对象。
        headers.setContentType(MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"));
        //设置响应的内容处置方式(Content-Disposition),告诉浏览器如何处理响应的内容。
        //Content-Disposition 头部:这个头部字段有助于控制浏览器对于响应内容的处理方式。它常用于提示浏览器下载文件,而不是直接在浏览器中显示内容。
        //attachment:表示响应的内容是一个附件,应该提示用户下载
        //data.xlsx":表示下载文件的默认名称为 data.xlsx
        headers.setContentDispositionFormData("attachment", "data.xlsx");

        // 返回 Excel 文件作为 ResponseEntity
        return ResponseEntity.ok()
                .headers(headers)
                .body(bytes);
    }

2.浏览器测试,输入http://localhost:你的端口号/execl/export即可下载

 

 

导入功能实现

1. 实现数据导入的 Controller

创建另一个 Controller 类,实现从 Excel 文件导入数据并存入数据库的功能:

@PostMapping("/import")
    public ResponseEntity<String> importDataFromExcel(@RequestParam("file") MultipartFile file) throws IOException {
        // 检查文件是否为空
        if (file.isEmpty()) {
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("文件为空");
        }

        // 用于存储解析后的数据
        List<DataEntity> dataList = new ArrayList<>();

        // 使用try-with-resources自动关闭资源
        try (InputStream inputStream = file.getInputStream();
             Workbook workbook = new XSSFWorkbook(inputStream)) {

            // 获取第一个工作表
            Sheet sheet = workbook.getSheetAt(0);
            int rowNum = 1; // 行号计数器
            for (Row row : sheet) {
                // 跳过表头行
                if (rowNum == 1) {
                    rowNum++;
                    continue;
                }

                // 创建并填充数据实体
                DataEntity data = new DataEntity();
                data.setId((long) row.getCell(0).getNumericCellValue());
                data.setName(row.getCell(1).getStringCellValue());
                data.setAge((int) row.getCell(2).getNumericCellValue());
                data.setEmail(row.getCell(3).getStringCellValue());

                //将字符串转换回 LocalDate 类型
                String birthdayString = row.getCell(4).getStringCellValue();
                LocalDate birthday = LocalDate.parse(birthdayString, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                data.setBirthday(birthday);

                //将字符串转换为 LocalDateTime 类型
                String currentTimeString = row.getCell(5).getStringCellValue();
                LocalDateTime currentTime = LocalDateTime.parse(currentTimeString, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                data.setCurrentTime(currentTime);


                // 添加到数据列表
                dataList.add(data);
            }
        }

        // 将数据保存到数据库
        dataService.saveBatch(dataList);

        // 返回成功响应
        return ResponseEntity.ok("数据导入成功");
    }

2.Postman测试

Excel数据 

 

数据库导入成功

 

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

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

相关文章

C语言| 数组倒置II

数组倒置第二种方法&#xff1a;直接在数组内进行倒置 第一个元素和最后一个元素交换&#xff0c; 第二个元素和倒数第二个元素交换 第三个元素和倒数第三个元素交换...... 数组元素个数为偶数&#xff0c;每个元素都能交换一次&#xff1b; 数组元素个数为奇数&#xff0c;最…

这次,彻底理解 JavaScript 的执行机制

无论你是 JavaScript 的初学者还是专家&#xff0c;无论是为了求职面试还是日常开发工作&#xff0c;我们经常会遇到这样的情况&#xff1a;给出几行代码&#xff0c;我们需要知道它们的输出内容和顺序。由于 JavaScript 是一种单线程语言&#xff0c;我们可以得出以下结论&…

南昌代理记账服务,打造专业财务管理团队

随着企业的发展和规模不断扩大&#xff0c;财务管理也变得越来越重要&#xff0c;而代理记账作为一种专业的财务管理服务&#xff0c;正逐步成为中小企业发展的必要条件之一&#xff0c;南昌作为江西省的省会城市&#xff0c;拥有一批优秀的会计服务机构&#xff0c;为各类企业…

基于Java学生选课管理系统设计和实现(源码+LW+调试文档+讲解等)

&#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者&#xff0c;博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f31f;文末获取源码数据库&#x1f31f; 感兴趣的可以先收藏起来&#xff0c;…

【启明智显产品分享】工业级HMI芯片——Model3,不止是速度,USB\CAN\8路串口

一、引言 Model3作为一款工业级HMI芯片&#xff0c;其性能卓越且功能全面。本文将从多个角度深入介绍Model3芯片&#xff0c;以展示其不仅仅是速度的代表。 二、Model3核心特性介绍 Model3工业级跨界MCU是一款国产自主的基于RISC-V架构的高性能芯片&#xff0c;内置平头哥E…

你只是重新发现了一些东西

指北君关于另外一条思维路径的发现。 "自以为是"的顿悟时刻 有很多时候&#xff0c;我会"自以为是"的发现/发明一些东西。这种"自以为是"的时刻通常还带有一些骄傲自豪的情绪。这种感觉特别像古希腊博学家阿基米德 在苦思冥想如何测量不规则物体…

windows使用curl命令出现乱码的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

deepin 加入甲辰计划,共建 RISC-V 繁荣生态

内容来源&#xff1a;deepin&#xff08;深度&#xff09;社区 今日&#xff0c;deepin(深度)社区宣布正式加入甲辰计划&#xff0c;致力于在下一个丙辰年&#xff08;2036龙年&#xff09;之前&#xff0c;基于RISC-V实现从数据中心到桌面办公、从移动穿戴到智能物联网全信息产…

通俗解释resultType和resultMap的区别

【 1 对于单表而言&#xff1a; 注&#xff1a;以下都是摘抄过来的&#xff0c;做了让自己更能理解的版本 如果数据库返回结果的列名和要封装的实体的属性名完全一致的话用 resultType 属性 如果数据库返回结果的列名&#xff08;起了别名&#xff09;和要封装的实体的属性名…

Android使用MPAndroidChart 绘制折线图

效果图&#xff1a; 1.导入依赖 1.1在项目根目录下的build.gradle文件中添加代码&#xff08;注意不是app下的build.gradle&#xff09;&#xff1a; maven { url https://jitpack.io } 1.2在app下的build.gradle中的依赖下添加&#xff1a; implementation com.github.PhilJa…

STM32单片机USART串口收发数据包

文章目录 1. 串口通信 1.1 串口初始化 1.2 库函数 2. 串口收发HEX数据包 2.1 Serial.c 2.2 Serial.h 2.3 main.c 3. 串口收发文本数据包 3.1 Serial.c 3.2 Serial.h 3.3 main.c​​​​​​​ 1. 串口通信 对于串口通信的详细​​​​​​​解析可以看下面这篇文章…

生产实习Day7 ---- Hive介绍

文章目录 概要整体架构流程Hive数据库操作建表语法表分类 概要 Hive是基于Hadoop的数据仓库工具。可以用于存储在Hadoop集群中的HDFS文件数据集进行数据整理、特殊查询和分析处理。Hive提供了类似于关系型数据库SQL语言的HiveQL工具&#xff0c;通过HQL&#xff08;HiveQL&…

用VPS部署聊天机器人有哪些优势?

VPS足以帮助您将人工智能 (AI) 的功能无缝融入聊天机器人并增强客户支持。聊天机器人已迅速成为改善用户体验的首选解决方案&#xff0c;因为它们全天候在线且可编程回答各种问题。 聊天机器人在客户支持方面的作用不容置疑。但所有出色的解决方案都需要出色的网络托管。 VPS…

从零到发布:npm插件包终极指南

在JavaScript和Node.js的生态系统中&#xff0c;npm&#xff08;Node Package Manager&#xff09;是最重要的包管理工具之一。通过npm&#xff0c;开发者可以共享代码、复用他人的工作成果以及协作开发。本指南将详细介绍如何通过npm发布自己的插件包&#xff0c;以便其他开发…

力扣372. 超级次方

Problem: 372. 超级次方 文章目录 题目描述思路复杂度Code 题目描述 思路 1.处理数组指数&#xff1a;如下图可以将其转换为一个递归的操作 2.处理 mod 运算:对于模运算我们有公式&#xff1a; ( a b ) % k ( a % k ) ( b % k ) % k (a \times b) \% k (a \% k) \times (b…

如何利用数据仓库进行业务分析:一名大数据工程师的视角

在大数据时代&#xff0c;数据的有效利用对企业的成功至关重要。 本文将基于上面的流程图&#xff0c;详细介绍如何利用数据仓库进行业务分析&#xff0c;并提供实际的例子和代码演示&#xff0c;以帮助读者更好地理解和应用相关技术。 数据仓库的基本流程 上图展示了一个典…

PointCloudLib 点云边缘点提取 C++版本

0.实现效果 1.算法原理 PCL(Point Cloud Library)中获取点云边界的算法主要基于点云数据的几何特征和法向量信息。以下是对该算法的详细解释,按照清晰的格式进行归纳: 算法概述 PCL中的点云边界提取算法主要用于从3D点云数据中识别并提取出位于物体边界上的点。这些边界…

五种主流数据库连接池的比较和分析(从零入门)

数据库连接池&#xff08;Database Connection Pool&#xff09;是现代应用程序中至关重要的组件。它通过管理一组数据库连接的复用&#xff0c;极大地提升了应用程序的性能和效率。在没有连接池的情况下&#xff0c;每个数据库请求都需要打开和关闭数据库连接&#xff0c;这不…

【C++】关于代码编译自动更新版本的问题

在写代码的时候&#xff0c;总是需要添加一个版本号&#xff0c;用于后续的版本管理 我常遇到的一个问题是&#xff0c;开发过程中&#xff0c;不一定会记得这件事情&#xff0c;导致有时候会出现同样的版本 于是希望有一个方式&#xff0c;能在编译代码的时候自动生成一个版…

【机器学习 复习】第11章 神经网络与深度学习(重中之重)

一、概念 1.神经元模型 &#xff08;1&#xff09;神经网络的基本组成单位 &#xff08;2&#xff09;生物上&#xff0c;每个神经元通过树突接受来自其他被激活神经元的信息&#xff0c;通过轴突释放出来的化学递质改变当前神经元内的电位。当神经元内的电位累计到一个水平时…