springboot+vue2+elementui+mybatis- 批量导出导入

news2024/11/27 4:35:31

全部导出

批量导出

报错问题分析

经过排查,原因是因为在发起 axios 请求的时候,没有指定响应的数据类型(这里需要指定响应的数据类型为 blob 二进制文件)

当响应数据回来后,会执行 axios 后置拦截器的代码,因为没有对响应头的类型进行判断,而是判断为字符串 String,将该流转为 JSON 对象而报错

导出的 思路分析:

1. 得到用户选中的 ids 数组(前端 vue)

2. 请求导出的后台接口

3. 根据 id,从数据库中查询记录(springboot)

4.拿到数据之后,使用流的方式,响应给浏览器/客户端

Vue2+Elementui

1.新增导出按钮

<el-button type="primary" @click="exportUsers">批量导出</el-button>

2.将选择的 ids 集合当作参数提交给后端 springboot

    //导出
    exportUsers() {//如果没有选择行数据,则全部导出或者按照检索条件导出

      this.$confirm("您是否需要导出?", "提示", {
        iconClass: "el-icon-question",//自定义图标样式
        confirmButtonText: "确认",//确认按钮文字更换
        cancelButtonText: "取消",//取消按钮文字更换
        showClose: true,//是否显示右上角关闭按钮
        type: "warning",//提示类型  success/info/warning/error
      }).then(() => {
        //确认操作
        //请求批量导出的接口
        this.$request.get('/user/exportUsersById', {
          params: { //ids携带过去,
            ids: this.ids //存的是勾选的id的数组
          },
          responseType: 'blob', // 设置响应类型为blob(响应的数据是二进制文件)
          paramsSerializer: params => {//get方法,传的参数的是数组解决uri的路径问题 ?ids[]=225&ids[]=226
            return qs.stringify(params, {indices: false})
          }
        }).then(response => {
          // console.log("response=", response)
          if (response.size > 0) {//返回的是blob,判断文件的大小

            this.$message.success("导出成功");
          } else {
            this.$message.warning("导出失败");
          }
        })
      }).catch(() => {
        //取消操作
      });
    },

3.在 axios 后置拦截器中将 blob 二进制文件转为 excel

import axios from 'axios'
import router from "@/router";
import {saveAs} from 'file-saver';//导入该依赖

// response 拦截器
// 可以在接口响应后统一处理结果
request.interceptors.response.use(response => {
    //简化.data操作 直接使用res.data就能得到数据
    let res = response.data;
    console.log("res=", res)


    // 判断是否为二进制数据
    if (response.config.responseType === 'blob') {
        console.log("该文件是二进制文件")
        // 从响应头中获取文件名
        const contentDisposition = response.headers.get('Content-Disposition');
        const filenameRegex = /filename=(.+)/
        const fileNameMatch = contentDisposition && contentDisposition.match(filenameRegex);
        const fileName = fileNameMatch && fileNameMatch[1];
        // 对文件名进行解码,换原成原始文件名
        const decodedFileName = decodeURIComponent(fileName);
        // 对文件名进行解码,换原成原始文件名
        // const decodedFileName = decodeURIComponent(fileName);
        // 使用FileSaver库保存文件
        const blob = new Blob([response.data], {type: response.headers['content-type']});
        // saveAs(blob, 'file.xlsx');
        saveAs(blob, decodedFileName || 'file.xlsx');
    }
    // // 兼容服务端返回的字符串数据
    //  if (typeof res === 'string') {
    //      res = res ? JSON.parse(res) : res
    //  }
    // //返回接口的状态码401,返回登录页面
    // if (res.code === '401') {
    //     router.push('/login')
    // }
    return res;
}, error => {
    console.error('response error: ' + error) // for debug
    return Promise.reject(error)
})

SpringBoot

导入 maven 依赖

<dependency>
  <groupId>org.apache.poi</groupId>
  <artifactId>poi-ooxml</artifactId>
  <version>4.1.2</version>
</dependency>
@RequestMapping("/exportUsersById")
public void exportUsersById(@RequestParam(value = "ids", required = false) List<Integer> ids, HttpServletResponse response) {
    log.info("idList=" + ids);
    List<User> userList;// 用户数据集合
    String fileName = "";// 文件名

    if (ObjectUtil.isEmpty(ids) || ids.contains(-1)) {// 全部导出
        userList = UserServiceImpls.list();
        fileName = "所有用户";
        log.info("所有用户=" + userList);
        if (ObjectUtil.isEmpty(userList)) { // 列表为空
            throw new BizException("用户列表为空");
        }
    } else {
        userList = UserServiceImpls.listByIds(ids);// 批量导出
        fileName = "部分用户";
        log.info("部分用户=" + userList);
    }

    // 使用huTools工具类-Excel导出
    ExcelWriter writer = ExcelUtil.getWriter(true);
    writer.write(userList, true);

    response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
    try {
        // 将Content-Disposition暴露,前端才能得到Content-Disposition的value值
        response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf-8") + ".xlsx");
        writer.flush(response.getOutputStream(), true);
    } catch (IOException e) {
        // e.printStackTrace();
    } finally {
        writer.close();
    }
}

批量导入

<el-upload
  style="display: inline-block"
  action="http://localhost:9000/user/importData"
  :headers="{token:loginUSer.token}"
  :show-file-list="false"
  :on-success="handleFileSuccess">
  <el-button type="success" class="my-button">批量导入</el-button>
</el-upload>
/**
     * 导入数据
     *
     * @param file:
     * @return ResultResponse<String>
     * @author "卒迹"
     * @description TODO
     * @date 17:32
     */

@PostMapping("/importData")
public ResultResponse<String> importData(MultipartFile file) throws IOException {
    // 写入文件流
    ExcelReader reader = ExcelUtil.getReader(file.getInputStream());
    // 以User类的格式导入数据-返回1个集合对象,这里取决于alias注解
    List<User> userList = reader.readAll(User.class);
    if (ObjectUtil.isEmpty(userList)) {// 导入的数据为空
        return ResultResponse.error("导入失败");
    }
    // 写入数据到数据库
    boolean isSave = false;
    try {
        isSave = UserServiceImpls.saveBatch(userList);
    } catch (Exception e) {
        // e.printStackTrace();
        return ResultResponse.error("导入出错");
    }
    return isSave ? ResultResponse.success("导入成功") : ResultResponse.error("导入失败");
}
//导入
handleFileSuccess(response, file, fileList) {
  console.log("response=", response)
  if (response.code === "2000") {
    this.$message.success(response.message);
    //刷新数据
    this.queryUserByUsernameOrName(this.isDisplayMsg = false, 1)
  }
  if (response.code === "-1") {
    this.$message.error(response.message);
  }

},

 

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

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

相关文章

Ubuntu22.04搭建CLion C++开发环境

Ubuntu22.04搭建CLion C开发环境 文章目录 Ubuntu22.04搭建CLion C开发环境1.首先下载CLion2.配置c环境3.创建快捷方式Reference 1.首先下载CLion 进入官网https://www.jetbrains.com/clion/download/#sectionlinux 然后进入自己存放这个压缩包的路径中&#xff0c; sudo mkd…

单调栈用法

文章目录 1. 单调栈1.1 理解单调栈&#xff08;模板&#xff09;1.2 每日温度1.3 子数组的最小值之和1.4 柱状图中最大的矩形1.5 最大矩形1.6 最大宽度坡1.7 去除重复字母 1. 单调栈 单调栈经典的用法&#xff1a; 对每个位置都求&#xff1a; 当前位置的左侧比当前位置的数…

电商技术揭秘22:智能仓储与物流优化(上)

相关系列文章 电商技术揭秘一&#xff1a;电商架构设计与核心技术 电商技术揭秘二&#xff1a;电商平台推荐系统的实现与优化 电商技术揭秘三&#xff1a;电商平台的支付与结算系统 电商技术揭秘四&#xff1a;电商平台的物流管理系统 电商技术揭秘五&#xff1a;电商平台…

【Java8新特性】二、函数式接口

这里写自定义目录标题 一、什么是函数式接口二、自定义函数式接口三、作为参数传递 Lambda 表达式四、四大内置核心函数式接口1、消费形接口2、供给形接口3、函数型接口4、断言形接口 一、什么是函数式接口 只包含一个抽象方法的接口&#xff0c;称为函数式接口。你可以通过 L…

php其他反序列化知识学习

简单总结一下最近学习的&#xff0c;php其他的一些反序列化知识 phar soap session 其他 __wakeup绕过gc绕过异常非公有属性&#xff0c;类名大小写不敏感正则匹配&#xff0c;十六进制绕过关键字检测原生类的利用 phar 基础知识 在 之前学习的反序列化利用中&#xff0…

CentOS 网卡ifcfg-eth0 ping不通外网(www.baidu.com)

1、如果确认好就直接激活网卡&#xff01; ifup eth0 2、慢慢找&#xff1a; cd /etc/sysconfig/network-scripts/ ls 找到你的网卡是啥&#xff0c;这里网卡是 ifcfg-eth0 执行1就好了&#xff01;

基于ssm会员卡管理系统的设计与实现论文

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本会员卡管理系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信息&…

自媒体ai写作成长之路:8款工具助力你飞得更高! #学习#科技#科技

在当今信息爆炸的时代&#xff0c;写作成为了人们表达思想、分享知识和传递情感的重要方式之一。对于很多人来说&#xff0c;写作并非易事。我们会陷入困境&#xff0c;无法找到灵感&#xff0c;我们会苦恼于语言表达的准确性&#xff0c;还有时候我们可能遭遇到了创作瓶颈&…

未来汽车硬件安全的需求(2)

目录 4.汽车安全控制器 4.1 TPM2.0 4.2 安全控制器的硬件保护措施 5. EVITA HSM和安全控制器结合 6.小结 4.汽车安全控制器 汽车安全控制器是用于汽车工业安全关键应用的微控制器。 他们的保护水平远远高于EVITA HSM。今天的典型应用是移动通信&#xff0c;V2X、SOTA、…

Ubuntu日常配置

目录 修改网络配置 xshell连不上怎么办 解析域名失败 永久修改DNS方法 临时修改DNS方法 修改网络配置 1、先ifconfig确认本机IP地址&#xff08;刚装的机子没有ifconfig&#xff0c;先apt install net-tools&#xff09; 2、22.04版本的ubuntu网络配置在netplan目录下&…

C++ 类和对象 上

目录 前言 什么是面向对象&#xff1f;什么是面向过程&#xff1f; 面向过程 面向对象 比较 类 引入 定义 实例化 类的大小 this指针 前言 今天我们来进入C类和对象的学习。相信大家一定听说过C语言是面向过程的语言&#xff0c;而C是面向对象的语言&#xff1f;那么他…

[当人工智能遇上安全] 13.威胁情报实体识别 (3)利用keras构建CNN-BiLSTM-ATT-CRF实体识别模型

《当人工智能遇上安全》系列将详细介绍人工智能与安全相关的论文、实践&#xff0c;并分享各种案例&#xff0c;涉及恶意代码检测、恶意请求识别、入侵检测、对抗样本等等。只想更好地帮助初学者&#xff0c;更加成体系的分享新知识。该系列文章会更加聚焦&#xff0c;更加学术…

微信小程序全屏开屏广告

效果图 代码 <template><view><!-- 自定义头部 --><u-navbar title" " :bgColor"bgColor"><view class"u-nav-slot" slot"left"><view class"leftCon"><view class"countDown…

2024-简单点-观察者模式

先看代码&#xff1a; # 导入未来模块以支持类型注解 from __future__ import annotations# 导入抽象基类模块和随机数生成器 from abc import ABC, abstractmethod from random import randrange# 导入列表类型注解 from typing import List# 定义观察者模式中的主体接口&…

Rocky(Centos)数据库等高并发或高io应用linux系统调优,及硬件问题排查(含网络、磁盘、系统监控)

一、系统参数优化 默认的最大打开文件数是1024.不满足生产环境的要求。按照如下配置&#xff1a; 1、修改 systemctl管理的 servie 资源限制 编辑/etc/systemd/system.conf # 全局的打开文件数 DefaultLimitNOFILE2097152 # 全局打开进程数 DefaultLimitNPROC655352、调整系…

【Vue3 + ElementUI】表单校验无效(写法:this.$refs[‘formName‘].validate((valid) =>{} ))

一. 表单校验 1.1 template模块 el-form 中 若校验&#xff0c;ref 和 rules 必须要有 <template><div style"padding:20px"><el-form ref"formName" :model"form" :rules"formRules" label-width"120px"…

Docker 学习笔记(七):介绍 Dockerfile 相关知识,使用 Dockerfile 构建自己的 centos 镜像

一、前言 记录时间 [2024-4-12] 系列文章简摘&#xff1a; Docker学习笔记&#xff08;二&#xff09;&#xff1a;在Linux中部署Docker&#xff08;Centos7下安装docker、环境配置&#xff0c;以及镜像简单使用&#xff09; Docker 学习笔记&#xff08;三&#xff09;&#x…

LDF、DBC、BIN、HEX、S19、BLF、ARXML、slx等

文章目录 如题 如题 LDF是LIN报文格式文件&#xff0c;把这个直接拖到软件里面&#xff0c;可以发报文和接收报文 DBC是CAN报文格式文件&#xff0c;把这个直接拖到软件里面&#xff0c;可以发报文和接收报文 BIN文件烧录在BOOT里面&#xff08;stm32&#xff09;&#xff0c…

适用于 Windows 的 10 个免费数据恢复工具集合

有时&#xff0c;我们都会在个人计算机上意外删除一些重要文件或数据。我们无需再担心此类问题&#xff0c;因为我们可以借助互联网上提供的免费数据恢复工具来恢复宝贵的数据和图像。 互联网上有许多免费的数据恢复工具&#xff0c;从一长串工具中&#xff0c;我们列出了最好…

蓝桥杯-STL-string

目录 字符串定义 字符串初始化 字符串输入输出 字符串输出 字符串输入 字符串访问 字符串拷贝 字符串拼接 直接相加 append(const char*str,int n) 字符串比较 ​编辑字符串长度length()/size() 字符串查找find(string str) 查找子串substr(int a,int b) 字符串的…