zoukankan      html  css  js  c++  java
  • 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%; 95%">
          <el-table
            v-loading="loading"
            :data="users.slice((currentPage-1)*pageSize,currentPage*pageSize)"
            stripe
            :default-sort="{ prop: 'id', order: 'ascending' }"
            style=" 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导出所需要的都准备好了,下面来看一下我的效果:

    这不就很完美了嘛

    结尾

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

    辰鬼丫
  • 相关阅读:
    表白利器,马赛克拼贴照片制作
    听说国漫最近崛起了,那我们就来爬几部国漫看看(动态加载,反爬)
    python爬虫--看看虎牙女主播中谁最“顶”
    “花小猪”,滴滴搬起石头砸自己的脚?
    Linux命令学习之awk
    《Redis深度历险》集群篇、拓展篇
    《Redis深度历险》原理篇
    《Redis深度历险》应用篇
    《鸟哥的Linux私房菜 基础篇》下
    Git使用
  • 原文地址:https://www.cnblogs.com/Acechengui/p/13635462.html
Copyright © 2011-2022 走看看