若依管理系统前后端分离版基于ElementUI和SpringBoot怎样实现Excel导入和导出

时间:2024-04-16 18:34:05

场景

使用若依前后端分离版实现Excel的导入和导出。

前端:Vue+ElementUI

后端:SpringBoot+POI+Mysql

注:

博客:
https://blog.****.net/badao_liumang_qizhi
关注公众号
霸道的程序猿
获取编程相关电子书、教程推送与免费下载。

实现

Excel导入

点击导入按钮时的效果

 

 

选中Excel后

 

 

首先是前端页面,添加导入的dialog

    <el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
      <el-upload
        ref="upload"
        :limit="1"
        accept=".xlsx, .xls"
        :headers="upload.headers"
        :action="upload.url"
        :disabled="upload.isUploading"
        :on-progress="handleFileUploadProgress"
        :on-success="handleFileSuccess"
        :auto-upload="false"
        :data="{updateSupport:upload.updateSupport}"
        drag
      >
        <i class="el-icon-upload"></i>
        <div class="el-upload__text">
          将文件拖到此处,或
          <em>点击上传</em>
        </div>
        <div class="el-upload__tip" slot="tip">
          <el-checkbox v-model="upload.updateSupport" />是否更新已经存在的下井次数设置数据
          <el-link
            type="info"
            style="font-size:12px"
            @click="downloadTemplate(\'xjszTemplate.xlsx\')"
          >下载模板</el-link>
        </div>
        <div
          class="el-upload__tip"
          style="color:red"
          slot="tip"
        >提示:仅允许导入“xls”或“xlsx”格式文件!是否全勤中:1代表全勤,0代表固定次数,不得有空值!!</div>
      </el-upload>

      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitFileForm">确 定</el-button>
        <el-button @click="upload.open = false">取 消</el-button>
      </div>
    </el-dialog>

通过:visible.sync="upload.open"控制默认隐藏,其中upload是声明的用于存储上传相关的参数的model

需要声明它

export default {
  name: "Xjcssz",
  data() {
    return {
      // 导入参数
      upload: {
        // 是否显示弹出层
        open: false,
        // 弹出层标题
        title: "",
        // 是否禁用上传
        isUploading: false,
        // 是否更新已经存在的数据
        updateSupport: 0,
        // 设置上传的请求头部
        headers: { Authorization: "Bearer " + getToken() },
        // 上传的地址
        url: process.env.VUE_APP_BASE_API + "/kqgl/xjcssz/importData",
      },

这里的getToken()是从auth中引入

import { getToken } from "@/utils/auth";

是要获取登录的token

export function getToken() {
  return Cookies.get(TokenKey)
}

文件上传组件使用的是e-upload组件,设置其一些属性

limit限制只能选择一个文件

accept限制能选择的文件类型

headers设置请求头携带token

action设置上传请求的url

disabled设置正在上传时禁用

on-progress设置正在上传时的处理事件

on-success设置上传成功后的事件

auto-upload设置自动提交为false,用来实现手动提交时才提交

data设置上传时携带的数据

drag表示支持可拖拽

设置on-progress正在上传时将其禁用

    // 文件上传中处理
    handleFileUploadProgress(event, file, fileList) {
      this.upload.isUploading = true;
    },

设置on-success上传成功后关闭上传窗口并设置上传可用,然后清除选择的文件并提示导入结果然后刷新数据。

    // 文件上传成功处理
    handleFileSuccess(response, file, fileList) {
      this.upload.open = false;
      this.upload.isUploading = false;
      this.$refs.upload.clearFiles();
      this.$alert(response.msg, "导入结果", { dangerouslyUseHTMLString: true });
      this.getList();
    },

这里是携带了参数 是否更新已经存在的数据,将其与勾选框进行双向数据绑定

<el-checkbox v-model="upload.updateSupport" />是否更新已经存在的下井次数设置数据

并且作为参数在提交时进行传递

:data="{updateSupport:upload.updateSupport}"

注意传递参数时的格式。

然后点击确定按钮时触发事件

 <el-button type="primary" @click="submitFileForm">确 定</el-button>

在事件处理中,通过设置的ref属性将表单提交

    submitFileForm() {
      this.$refs.upload.submit();
    },

此时表单就会提交到指定的url的后台接口。

来到后台接口

    @RequestMapping("/importData")
    @ResponseBody
    @ApiOperation("导入下井次数设置数据")
    public AjaxResult importData(@RequestParam MultipartFile file, @RequestParam boolean updateSupport) throws Exception {
        ExcelUtil<KqXjcssz> util = new ExcelUtil<KqXjcssz>(KqXjcssz.class);
        List<KqXjcssz> xjcsszList = util.importExcel(file.getInputStream());
        //循环插入数据
        for (KqXjcssz xjcssz:xjcsszList) {
            if(xjcssz.getGh()==null)
            {
                return  AjaxResult.error("存在为空的工号数据");
            }

            xjcssz.setSzrq(new Date());
            xjcssz.setSzr(SecurityUtils.getUsername());

            //根据工号查询是否已经存在
            Integer count = kqXjcsszService.isExistByGh(xjcssz.getGh());

            if(count>0)
            {
                //如果设置了更新
                if(updateSupport)
                {
                    kqXjcsszService.updateKqXjcssz(xjcssz);
                }else
                {
                    //选择了不更新 啥也不干
                }
            }
            else
            {
                //之前不存在直接插入
                kqXjcsszService.insertKqXjcssz(xjcssz);
            }
        }
        return AjaxResult.success("导入成功");
    }

 

这里的后台接口使用@RequestMapping接收,并且使用@ResponseBody注解响应json数据。

接受请求参数时,文件必须是@RequestParam MultipartFile file,且名称为file,如果不进行更改指定的话。

然后第二个参数要与传递时的参数名一致。

然后调用若依自带的工具类

        ExcelUtil<KqXjcssz> util = new ExcelUtil<KqXjcssz>(KqXjcssz.class);
        List<KqXjcssz> xjcsszList = util.importExcel(file.getInputStream());

 

以及实体类上的注解

    /** 工号 */
    @Excel(name = "工号")
    private String gh;

 

等就能实现解析Excel的数据并获取成对象的list。

这里的导入时的模板建议用下面的导出的EXCEL作为导入模板用。

然后上传时点击下载模板时调用公共下载接口。

Excel导出

页面上添加导出按钮

        <el-button
          type="warning"
          icon="el-icon-download"
          size="mini"
          @click="handleExport"
          v-hasPermi="[\'kqgl:bcgl:export\']"
        >导出</el-button>

 

导出按钮对应的处理方法

 

   /** 导出按钮操作 */
    handleExport() {
      const queryParams = this.queryParams;
      this.$confirm("是否确认导出所有数据项?", "警告", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(function () {
          return exportBcgl(queryParams);
        })
        .then((response) => {
          this.download(response.msg);
        })
        .catch(function () {});
    },

 

会弹窗提示,点击确定后执行exportBcgl方法,此方法是从外部js中引入

import {
  exportBcgl,
} from "@/api/kqgl/bcgl";

 

在js方法中

export function exportBcgl(query) {
  return request({
    url: \'/kqgl/bcgl/export\',
    method: \'get\',
    params: query
  })
}

 

在此方法中发送get请求给SpringBoot后台接口。

其中request是来自request.js,封装的axios发送请求的对象。

在对应的SpringBoot后台接口

    @GetMapping("/export")
    public AjaxResult export(KqBcgl kqBcgl)
    {
        List<KqBcgl> list = kqBcglService.getBcListByNameToExport(kqBcgl);
        ExcelUtil<KqBcgl> util = new ExcelUtil<KqBcgl>(KqBcgl.class);
        return util.exportExcel(list, "bcgl");
    }

 

直接调用若依自带的Excel工具类就可以实现导出。

其中KqBcgl是对应的业务的实体类,可以使用代码生成工具去生成。

在实体类中通过添加注解的方式就能实现将此属性导出,如果不加此注解则不导出

    /** 编号 */
    @Excel(name = "编号")
    private String bcbh;

 

而且注解里面的name属性就是导出时那列的标题。

关于这个注解还有好多个属性,具体可以参考其源码

public @interface Excel
{
    /**
     * 导出到Excel中的名字.
     */
    public String name() default "";

    /**
     * 日期格式, 如: yyyy-MM-dd
     */
    public String dateFormat() default "";

    /**
     * 读取内容转表达式(如:0=男,1=女,2=未知)
     */
    public String readConverterExp() default "";

    /**
     * 导出类型(0数字 1字符串)
     */
    public ColumnType cellType() default ColumnType.STRING;

    /**
     * 导出时在excel中每个列的高度 单位为字符
     */
    public double height() default 14;

    /**
     * 导出时在excel中每个列的宽 单位为字符
     */
    public double width() default 16;

    /**
     * 文字后缀,如% 90 变成90%
     */
    public String suffix() default "";

    /**
     * 当值为空时,字段的默认值
     */
    public String defaultValue() default "";

    /**
     * 提示信息
     */
    public String prompt() default "";

    /**
     * 设置只能选择不能输入的列内容.
     */
    public String[] combo() default {};

    /**
     * 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.
     */
    public boolean isExport() default true;

    /**
     * 另一个类中的属性名称,支持多级获取,以小数点隔开
     */
    public String targetAttr() default "";

    /**
     * 字段类型(0:导出导入;1:仅导出;2:仅导入)
     */
    Type type() default Type.ALL;

    public enum Type
    {
        ALL(0), EXPORT(1), IMPORT(2);
        private final int value;

        Type(int value)
        {
            this.value = value;
        }

        public int value()
        {
            return this.value;
        }
    }

    public enum ColumnType
    {
        NUMERIC(0), STRING(1);
        private final int value;

        ColumnType(int value)
        {
            this.value = value;
        }

        public int value()
        {
            return this.value;
        }
    }
}

 

还有一种情况是,在导出前的查询数据的方法,如果调用的是和查询接口一样的方法。

某些属性比如某某状态等需要用到字典表的列。在查询接口可能就是直接查询出来,返回值

直接就是1或者2等这些字典的值。然后返回给前端,前端再进行格式化显示。

但是在导出时必须要显示对应的字典表的label,所以需要修改查询数据的方法getBcListByNameToExport

将要查询的表与字典表相关联,查询出其label值作为对应的属性,如果有多个需要关联字典表的属性,则关联两次,下面是示例代码

 

   <select id="getBcListByNameToExport" parameterType="KqBcgl" resultMap="KqBcglResult">
        SELECT
        b.id,
        b.bcbh,
        b.bcmc,
        s.dict_label AS bclx,
        sfkt,
        b.xss,
        b.jgs,
        b.sfyb,
        kqts,
        b.mzxx,
        b.bz,
        s1.dict_label AS jxbclx
        FROM
        kq_bcgl b
        LEFT JOIN sys_dict_data s ON b.bclx = s.dict_value
        AND s.dict_type = "kq_kqgl_bcgl_bclx"
        LEFT JOIN sys_dict_data s1 ON b.jxbclx = s1.dict_value
        AND s1.dict_type = "kq_kqgl_bcgl_jxbclx"
        <where>
            <if test="bcmc != null  and bcmc != \'\'"> and bcmc LIKE "%"#{bcmc}"%"</if>
        </where>
    </select>

 

那么点击导出按钮就能实现导出了