改造若依Excel导出功能——可自定义模板导出

一、背景

若依 RuoYi-Vue 原本的台账列表导出(excel)功能,效果是统一样式,如下图所示(本文以用户管理页面演示):

在这里插入图片描述

现在有个需求,大致是导出可根据自定义模板导出,比如加上导出标题、导出日期、导出人等信息。

目标效果

举例,下图是客户要求的导出模板,希望 标题 ${title} 在导出的时候可以自定义,然后 $ {date} 自动赋值当前日期,${user} 自动赋值当前登录用户名,然后从下面带“表头”字样的那一行开始,填充原本若依导出的表格

模板:

在这里插入图片描述

目标效果如下:

在这里插入图片描述

在这里插入图片描述

二、后端

逻辑

先建一个excel模板,样式如上面所示,存放目录如 src/main/resources/templates/template.xlsx

找到原来用户管理台账导出接口 /export

增加新参数–导出标题 title,

动态替换模板里的变量参数,

修改原来的导出excel方法,在模板excel的基础上,再贴入原先的表格

实现

  • com.ruoyi.web.controller.system.SysUserController

    导出接口

        @Log(title = "用户管理", businessType = BusinessType.EXPORT)
        @PreAuthorize("@ss.hasPermi('system:user:export')")
        @PostMapping("/export")
        public void export(HttpServletResponse response, SysUser user, String title) throws IOException {
            List<SysUser> list = userService.selectUserList(user);
            ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
    //        util.exportExcel(response, list, "用户数据");
            // 替换模板变量
            Map<String, String> replacements = new HashMap<>(16);
            replacements.put("title",title);
            replacements.put("date",DateUtils.getDate());
            replacements.put("user", getUsername());
            // 读取模板文件
            Resource resource = new ClassPathResource("templates/template.xlsx");
            InputStream templateStream = resource.getInputStream();
    
            util.exportExcelByTemplate(response, list, "用户数据",templateStream,replacements);
        }
    

    注意

    这里读取模板文件的方法是使用InputStream流读取resource目录下的资源,这样的好处是不需要打包,直接用idea启动项目,同个局域网的其他机器访问你本地项目也能进行测试

  • com.ruoyi.common.utils.poi.ExcelUtil

    导出方法

        /**
         * 对list数据源将其里面的数据导入到excel表单
         * 改造:根据模板导出,可以替换模板里的变量
         * @param response 返回数据
         * @param list 导出数据集合
         * @param sheetName 工作表的名称
         * @return 结果
         */
        public void exportExcelByTemplate(HttpServletResponse response, List<T> list, String sheetName, InputStream inputStream, Map<String, String> replacements) throws IOException {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            if (list == null)
            {
                list = new ArrayList<T>();
            }
            this.list = list;
            this.sheetName = sheetName;
            this.type = Type.EXPORT;
    
            // 创建工作簿对象
            Workbook workbook = WorkbookFactory.create(inputStream);
            // 关闭输入流
            inputStream.close();
    
            // 获取指定的工作表
            Sheet sheet = workbook.getSheetAt(0); // 选择第一个工作表,索引从0开始
    
            // 遍历所有行和列,查找包含 ${key} 的单元格
            for (Row row : sheet) {
                for (Cell cell : row) {
                    if (cell.getCellType() == CellType.STRING) {
                        String cellValue = cell.getStringCellValue();
                        if (cellValue.contains("${")) { // 判断是否包含占位符
                            for (Map.Entry<String, String> entry : replacements.entrySet()) {
                                String key = "${" + entry.getKey() + "}";
                                if (cellValue.contains(key)) {
                                    cellValue = cellValue.replace(key, entry.getValue());
                                }
                            }
                            cell.setCellValue(cellValue); // 替换并保持格式
                        }
                    }
                }
            }
    
            // 找到第一个单元格值为"表头"的行,并删除它
            int headerRowIndex = -1;
            for (Row row : sheet) {
                Cell firstCell = row.getCell(0); // 获取第一列单元格
                if (firstCell != null && firstCell.getCellType() == CellType.STRING && "表头".equals(firstCell.getStringCellValue())) {
                    headerRowIndex = row.getRowNum();
                    break;
                }
            }
            if (headerRowIndex != -1) {
                sheet.removeRow(sheet.getRow(headerRowIndex));
                this.rownum = headerRowIndex;
            }
    
            workbook.setSheetName(0, sheetName);
            this.wb = workbook;
            this.sheet = sheet;
            createExcelField();
            this.styles = createStyles(wb);
            exportExcel(response);
    
        }
    

    注意

    this.rownum 是sheet的当前行数,这里因为我们要在模板已有内容的后面补充原先要导出的表格,所以这个rownum值要更新

三、前端

逻辑

点击导出按钮时,先弹窗让用户输入导出标题,如下图所示

然后点"确定"再调用导出方法,传入的参数新增"title"

在这里插入图片描述

在这里插入图片描述

实现

  • ruoyi-ui/src/views/system/user/index.vue

              <el-col :span="1.5">
                <el-button
                  type="warning"
                  plain
                  icon="el-icon-download"
                  size="mini"
                  @click="openExportDialog"
                  v-hasPermi="['system:user:export']"
                >导出</el-button>
              </el-col>
    
              <!-- 导出弹窗 -->
              <el-dialog title="导出数据" :visible.sync="exportDialogVisible" width="30%">
                <el-form label-width="80px">
                  <el-form-item label="导出标题">
                    <el-input v-model="exportTitle" placeholder="请输入导出文件的标题"></el-input>
                  </el-form-item>
                </el-form>
                <span slot="footer" class="dialog-footer">
                  <el-button @click="exportDialogVisible = false">取消</el-button>
                  <el-button type="primary" @click="handleConfirmExport">确定</el-button>
                </span>
              </el-dialog>
    
    
    data() {
        return {
          // 控制弹窗
          exportDialogVisible: false,
          // 导出标题
          exportTitle: "",
        };
     }
    
     // 打开导出弹窗
         openExportDialog() {
          this.exportTitle = ""; // 清空输入框
          this.exportDialogVisible = true;
        },
        
        // 确认导出
        handleConfirmExport() {
          if (!this.exportTitle) {
            this.$message.warning("请输入导出标题");
            return;
          }
          
          this.exportDialogVisible = false; // 关闭弹窗
    
          // 调用导出 API,带上标题参数
          this.download("system/user/export", {
            ...this.queryParams,
            title: this.exportTitle
          }, `user_${new Date().getTime()}.xlsx`);
        },
    

四、最终效果

如下图所示

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值