SpringBoot 数据库批量导入导出 Xlsx文件的导入与导出 全量导出 数据库导出表格 数据处理 外部数据

news2025/7/27 22:29:40

介绍

poi-ooxml 是 Apache POI 项目中的一个库,专门用于处理 Microsoft Office 2007 及以后版本的文件,特别是 Excel 文件(.xlsx 格式)和 Word 文件(.docx 格式)。

在管理系统中需要对数据库的数据进行导入或导出在系统中经常使用的到。

Java针对MS Office的操作的库屈指可数,比较有名的就是Apache的POI库。这个库异常强大,但是使用起来也并不容易。Hutool针对POI封装一些常用工具,使Java操作Excel等文件变得异常简单。

胡图官网:https://doc.hutool.cn/pages/poi/#%E7%94%B1%E6%9D%A5

Hutool-poi是针对Apache POI的封装,因此需要用户自行引入POI库,Hutool默认不引入。

  • XLS:是 Excel 97-2003 版本的文件格式,基于二进制文件格式。存储数据和工作表信息采用了二进制格式,不易直接读取和处理。

  • XLSX:是 Excel 2007 及更高版本使用的文件格式,基于 XML。XLSX 实际上是一个压缩的文件包,里面包含了多个 XML 文件,更加标准化和易于扩展。

依赖

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

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.7.18</version>
</dependency>

实体类

支持别名注解的。可以在字段上加@Alias注解。

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("site")
public class Site implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.AUTO)
    @Alias(value = "编号")
    private Integer id;

    @TableField("ip_address")
    @Alias(value = "IP地址")
    private String ipAddress;

    @TableField("source")
    @Alias(value = "来源")
    private String source;

    @TableField("operation")
    private String operation;

    @TableField("access_time")
    private LocalDateTime accessTime;
    
}

在这里插入图片描述

导出Xls

 @GetMapping()
    public void export(HttpServletResponse response) throws Exception{

        String fileName = "测试.xls";
        String encodedFileName = URLEncoder.encode(fileName, "UTF-8");
        encodedFileName = encodedFileName.replace("+", "%20");  // 处理空格字符

        List<Site> list = siteService.list();
// 通过工具类创建writer,默认创建xls格式
        ExcelWriter writer = ExcelUtil.getWriter();

// 一次性写出内容,使用默认样式,强制输出标题
        writer.write(list, true);

        //response为HttpServletResponse对象
        response.setContentType("application/vnd.ms-excel;charset=utf-8");

        //test.xls是弹出下载对话框的文件名
        response.setHeader("Content-Disposition","attachment;filename="+encodedFileName);

        ServletOutputStream out=response.getOutputStream();

        writer.flush(out, true);
    // 关闭writer,释放内存
        writer.close();
//此处记得关闭输出Servlet流
        IoUtil.close(out);

    }

在这里插入图片描述

导出Xlsx

@GetMapping()
public void export(HttpServletResponse response) throws Exception{

    String  fileName = URLEncoder.encode("测试.xlsx", "UTF-8").replace("+", "%20");

    List<Site> list = siteService.list();

    ExcelWriter writer = ExcelUtil.getWriter(true);
    writer.write(list, true);

    response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
    response.setHeader("Content-Disposition","attachment;filename="+fileName);
    ServletOutputStream out=response.getOutputStream();

    writer.flush(out, true);
    writer.close();
    IoUtil.close(out);
    
}

以上都是基于全量数据的导出方法,下面是按需导出。


创建自定义注解

@Retention(RetentionPolicy.RUNTIME) // 保证注解在运行时可访问
public  @interface ExcelTitle {
    String value(); // 用来保存 Excel 列标题
}

自定义实体类

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("site")
public class Site implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    @TableField("ip_address")
    @ExcelTitle("IP地址")
    private String ipAddress;

    @TableField("source")
    @ExcelTitle("来源")
    private String source;

    @TableField("operation")
    @ExcelTitle("测试字段")
    private String operation;

    @TableField("access_time")
    @ExcelTitle("访问时间")
    private LocalDateTime accessTime;

}

按需不排序

@GetMapping() 
public void export(HttpServletResponse response) throws Exception{

    // 需要导出的字段名
    String[] key = {"访问时间", "IP地址", "来源"};

    // 查找性能较高
    Set<String> keySet = new HashSet<>(Arrays.asList(key));

    // 对文件名进行 URL 编码,防止中文字符出现乱码,并将 "+" 替换成 "%20"
    String fileName = URLEncoder.encode("测试.xlsx", "UTF-8").replace("+", "%20");

    // 从服务层获取数据列表,通常是从数据库或其他数据源获取
    List<Site> list = siteService.list();

    // 创建一个 ExcelWriter 实例,用于写入 Excel 文件,true 表示创建时有表头
    ExcelWriter writer = ExcelUtil.getWriter(true);

    // 获取 Site 类的所有字段(反射机制)
    Field[] fields = Site.class.getDeclaredFields();

    // 遍历每个字段
    for (Field field : fields) {

        // 获取字段上是否有 @ExcelTitle 注解
        ExcelTitle excelAnnotation = field.getAnnotation(ExcelTitle.class);

        // 如果字段上存在 @ExcelTitle 注解
        if (excelAnnotation != null) {

            // 获取注解中的 value 值(即字段对应的 Excel 标题)
            String excelValue = excelAnnotation.value();

            // 判断当前字段的 Excel 标题是否是我们关心的字段
            if (Arrays.asList(key).contains(excelValue)) {

                // 如果是我们关心的字段,则添加标题别名(即字段名与 Excel 表头的映射关系)
                writer.addHeaderAlias(field.getName(), excelValue);
            }
        }
    }

    // 默认情况下,未添加 alias 的属性也会被写出。如果我们只想输出加了别名的字段,可以调用该方法
    writer.setOnlyAlias(true);

    // 将数据写入 Excel 文件,true 表示需要写入表头
    writer.write(list, true);

    // 设置响应内容类型为 Excel 文件格式
    response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");

    // 设置响应头,指定下载的文件名
    response.setHeader("Content-Disposition", "attachment;filename=" + fileName);

    // 获取响应输出流,用于将文件写入客户端
    ServletOutputStream out = response.getOutputStream();

    // 将 Excel 内容刷新到输出流
    writer.flush(out, true);

    // 关闭 writer 释放资源
    writer.close();

    // 关闭输出流
    IoUtil.close(out);
}

按需排序导出

    @GetMapping()
    public void export(HttpServletResponse response) throws Exception {

        String[] key = {"访问时间", "IP地址", "来源"};
        Set<String> keySet = new HashSet<>(Arrays.asList(key));


        String fileName = URLEncoder.encode("测试.xlsx", "UTF-8").replace("+", "%20");

        List<Site> list = siteService.list();

        ExcelWriter writer = ExcelUtil.getWriter(true);

        for (String k : key) {
          String title =  getCharacter(Site.class, k);
          if(title==null)continue;
            writer.addHeaderAlias(title, k);
        }


//        //自定义标题别名
//        writer.addHeaderAlias("ipAddress", "IP地址");

        // 默认的,未添加alias的属性也会写出,如果想只写出加了别名的字段,可以调用此方法排除之
        writer.setOnlyAlias(true);

        writer.write(list, true);


        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
        ServletOutputStream out = response.getOutputStream();

        writer.flush(out, true);
        writer.close();
        IoUtil.close(out);

    }
/**
 * 根据传入的类和关键字,查找类中具有 @ExcelTitle 注解的字段,
 * 如果该字段的 @ExcelTitle 注解的 value 属性与传入的关键字匹配,则返回该字段的名称。
 *
 * @param clazz 目标类的 Class 对象,用于获取类的字段信息。
 * @param key   需要匹配的关键字,用于查找与其对应的 @ExcelTitle 注解的字段。
 * @return 如果找到匹配的字段,则返回字段名称;否则返回 null。
 */
public String getCharacter(Class<Site> clazz, String key) {
    // 获取目标类的所有字段
    Field[] fields = clazz.getDeclaredFields();
    
    // 遍历所有字段
    for (Field field : fields) {
        // 获取当前字段的 @ExcelTitle 注解
        ExcelTitle excelAnnotation = field.getAnnotation(ExcelTitle.class);

        // 如果字段具有 @ExcelTitle 注解
        if (excelAnnotation != null) {
            
            // 获取注解的 value 值
            String excelValue = excelAnnotation.value();

            // 检查传入的 key 是否与 @ExcelTitle 注解中的值匹配
            if (Arrays.asList(key).contains(excelValue)) {
                
                // 如果匹配,返回字段名称
                return field.getName();
            }
        }
    }
    
    // 如果没有找到匹配的字段,返回 null
    return null;
}

在这里插入图片描述
也可以将该功能给前端去做。


批量导入

@PostMapping("/import")
public String importData(MultipartFile file) throws IOException {

    //读取文件转成输入流
    ExcelReader reader = ExcelUtil.getReader(file.getInputStream());

    List<Object> header = reader.readRow(0); // 读取第0行作为列标题
    for (Object column : header) {
        reader.addHeaderAlias(column+"",getCharacter(Site.class,column+""));
        }

    List<Site> list = reader.readAll(Site.class);
    siteService.saveBatch(list);
    
    return null;
}

模板下载

@GetMapping("/template")
public void template(HttpServletResponse response) throws Exception {
    // 定义模板标题
    String[] key = {"访问时间", "IP地址", "来源"};

    // 文件名编码
    String fileName = URLEncoder.encode("测试.xlsx", "UTF-8").replace("+", "%20");

    // 创建一个空的 List,作为数据源,模板将只包含标题行
    List<Map<String, Object>> list = new ArrayList<>();

    // 生成空数据的行
    Map<String, Object> emptyRow = new HashMap<>();
    for (String column : key) {
        emptyRow.put(column, "");  // 为空字段赋空值
    }
    list.add(emptyRow); // 将空数据行添加到 list

    // 创建 ExcelWriter
    ExcelWriter writer = ExcelUtil.getWriter(true);

    // 为每一列设置别名
    for (String k : key) {
        writer.addHeaderAlias(k, k);  // 直接使用标题作为别名
    }

    // 写入空数据(标题和一行空数据)
    writer.write(list, true);

    // 设置响应的内容类型和头部,触发浏览器下载
    response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
    response.setHeader("Content-Disposition", "attachment;filename=" + fileName);

    // 获取输出流,写入到客户端
    ServletOutputStream out = response.getOutputStream();

    // 将数据写入输出流
    writer.flush(out, true);
    writer.close();
    IoUtil.close(out);
}

测试demo,实际业务自行优化

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

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

相关文章

解决:install via Git URL失败的问题

为解决install via Git URL失败的问题&#xff0c;修改安全等级security_level的config.ini文件&#xff0c;路径如下&#xff1a; 还要重启&#xff1a; 1.reset 2.F5刷新页面 3.关机服务器&#xff0c;再开机&#xff08;你也可以省略&#xff0c;试试&#xff09; 4.Wind…

OpenCV CUDA模块特征检测------创建Harris角点检测器的GPU实现接口cv::cuda::createHarrisCorner

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 该函数创建一个 基于 Harris 算法的角点响应计算对象&#xff0c;专门用于在 GPU 上进行高效计算。 它返回的是一个 cv::Ptrcv::cuda::Cornernes…

【氮化镓】钝化层对p-GaN HEMT阈值电压的影响

2021年5月13日,中国台湾阳明交通大学的Shun-Wei Tang等人在《Microelectronics Reliability》期刊发表了题为《Investigation of the passivation-induced VTH shift in p-GaN HEMTs with Au-free gate-first process》的文章。该研究基于二次离子质谱(SIMS)、光致发光(PL)…

C++:优先级队列

目录 1. 概念 2. 特征 3. 优先级队列的使用 1. 概念 优先级队列虽然名字有队列二字&#xff0c;但根据队列特性来说优先级队列不满足先进先出这个特征&#xff0c;优先级队列的底层是用堆来实现的。 优先级队列是一种容器适配器&#xff0c;就是将特定容器类封装作为其底层…

睡眠分期 html

截图 代码 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>睡眠图表</title><script src…

Github 2025-05-29 Go开源项目日报Top9

根据Github Trendings的统计,今日(2025-05-29统计)共有9个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Go项目9Assembly项目1Ollama: 本地大型语言模型设置与运行 创建周期:248 天开发语言:Go协议类型:MIT LicenseStar数量:42421 个Fork数量:27…

AWS VPC 网络详解:理解云上专属内网的关键要素

全面解读 AWS VPC、子网、安全组、路由与 NAT 网关的实际应用 在使用 AWS 云服务的过程中&#xff0c;许多用户最先接触的是 EC2&#xff08;云服务器&#xff09;。但你是否曾遇到过这样的情况&#xff1a;实例启动正常&#xff0c;却无法访问公网&#xff1f;或者数据库无法…

Ubuntu24.04.2 + kubectl1.33.1 + containerdv1.7.27 + calicov3.30.0

Ubuntu24.04.2 kubectl1.33.1 containerdv1.7.27 calicov3.30.0 安装Ubuntu24.04.2 kubectl1.33.1 containerdv1.7.27 calicov3.30.0 1.安装Ubuntu24.04.2&#xff0c;设置阿里云镜像地址 $ sudo vim /etc/apt/sources.list.d/ubuntu.sources URIs: https://mirrors.aliy…

循环神经网络(RNN)全面教程:从原理到实践

循环神经网络(RNN)全面教程&#xff1a;从原理到实践 引言 循环神经网络(Recurrent Neural Network, RNN)是处理序列数据的经典神经网络架构&#xff0c;在自然语言处理、语音识别、时间序列预测等领域有着广泛应用。本文将系统介绍RNN的核心概念、常见变体、实现方法以及实际…

uniapp 键盘顶起页面问题

关于uniapp中键盘顶起页面的问题。这是一个在移动应用开发中常见的问题&#xff0c;特别是当输入框位于页面底部时&#xff0c;键盘弹出会顶起整个页面&#xff0c;导致页面布局错乱。 pages.json 文件内&#xff0c;在需要处理软键盘的页面添加 softinputMode 配置&#xff1…

【C++高级主题】命令空间(五):类、命名空间和作用域

目录 一、实参相关的查找&#xff08;ADL&#xff09;&#xff1a;函数调用的 “智能搜索” 1.1 ADL 的核心规则 1.2 ADL 的触发条件 1.3 ADL 的典型应用场景 1.4 ADL 的潜在风险与规避 二、隐式友元声明&#xff1a;类与命名空间的 “私密通道” 2.1 友元声明的基本规则…

国标GB28181设备管理软件EasyGBS视频平台筑牢文物保护安全防线创新方案

一、方案背景​ 文物作为人类文明的珍贵载体&#xff0c;具有不可再生性。当前&#xff0c;盗窃破坏、游客不文明行为及自然侵蚀威胁文物安全&#xff0c;传统保护手段存在响应滞后、覆盖不全等局限。随着5G与信息技术发展&#xff0c;基于GB28181协议的EasyGBS视频云平台&…

Baklib内容中台AI重构智能服务

AI驱动智能服务进化 在智能服务领域&#xff0c;Baklib内容中台通过自然语言处理技术与深度学习框架的深度融合&#xff0c;构建出具备意图理解能力的知识中枢。系统不仅能够快速解析用户输入的显性需求&#xff0c;更通过上下文关联分析算法识别会话场景中的隐性诉求&#xf…

数据库包括哪些?关系型数据库是什么意思?

目录 一、数据库包括哪些 &#xff08;一&#xff09;关系型数据库 &#xff08;二&#xff09;非关系型数据库 &#xff08;三&#xff09;分布式数据库 &#xff08;四&#xff09;内存数据库 二、关系型数据库是什么 &#xff08;一&#xff09;关系模型的基本概念 …

Python爬虫监控程序设计思路

最近因为爬虫程序太多&#xff0c;想要为Python爬虫设计一个监控程序&#xff0c;主要功能包括一下几种&#xff1a; 1、监控爬虫的运行状态&#xff08;是否在运行、运行时间等&#xff09; 2、监控爬虫的性能&#xff08;如请求频率、响应时间、错误率等&#xff09; 3、资…

【HarmonyOS 5】Laya游戏如何鸿蒙构建发布详解

【HarmonyOS 5】Laya游戏如何鸿蒙构建发布详解 一、前言 LayaAir引擎是国内最强大的全平台引擎之一&#xff0c;当年H5小游戏火的时候&#xff0c;腾讯入股了腊鸭。我还在游戏公司的时候&#xff0c;17年曾经开发使用腊鸭的H5小游戏&#xff0c;很怀念当年和腊鸭同事一起解决…

【鱼皮-用户中心】笔记

任务&#xff1a;完整了解做项目的思路&#xff0c;接触一些企业及的开发技术 title 企业做项目流程需求分析技术选型 计划一一、前端初始化1. **下载node.js**2. **安装yarn**3. **初始化 Ant Design Pro 脚⼿架&#xff08;关于更多可进入官网了解&#xff09;**4. **开启Umi…

交错推理强化学习方法提升医疗大语言模型推理能力的深度分析

核心概念解析 交错推理:灵活多变的思考方式 交错推理(Interleaved Reasoning)是一种在解决复杂问题时,不严格遵循单一、线性推理路径,而是交替、灵活应用多种推理策略的方法。这种思维方式与人类专家在处理复杂医疗问题时的思考模式更为接近,表现为一种动态、适应性强的…

SpringBatch+Mysql+hanlp简版智能搜索

资源条件有限&#xff0c;需要支持智搜的数据量也不大&#xff0c;上es搜索有点大材小用了&#xff0c;只好写个简版mysql的智搜&#xff0c;处理全文搜素&#xff0c;支持拼音搜索&#xff0c;中文分词&#xff0c;自定义分词断词&#xff0c;地图范围搜索&#xff0c;周边搜索…

go语言基础|slice入门

slice slice介绍 slice中文叫切片&#xff0c;是go官方提供的一个可变数组&#xff0c;是一个轻量级的数据结构&#xff0c;功能上和c的vector&#xff0c;Java的ArrayList差不多。 slice和数组是有一些区别的&#xff0c;是为了弥补数组的一些不足而诞生的数据结构。最大的…