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

全部导出

批量导出

报错问题分析

经过排查,原因是因为在发起 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);
  }

},
相关推荐
2401_854391083 分钟前
Spring Boot大学生就业招聘系统的开发与部署
java·spring boot·后端
杨荧30 分钟前
【JAVA开源】基于Vue和SpringBoot的洗衣店订单管理系统
java·开发语言·vue.js·spring boot·spring cloud·开源
2401_8576100340 分钟前
SpringBoot实现:校园资料分享平台开发指南
服务器·spring boot·php
这孩子叫逆1 小时前
Spring Boot项目的创建与使用
java·spring boot·后端
Jay_fearless2 小时前
Redis SpringBoot项目学习
spring boot·redis
罗曼蒂克在消亡2 小时前
2.3MyBatis——插件机制
java·mybatis·源码学习
coderWangbuer2 小时前
基于springboot的高校招生系统(含源码+sql+视频导入教程+文档+PPT)
spring boot·后端·sql
Kenny.志2 小时前
2、Spring Boot 3.x 集成 Feign
java·spring boot·后端
sky丶Mamba3 小时前
Spring Boot中获取application.yml中属性的几种方式
java·spring boot·后端
千里码aicood4 小时前
【2025】springboot教学评价管理系统(源码+文档+调试+答疑)
java·spring boot·后端·教学管理系统