SpringBoot+easypol前后端分离实现excel导出(保姆级教程)

news2025/1/12 0:50:35

本篇博文目录

      • 1.后端
      • 2.前端(采用axios)
      • 3.运行效果

1.后端

  • 导入easypoi的依赖
        <!--用来处理POL相关的操作:easypol-->
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-base</artifactId>
            <version>4.2.0</version>
        </dependency>
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-web</artifactId>
            <version>4.2.0</version>
        </dependency>
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-annotation</artifactId>
            <version>4.2.0</version>
        </dependency>

  • ExcelUtil.java(导入导出工具类)
package com.dudu.smartagriculture.utils;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;

/**
 * Excel导入导出工具类
 * @author pangu
 */
public class ExcelUtil {

    /**
     * 导出工具类
     * @param list
     * @param title
     * @param sheetName
     * @param pojoClass
     * @param fileName
     * @param isCreateHeader
     * @param response
     */
    public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass,
                                   String fileName, boolean isCreateHeader, HttpServletResponse response){
        ExportParams exportParams = new ExportParams(title, sheetName);
        exportParams.setCreateHeadRows(isCreateHeader);
        defaultExport(list, pojoClass, fileName, response, exportParams);
    }

    /**
     * 导出工具类
     * @param list
     * @param title
     * @param sheetName
     * @param pojoClass
     * @param fileName
     * @param response
     */
    public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass,String fileName,
                                   HttpServletResponse response){
        defaultExport(list, pojoClass, fileName, response, new ExportParams(title, sheetName));
    }

    public static void exportExcel(List<Map<String, Object>> list, String fileName, HttpServletResponse response){
        defaultExport(list, fileName, response);
    }

    private static void defaultExport(List<?> list, Class<?> pojoClass, String fileName,
                                      HttpServletResponse response, ExportParams exportParams) {
        Workbook workbook = ExcelExportUtil.exportExcel(exportParams,pojoClass,list);
        if (workbook != null); downLoadExcel(fileName, response, workbook);
    }

    private static void downLoadExcel(String fileName, HttpServletResponse response, Workbook workbook) {
        try {
            response.setCharacterEncoding("UTF-8");
            response.setHeader("content-Type", "application/vnd.ms-excel");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            workbook.write(response.getOutputStream());
        } catch (IOException e) {
            //throw new NormalException(e.getMessage());
        }
    }

    private static void defaultExport(List<Map<String, Object>> list, String fileName, HttpServletResponse response) {
        Workbook workbook = ExcelExportUtil.exportExcel(list, ExcelType.HSSF);
        if (workbook != null);
        downLoadExcel(fileName, response, workbook);
    }

    public static <T> List<T> importExcel(String filePath,Integer titleRows,Integer headerRows, Class<T> pojoClass){
        if (StringUtils.isBlank(filePath)){
            return null;
        }
        ImportParams params = new ImportParams();
        params.setTitleRows(titleRows);
        params.setHeadRows(headerRows);
        List<T> list = null;
        try {
            list = ExcelImportUtil.importExcel(new File(filePath), pojoClass, params);
        }catch (NoSuchElementException e){
            //throw new NormalException("模板不能为空");
        } catch (Exception e) {
            e.printStackTrace();
            //throw new NormalException(e.getMessage());
        } return list;
    }

    public static <T> List<T> importExcel(MultipartFile file, Integer titleRows, Integer headerRows, Class<T> pojoClass){
        if (file == null){ return null;
        }
        ImportParams params = new ImportParams();
        params.setTitleRows(titleRows);
        params.setHeadRows(headerRows);
        List<T> list = null;
        try {
            list = ExcelImportUtil.importExcel(file.getInputStream(), pojoClass, params);
        }catch (NoSuchElementException e){
            // throw new NormalException("excel文件不能为空");
        } catch (Exception e) {
            //throw new NormalException(e.getMessage());
            System.out.println(e.getMessage());
        }
        return list;
    }

}

  • 后端excel导出接口(通过get请求,/devicepolicies/exportMemberList)
    @ApiOperation(value = "导出策略列表Excel")
    @RequestMapping(value = "/exportMemberList", method = RequestMethod.GET)
    public void exportMemberList(@ApiIgnore HttpServletResponse response) {

        try {
            // 设置下载弹窗的文件名和格式(文件名要包括名字和文件格式)
            List<RulesListDto> allList = rulesService.getAllListByKeyword(null);// 获取数据
            //导出操作
            ExcelUtil.exportExcel(allList,"智慧农业监测系统策略记录","策略管理", RulesListDto.class,"智慧农业监测系统策略记录表.xlsx",response);
        } catch (Exception e) {
            LOGGER.error(e.getMessage());
        }

    }

备注:allList 为excel的数据源;"智慧农业监测系统策略记录"为title;策略管理为sheel的名字;智慧农业监测系统策略记录表.xlsx为文件名;RulesListDto.class为数据源对应的实体映射对象。

  • 之所以有/devicepolicies,是因为在该接口类上有RequestMapping

在这里插入图片描述

  • 映射实体对象,重点放在 @Excel标签上;name为列名;width为列宽;needMerge = true是否合并单元格;format为时间格式

在这里插入图片描述

  • 关于@Excel注解常用的几个参数解释:
/**
 * 购物会员
 * Created by macro on 2021/10/12.
 */
@Data
@EqualsAndHashCode(callSuper = false)
public class Member {
    @Excel(name = "ID", width = 10)
    private Long id;
    @Excel(name = "用户名", width = 20, needMerge = true)
    private String username;
    private String password;
    @Excel(name = "昵称", width = 20, needMerge = true)
    private String nickname;
    @Excel(name = "出生日期", width = 20, format = "yyyy-MM-dd")
    private Date birthday;
    @Excel(name = "手机号", width = 20, needMerge = true, desensitizationRule = "3_4")
    private String phone;
    private String icon;
    @Excel(name = "性别", width = 10, replace = {"男_0", "女_1"})
    private Integer gender;
}

在此我们就可以看到EasyPoi的核心注解@Excel,通过在对象上添加@Excel注解,可以将对象信息直接导出到Excel中去,下面对注解中的属性做个介绍;

  • name:Excel中的列名;
  • width:指定列的宽度;
  • needMerge:是否需要纵向合并单元格;
  • format:当属性为时间类型时,设置时间的导出导出格式;
  • desensitizationRule:数据脱敏处理,3_4表示只显示字符串的前3位和后4位,其他为*号;
  • replace:对属性进行替换;
  • suffix:对数据添加后缀。

备注:来源于https://cloud.tencent.com/developer/article/1895554

2.前端(采用axios)

  • 在request.js 工具类中(请求封装类)
import axios from 'axios'
import { Message, MessageBox } from 'element-ui'
import store from '../store'
import { getToken } from '@/utils/auth'

// 创建axios实例
const service = axios.create({
  // baseURL: process.env.BASE_API, // api的base_url
  baseURL:'/api',
  timeout: 15000 // 请求超时时间
})

// request拦截器
service.interceptors.request.use(config => {
  if (store.getters.token) {
    config.headers['Authorization'] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
  }
  return config
}, error => {
  // Do something with request error
  console.log(error) // for debug
  Promise.reject(error)
})

// respone拦截器
service.interceptors.response.use(
  response => {
  /**
  * code为非200是抛错 可结合自己业务进行修改
  */
    const res = response.data
    console.log(res);
    console.log(response);
    if(res.type === "application/vnd.ms-excel" && response.status === 200){// 说明是excel
      return response;
    }
    if (res.code !== 200) {
      Message({
        message: res.message,
        type: 'error',
        duration: 3 * 1000
      })

      // 401:未登录;
      if (res.code === 401) {
        MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', {
          confirmButtonText: '重新登录',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          store.dispatch('FedLogOut').then(() => {
            location.reload()// 为了重新实例化vue-router对象 避免bug
          })
        })
      }
      return Promise.reject('error')
    } else {
      return response.data
    }
  },
  error => {
    console.log('err' + error)// for debug
    Message({
      message: error.message,
      type: 'error',
      duration: 3 * 1000
    })
    return Promise.reject(error)
  }
)

export default service

  • 重点代码在这里:
 if(res.type === "application/vnd.ms-excel" && response.status === 200){// 说明是excel
      return response;
    }

之所以做该判断是因为后端接口没有像其他接口那样返回统一结果对象(接口返回结果封装对象)

在这里插入图片描述

为什么是res.type和response.status来决定是否为导出excel接口

在这里插入图片描述

  • 在api中编写再一次封装的请求函数

在这里插入图片描述
在这里插入图片描述

导出excel的request函数

export function exportMemberList(){
  return request({
    url: '/devicepolicies/exportMemberList',
    method: 'get',
    responseType: 'blob',
    header: {
      headers: {
        'Content-Type': 'application/x-download'
      }
    },
  })
}

组件代码中导入api

在这里插入图片描述

给导出按钮绑定点击事件

在这里插入图片描述

在methods中加入事件函数

, /** 导出按钮操作 */
    handleExport() {
      exportMemberList()
        .then((response) => {
          this.downloadFile(response, "智慧农业监测系统策略记录表.xlsx");
            this.$message({
              showClose: true,
              message: "导出成功",
              type: "success",
            });
        })
    },
    // 下载文件
    downloadFile(res, fileName) {
        const content = res.data;
        const blob = new Blob([content]);
        if ("download" in document.createElement("a")) {
          // 非IE下载
          const elink = document.createElement("a");
          elink.download = fileName;
          elink.style.display = "none";
          elink.href = URL.createObjectURL(blob);
          document.body.appendChild(elink);
          elink.click();
          URL.revokeObjectURL(elink.href); // 释放URL 对象
          document.body.removeChild(elink);
        } else {
          // IE10+下载
          navigator.msSaveBlob(blob, fileName);
        }
    },

3.运行效果

  • 用户点击导出

在这里插入图片描述

  • 打开下载的excel文件

在这里插入图片描述

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

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

相关文章

Cadence OrCAD: 层次化设计中的电源和地符号

Cadence OrCAD: 层次化设计中的电源和地符号 层次化设计操作步骤&#xff1a;Cadence OrCAD: 层次化设计 Hierarchical Design 本文介绍一个小问题&#xff1a;分层设计中的电源和地符号的作用范围。 电源符号默认作用范围 OrCAD中电源和地符号默认是全局的&#xff0c;也就…

2023年1月中国数据库排行榜:OceanBase 持续两月登顶,前四甲青云直上开新局

一元复始&#xff0c;万象更新。 国产数据库在经历过耕获菑畲的一年后&#xff0c;产品、生态、人才队伍建设等都取得了重大的进展。2023年1月 墨天轮中国数据库流行度排行 火热出炉&#xff0c;本月排行榜“属性”列新增“多模型”&#xff0c;榜单前十名变动较小&#xff0c;…

基于springboot,vue影院订票系统

开发工具&#xff1a;IDEA服务器&#xff1a;Tomcat9.0&#xff0c; jdk1.8项目构建&#xff1a;maven数据库&#xff1a;mysql5.7系统用户前台和管理后台两部分&#xff0c;项目采用前后端分离前端技术&#xff1a;vue elementUI服务端技术&#xff1a;springbootmybatis项目功…

JAVA开发(Netty框架与NIO)

所谓IO即input和output的缩写&#xff0c;是对数据的流入和流出的一种抽象。其中NIONIO主要有三大核心部分&#xff1a;Channel&#xff08;通道&#xff09;&#xff0c;Buffer&#xff08;缓冲区&#xff09;,Selector&#xff08;选择器&#xff09;。Channel(通道)&#xf…

Day54 跨域CORS资源JSONP回调域名接管劫持

前言&#xff1a; #知识点&#xff1a; 1、子域名接管-检测&探针&利用 2、COSP跨域资源-检测&探针&利用 3、JSONP跨域回调-检测&探针&利用 #前置知识点&#xff1a; -同源策略(SOP)-“同源”包括三个条件&#xff1a;同协议 同域名 同端口 同源策…

C/C++之(五)洛谷刷题基础题 --- 新年好

学习之路&#xff0c;长路漫漫&#xff0c;写学习笔记的过程就是把知识讲给自己听的过程。 唯有热爱&#xff0c;可抵岁月漫长&#xff0c;唯有热爱&#xff0c;不畏世间无常&#xff01; 新的一年祝你大展宏“兔” 新的一年&#xff0c;大家记得不要忘记刷题(⊙o⊙)&#xff…

NTN(四) RRC related

微信同步更新欢迎关注同名modem协议笔记。 这篇主要是与RRC层相关的内容&#xff0c;按照cell selection/re-selection->idle->connected 的顺序&#xff0c;对涉及NTN的内容进行总结。首先看下NTN RF相关的内容&#xff0c;这部分对应38.101-5这本spec。 NTN freq inf…

操作系统面试题(史上最全、持续更新)

尼恩面试宝典专题40&#xff1a;操作系统面试题&#xff08;史上最全、持续更新&#xff09; 本文版本说明&#xff1a;V28 《尼恩面试宝典》升级规划为&#xff1a; 后续基本上&#xff0c;每一个月&#xff0c;都会发布一次&#xff0c;最新版本&#xff0c;可以联系构师尼…

一个高效的通用光学卫星数据正射校正程序

李国春 随着高分辨率对地观测卫星发射的日益增多&#xff0c;对数据处理软件的要求也越来越高。通常每个系列卫星都有自己的数据特点并需要专门的处理软件&#xff0c;但卫星数量的增加为每种卫星单独设计软件的压力越来越大。本文介绍的一种处理方案旨在能够正射校正处理大多…

矩阵形状的读取和改变ndarray.shape()方法

【小白从小学Python、C、Java】【计算机等级考试500强双证书】【Python-数据分析】矩阵形状的读取和改变ndarray.shape()方法[太阳]选择题以下说法正确的是&#xff1a;import numpy as np a np.array([[1,2,3],[4,5,6]])print("【显示】a\n",a)print("【显示】…

【第十六篇】Camunda系列-动态表单

动态表单 接下来我们看看动态表单的应用,在Camunda中表单分为内置表单和动态表单。 1.内置表单 内置表单就是在绘制流程图的时候同时绘制表单。这种方式其实就是绑定了对应的流程变量,不是太灵活。但还是来讲解下。 1.1 启动流程绑定 我们先来看下在启动流程的时候就设置相…

点击化学Alkynyl Myristic COOH,82909-47-5,13-十四炔酸

基础产品数据&#xff08;Basic Product Data&#xff09;&#xff1a;CAS号&#xff1a;82909-47-5中文名&#xff1a;炔基-肉豆蔻酸&#xff0c;13-十四炔酸英文名&#xff1a;Alkynyl Myristic Acid&#xff0c;Alkynyl Myristic COOH试剂基团反应特点&#xff08;Reagent g…

c++模板,选择排序,字符数组,字符串

目录 1.模板 1.1模板概念 1.2.函数模板 1.2.1函数模板语法&#xff0c;函数模板的调用--1.自动类型推导&#xff0c;2.显示指定类型 1.2.2函数模板注意事项 ​编辑 1.2.3函数模板的案例&#xff0c;选择排序&#xff0c;字符数组&#xff0c;字符串 1.2.4普通函数与函数…

C语言中的回调函数 和 函数指针

以冒泡排序为例&#xff1a; void sort(int *a, int size) {int i, j;for (i 0; i < size-1; i){for (j 0; j < size - i - 1; j){if (a[j] > a[j1]){int num a[j];a[j] a[j1];a[j1] num;}}}}int main(){int arr[9] {1,2,3,4,5,6,7,8,9};sort(arr, 9); // sort…

列表元素的最大值,最小值,出现的次数和列表长度

1 获取列表中的最大元素和最小元素&#xff1a; 使用max和min可以分别获取一个列表中最大元素和最小元素的值&#xff0c;其语法格式为&#xff1a; max(list) 和min(list) 例&#xff1a;ls[12,34,56,87]#创建列表并赋给ls print(ls中最大元素值为&#xff1a;max(ls))#输出…

JDY-10M BLE组网模块介绍

JDY-10M BLE组网模块简介JDY-10透传模块是基于蓝牙4.0协议标准&#xff0c;工作频段为2.4GHZ范围&#xff0c;调制方式为GFSK&#xff0c;最大发射功率为8db&#xff0c;最大发射距离50米&#xff0c;具有功耗低、尺寸小、信号强、数据传输稳定等特性。JDY-10M BLE组网模块特征…

DM8:达梦数据库DEM部署说明(详细步骤)

DM8:达梦数据库DEM部署说明&#xff08;详细步骤&#xff09;1 创建一个数据库作为DEM后台数据库, 数据库dm.ini参数配置进行优化, 推荐配置:1.1 在该数据库中执行DEM的SQL脚本2 配置tomcat2.1 配置/tomcat/conf/server.xml2.2 修改jvm启动参数3 配置JAVA 1.8及以上版本的运行时…

潜力出众应该具有的特质

前言 先说一下背景&#xff0c;最近在以面试官的角色面试候选人的过程中&#xff0c;一直在思考一个问题&#xff1a;“如何判断一个候选人是否有潜力&#xff0c;是否适合这个岗位&#xff0c;入职后是否能能快速成长&#xff0c;成为独挡一面的人&#xff0c;一个有潜力的人…

手撕Pytorch源码#1.Dataset类 part1

写在前面手撕Pytorch源码系列目的&#xff1a;通过手撕源码复习了解高级python语法熟悉对pytorch框架的掌握在每一类完成源码分析后&#xff0c;会与常规深度学习训练脚本进行对照本系列预计先手撕python层源码&#xff0c;再进一步手撕c源码版本信息python&#xff1a;3.6.13p…

PHP MySQL 插入多条数据

使用 MySQLi 和 PDO 向 MySQL 插入多条数据 mysqli_multi_query() 函数可用来执行多条SQL语句。 以下实例向 "MyGuests" 表添加了三条新的记录: 实例 (MySQLi - 面向对象) <?php $servername "localhost"; $username "username"; $pas…