vue springboot利用easypoi实现简单导出


前言

今天玩了一下vue springboot利用easypoi实现excel的导出,以前没玩过导入导出,只不过听说过看别人用过,怎么说呢,想玩就玩一下吧,毕竟结合自己业务场景需要才会考虑是否使用。先简单介绍一下easypoi。


一、easypoi是什么?

1.不太熟悉poi的
2.不想写太多重复太多的
3.只是简单的导入导出的
4.喜欢使用模板的

若poi都不知道的童鞋请自行百度。。。

Easypoi的目标不是替代poi,而是让一个不懂导入导出的快速使用poi完成Excel和word的各种操作,而不是看很多api才可以完成这样工作。

二、使用步骤

1.传送门

因为我也是第一次使用,这里还是先将easypoi的官方文档放这儿吧:

点我查看Easypoi官方文档

2.前端vue

咋先从前端开始吧,总要一步步来嘛,下面看代码(仔细看注释):

<template>
  <div>
    <!-- 这里只演示导出,导入也差不多 -->
    <!-- <el-button class="el-icon-upload" type="success">导入</el-button> -->
    <el-button class="el-icon-download" type="success" @click="exportExcel()">导出</el-button>
  </div>
</template>
<script>
export default {
  name: "importandexport",
  data() {
    return {
      extp: this.exportExceltype,
    };
  },
  props: ["exportExceltype"],//父组件向子传递过来的值,用于判断是那个组件过来的
  methods: {
    exportExcel() {
      const extpurl = ""; //导出请求地址
      //这里就是判断来自哪个父组件,从而发送不同的请求路径
      if (this.extp == "user") {
        this.extpurl = "/exportUser";
      } else if (this.extp == "role") {
        this.extpurl = "/exportRole";
      }

      this.$axios
        .get(this.extpurl, { responseType: "blob" })
        .then((res) => {
          const blob = new Blob([res.data], { //取响应回来的数据
            type: "application/vnd.ms-excel;charset=utf-8",
          });
          const href = window.URL.createObjectURL(blob); // 创建下载的链接
          const downloadElement = document.createElement("a");
          downloadElement.href = href;
          downloadElement.download = decodeURI(res.headers["filename"]);
          document.body.appendChild(downloadElement);
          downloadElement.click(); // 点击下载
          document.body.removeChild(downloadElement); // 下载完成移除元素
          window.URL.revokeObjectURL(href); // 释放掉blob对象
        })
        .catch((fail) => {
          console.error(fail);
        });
    },
  },
};
</script>
<style scoped>
</style>

上面的是公用的子组件,还缺少父组件,看下面代码:

<template>
  <div>
    <el-row style="margin: 18px 0px 0px 18px ">
      <el-breadcrumb separator-class="el-icon-arrow-right">
        <el-breadcrumb-item :to="{ path: '/admin/dashboard' }"
          >管理中心</el-breadcrumb-item
        >
        <el-breadcrumb-item>用户管理</el-breadcrumb-item>
        <el-breadcrumb-item>用户信息</el-breadcrumb-item>
      </el-breadcrumb>
    </el-row>
    <bulk-registration @onSubmit="listUsers()"></bulk-registration>
    <el-card style="margin: 18px 2%;width: 95%">
      <el-table
        v-loading="loading"
        :data="users.slice((currentPage-1)*pageSize,currentPage*pageSize)"
        stripe
        :default-sort="{ prop: 'id', order: 'ascending' }"
        style="width: 100%"
        :max-height="tableHeight"
      >
        <el-table-column type="selection" width="55"> </el-table-column>
        <el-table-column prop="id" label="id" sortable width="100">
        </el-table-column>
        <el-table-column prop="username" label="用户名" fit> </el-table-column>
        <el-table-column prop="name" label="真实姓名" fit> </el-table-column>
        <el-table-column prop="phone" label="手机号" fit> </el-table-column>
        <el-table-column prop="email" label="邮箱" show-overflow-tooltip fit>
        </el-table-column>
        <el-table-column label="状态" sortable width="100">
          <template slot-scope="scope">
            <el-switch
              v-model="scope.row.enabled"
              active-color="#13ce66"
              inactive-color="#ff4949"
              @change="value => commitStatusChange(value, scope.row)"
            >
            </el-switch>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="120">
          <template slot-scope="scope">
            <el-button @click="editUser(scope.row)" type="text" size="small">
              编辑
            </el-button>
            <el-button @click="delUser(scope.row)" type="text" size="small">
              移除
            </el-button>
          </template>
        </el-table-column>
      </el-table>
       <el-pagination
          layout="total, prev, pager, next, jumper"
          @current-change="handleCurrentChange"
          :page-size="pageSize"
          :current-page="currentPage"
          :total="total">
        </el-pagination>
    </el-card>
    
    < !--放入组件,如不知道父组件如何向子组件传值的,也可以好好看看
     :exportExceltype 指子组件中的 props: ["exportExceltype"]
     excelobj 则就是当前父组件中的data里面的属性,并指定了固定值-->
     
    <ImportAndExport :exportExceltype="excelobj"></ImportAndExport>
    
  </div>
</template>

<script>
//导入导出excel
import ImportAndExport from '@/components/common/ImportAndExport'
export default {
  name: "UserProfile",
  components: { ImportAndExport },
  data() {
    return {
      excelobj:'user',//指定当前组件导入导出的标识,传入子组件即导入导出组件中判断
    };
  },
 
};
</script>

<style scoped></style>

这里我只保留了需要的代码,其他代码无关紧要,详细看注释,很简单的东西我也写得很详细了。。。
至此,前端部分已经完成,现在我讲一下导出思路:由前端通过判断不同页面需要导出的请求路径,然后通过设置请求方式、参数。像后端发起请求,后端通过easypoi的工具方法、注解。生成需要的excel或者word文档,然后给前端响应返回。前端再进行接收处理,并进行下载。
如果是,实现导入的话,思路也一样,只不过后端处理稍微变化了。(实质上也就是将数据库的数据组成list或者map然后交给easypoi处理)。

3.后端springboot

首先引入easypoi所需依赖:

       <!--easypoi导入导出-->
		<dependency>
			<groupId>cn.afterturn</groupId>
			<artifactId>easypoi-base</artifactId>
			<version>4.1.3</version>
		</dependency>
		<dependency>
			<groupId>cn.afterturn</groupId>
			<artifactId>easypoi-web</artifactId>
			<version>4.1.3</version>
		</dependency>
		<dependency>
			<groupId>cn.afterturn</groupId>
			<artifactId>easypoi-annotation</artifactId>
			<version>4.1.3</version>
		</dependency>

或者使用这个:

<dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-spring-boot-starter</artifactId>
    <version>4.0.0</version>
</dependency>

3.1编写实体类(我这里是dto,也一样)

package top.wangxingjun.separate.dto;

import cn.afterturn.easypoi.excel.annotation.Excel;
import top.wangxingjun.separate.dto.base.OutputConverter;
import top.wangxingjun.separate.entity.AdminRole;
import top.wangxingjun.separate.entity.User;
import lombok.Data;
import lombok.ToString;

import java.util.List;

/**
 * @author wxj
 * @Date 2020/8/10
 */
@Data
@ToString
public class UserDTO implements OutputConverter<UserDTO, User> {

    @Excel(name = "编号")
    private int id;

    @Excel(name = "账号")
    private String username;

    @Excel(name = "真实姓名")
    private String name;

    @Excel(name = "手机号")
    private String phone;

    @Excel(name = "邮箱")
    private String email;

    @Excel(name = "状态",replace = {"启用_true","禁用_false"})
    private boolean enabled;

}

这里使用了 @Excel 是关键注解,必不可少,name表示指定生成的excel的对应列明,replace 则表示用来做转换的,如:数据库表的性别字段,数据库字段值使用0或1表示,而前台需要显示男或女,导出的话,格式是 replace = {“前台显示值_数据库字段值”,“前台显示值_数据库字段值”} 用 _ 隔开。如果是导出,把前台显示值与数据库字段值调换下位置就可以了~更多用法请求官方文档查看或者百度使用。

3.2控制层

直接看代码:

    /**
     * 用户信息导出
     */
    @GetMapping("api/exportUser")
    public void exportUser(HttpServletResponse response) throws Exception {
        List<UserDTO> list = userService.list();
        ExcelUtil.exportExcel(list, null, "sheet1", UserDTO.class, "用户信息", response);
    }

没错,就这么几行代码,当然了,还要有个工具类,是我封装好的,网上也有很多的咯。下面看工具类:

 package top.wangxingjun.separate.util;

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 lombok.extern.log4j.Log4j2;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
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.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;

/**
 * @ProjectName: separate
 * @Package: top.wangxingjun.separate.util
 * @ClassName: ExcelUtil
 * @Author: wxj
 * @Description: Excel导入导出工具类
 * @Date: 2020/8/25 10:07
 * @Version: 1.0
 */
@Log4j2
public class ExcelUtil {
    /**
     * Map集合导出
     *
     * @param list     需要导出的数据
     * @param fileName 导出的文件名
     * @param response HttpServletResponse对象
     */
    public static void exportExcel(List<Map<String, Object>> list, String fileName, HttpServletResponse response) throws Exception{
        defaultExport(list, fileName, response);
    }

    /**
     * 复杂导出Excel,包括文件名以及表名(不创建表头)
     *
     * @param list      需要导出的数据
     * @param title     表格首行标题(不需要就传null)
     * @param sheetName 工作表名称
     * @param pojoClass 映射的实体类
     * @param fileName  导出的文件名(如果为null,则默认文件名为当前时间戳)
     * @param response  HttpServletResponse对象
     */
    public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass, String fileName,
                                   HttpServletResponse response) throws Exception{
        defaultExport(list, pojoClass, fileName, response, new ExportParams(title, sheetName));
    }

    /**
     * 复杂导出Excel,包括文件名以及表名(创建表头)
     *
     * @param list           需要导出的数据
     * @param title          表格首行标题(不需要就传null)
     * @param sheetName      工作表名称
     * @param pojoClass      映射的实体类
     * @param fileName       导出的文件名
     * @param isCreateHeader 是否创建表头
     * @param response       HttpServletResponse对象
     */
    public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass, String fileName,
                                   boolean isCreateHeader, HttpServletResponse response) throws Exception{
        ExportParams exportParams = new ExportParams(title, sheetName);
        exportParams.setCreateHeadRows(isCreateHeader);
        defaultExport(list, pojoClass, fileName, response, exportParams);
    }

    /**
     * 默认导出方法
     *
     * @param list         需要导出的数据
     * @param pojoClass    对应的实体类
     * @param fileName     导出的文件名
     * @param response     HttpServletResponse对象
     * @param exportParams 导出参数实体
     */
    private static void defaultExport(List<?> list, Class<?> pojoClass, String fileName, HttpServletResponse response,
                                      ExportParams exportParams) throws Exception{
        Workbook workbook = ExcelExportUtil.exportExcel(exportParams, pojoClass, list);
        downloadExcel(fileName, workbook, response);
    }

    /**
     * 默认导出方法
     *
     * @param list     Map集合
     * @param fileName 导出的文件名
     * @param response HttpServletResponse对象
     */
    private static void defaultExport(List<Map<String, Object>> list, String fileName, HttpServletResponse response)throws Exception {
        Workbook workbook = ExcelExportUtil.exportExcel(list, ExcelType.HSSF);
        if (null != workbook) {
            downloadExcel(fileName, workbook, response);
        }
    }

    /**
     * Excel导出
     *
     * @param fileName Excel导出
     * @param workbook Excel对象
     * @param response HttpServletResponse对象
     */
    public static void downloadExcel(String fileName, Workbook workbook, HttpServletResponse response) throws Exception{
        try {
            if (StringUtils.isEmpty(fileName)) {
                throw new RuntimeException("导出文件名不能为空");
            }
            String encodeFileName = URLEncoder.encode(fileName, "UTF-8");
            response.setHeader("content-Type", "application/vnd.ms-excel; charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + encodeFileName);
            response.setHeader("FileName", encodeFileName);
            response.setHeader("Access-Control-Expose-Headers", "FileName");
            workbook.write(response.getOutputStream());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 根据文件路径来导入Excel
     *
     * @param filePath   文件路径
     * @param titleRows  表标题的行数
     * @param headerRows 表头行数
     * @param pojoClass  映射的实体类
     * @return
     */
    public static <T> List<T> importExcel(String filePath, Integer titleRows, Integer headerRows, Class<T> pojoClass) throws Exception{
        //判断文件是否存在
        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) {
            log.error("模板不能为空", e);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return list;
    }

    /**
     * 根据接收的Excel文件来导入Excel,并封装成实体类
     *
     * @param file       上传的文件
     * @param titleRows  表标题的行数
     * @param headerRows 表头行数
     * @param pojoClass  映射的实体类
     * @return
     */
    public static <T> List<T> importExcel(MultipartFile file, Integer titleRows, Integer headerRows, Class<T> pojoClass) throws Exception{
        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) {
            log.error("excel文件不能为空", e);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return list;
    }

    /**
     * 文件转List
     *
     * @param file
     * @param pojoClass
     * @param <T>
     * @return
     */
    public static <T> List<T> fileToList(MultipartFile file, Class<T> pojoClass) throws Exception{
        if (file.isEmpty()) {
            throw new RuntimeException("文件为空");
        }
        List<T> list = ExcelUtil.importExcel(file, 1, 1, pojoClass);
        if (CollectionUtils.isEmpty(list)) {
            throw new RuntimeException("未解析到表格数据");
        }
        return list;
    }
}

excel导出所需要的都准备好了,下面来看一下我的效果:

这不就很完美了嘛

结尾

好了今天的分享就到这里了,结束~~

posted @ 2020-08-25 18:23  辰鬼  阅读(800)  评论(0编辑  收藏  举报