zoukankan      html  css  js  c++  java
  • 若依管理系统前后端分离版基于ElementUI和SpringBoot怎样实现Excel导入和导出

    场景

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

    前端:Vue+ElementUI

    后端:SpringBoot+POI+Mysql

    注:

    博客:
    https://blog.csdn.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>

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

    博客园: https://www.cnblogs.com/badaoliumangqizhi/ 关注公众号 霸道的程序猿 获取编程相关电子书、教程推送与免费下载。
  • 相关阅读:
    Java基本数据类型之间转换
    python 元组tuple
    python 列表List
    python 字符串
    python for循环
    python break/continue
    python while循环
    python条件判断if/else
    python运算符
    python变量
  • 原文地址:https://www.cnblogs.com/badaoliumangqizhi/p/13577202.html
Copyright © 2011-2022 走看看