基于Java、Js导出Execl通用模板

需求:批量导出不同表格的数据,每个表格的数据不一样,字段不一样,用最简单的方式实现导出Execl通用模板

效果图:

一、前端

1.1、前端代码

<button id="export" onclick="exportData();return false; "> <span class="icon_export">导出</span></button>
 
// 导出
function exportData() {
	top.Dialog.alert("数据正在生成中,请耐心等待...!");
	// Get方式请求后台,参数后台通过HttpServletRequest获取
    window.open(getBaseUrl() + "/khzpf/exportXxxxErroInfo?rqdm=" + params.rqdm + "&rpfxdm=" + params.rpfxdm);
}

    /*
    备注:
    	这种方式也可以实现
    	出现的问题:但是多次操作会出现,$('#myFormId')[0] == 'undefined'的情况,询问DeepSeek:回答表格有防止重复提交的功能,所以只可以点击一次,DeepSeek提供的方式没有解决去除表格防止重复的功能,但是实际业务可能多次点击,所以暂时把代码放在这里
    */
    $('#myFormId').attr("action", getBaseUrl() + "/khzpf/exportXxxxxxxErroInfo?rqdm=" + params.rqdm + "&rpfxdm=" + params.rpfxdm);
    $('#myFormId').submit();
    // 重置表单(可选)
    setTimeout(() => { $('#myFormId')[0].reset() }, 1000);

1.2、题外话:前端制作通用列表显示内容

            // 1002	"每周一次自动粮情检测	"
            const columns1002 = [
                { display: '序号', name: 'xh', align: 'center', width: "10%", isSort: false, showTitle: true },
                { display: '1002标题列1', name: 'value1', align: 'center', width: "20%", isSort: false, showTitle: true },
                { display: '1002标题列2', name: 'value2', align: 'center', width: "20%", isSort: false, showTitle: true },
                { display: '1002标题列3', name: 'value3', align: 'center', width: "20%", isSort: false, showTitle: true },
                { display: '1002标题列4', name: 'value4', align: 'center', width: "20%", isSort: false, showTitle: true }
            ]
            // 1003	出入库业务每笔必须有地磅抓拍图片
            const columns1003 = [
                { display: '序号', name: 'xh', align: 'center', width: "10%", isSort: false, showTitle: true },
                { display: '1003标题列1', name: 'value1', align: 'center', width: "10%", isSort: false, showTitle: true },
                { display: '1003标题列2', name: 'value2', align: 'center', width: "10%", isSort: false, showTitle: true },
                { display: '1003标题列3', name: 'value3', align: 'center', width: "10%", isSort: false, showTitle: true },
                { display: '1003标题列4', name: 'value4', align: 'center', width: "10%", isSort: false, showTitle: true },
                { display: '1003标题列5', name: 'value5', align: 'center', width: "10%", isSort: false, showTitle: true }
            ]
            
            // 方案2:使用对象容器(推荐更安全的模式)
            const columnsConfig = {
                1002: columns1002,
                1003: columns1003
            }
            
            //加载表格数据
            grid = $("#dataBasic").quiGrid({
                 columns: columnsConfig[rpfxdmStr]
            });

二、后端

2.1、pom

<dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-base</artifactId>
    <version>3.2.0</version>
</dependency>
<dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-web</artifactId>
    <version>3.2.0</version>
</dependency>
<dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-annotation</artifactId>
    <version>3.2.0</version>
</dependency>

2.2、后台代码

    /**
     * 导出方法
     * @param request 前端请求
     * @param response 请求返回
     * @throws IOException 异常
     */
    @GetMapping(value = "/exportXxxxxxxErroInfo")
    public void exportXxxxxxxErroInfo(HttpServletRequest request, HttpServletResponse response) throws IOException {
        try {
            // 1. 前台参数校验
            String rpfxdm = request.getParameter("rpfxdm");
            String rqdm = request.getParameter("rqdm");
            if (StringUtils.isEmpty(rpfxdm) || StringUtils.isEmpty(rqdm)) {
                response.sendError(HttpServletResponse.SC_BAD_REQUEST, "参数 rpfxdm 或 rqdm 不能为空");
                return;
            }

            // 2. 获取用户信息和文件名称
            TbSysUserInfo userInfo = UserInfoUtil.getUserInfo();
            // 默认文件名称
            String pfx = "文件详情";
            TbAssKhzpfmb detail = tbAssKhzpfmbService.detail(rpfxdm);
            if (detail != null && detail.getPfx() != null) {
                pfx = detail.getPfx();
            }

            // 3. 创建导出参数,第二行显示
            /*
             * 三个参数
             * title Sheet页主页的标题名称,第一行显示
             * secondTitle 第二行显示的标题名称,这里显示的是导出人(操作人)
             * String sheetName Sheet页的名称
             */
            ExportParams exportParams = new ExportParams(pfx, "导出人:" + userInfo.getFullname(), pfx);
            exportParams.setStyle(ExcelStyleType.BORDER.getClazz());

            // 4. 生成 Workbook 并设置响应
            /*
                response.setContentType("application/vnd.ms-excel");
                作用:在 Java Web 开发中用于设置 HTTP 响应的 MIME 类型,指定浏览器应该如何处理返回的文件。
                1、指定响应类型:
                将 HTTP 响应的内容类型(Content-Type)设置为 application/vnd.ms-excel,告诉浏览器返回的数据是一个 Excel 文件(通常是 .xls 文件),并应按照 Excel 文件进行处理。
                2、提示浏览器下载 Excel 文件:
                当浏览器接收到这个响应时,它会识别到这个 MIME 类型,并自动提示用户下载 Excel 文件或者在支持的浏览器中以 Excel 格式打开文件。
                3、Excel 文件格式:
                application/vnd.ms-excel 是 Microsoft Excel 文件的 MIME 类型,表示文件是一个 Excel 表格,通常为 .xls 后缀。
                如果你想返回一个 .xlsx 文件(Excel 2007及以后版本),则可以使用 application/vnd.openxmlformats-officedocument.spreadsheetml.sheet。
             */
            response.setContentType("application/vnd.ms-excel");
            // 文件名
            String fileName = pfx + "_文件详情.xls";
            // 使用URLEncoder对文件名进行UTF-8编码,并替换加号为%20。
            // 这是因为URLEncoder会将空格转换为加号,但在HTTP头中,空格应该被编码为%20。
            String encodedFileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
            // 设置Content-Disposition响应头,指定附件的文件名。
            // 使用filename*=UTF-8''前缀告诉浏览器该文件名是UTF-8编码的。
            // encodedFileName变量已经处理过加号的问题,确保文件名正确无误。
            response.setHeader("Content-Disposition", "attachment;filename*=UTF-8''" + encodedFileName);

            // 5. 使用 try-with-resources 确保资源释放
            /*
                try-with-resources 的自动关闭机制
                作用:代码中声明的 Workbook 和 ServletOutputStream 会在 try 块执行完毕后自动调用 close() 方法,无论代码是否正常执行或抛出异常
                     在try 块结束后,out 和 workbook 会按声明顺序的逆序关闭(即先关闭 out,再关闭 workbook),确保资源释放
                前提条件:资源必须实现 AutoCloseable 接口。
                例如: Apache POI 的 Workbook(如 XSSFWorkbook 或 HSSFWorkbook)实现了 AutoCloseable,支持自动关闭。
                      ServletOutputStream 是 Servlet 规范中的类,通常也实现了 Closeable(AutoCloseable 的子接口)
             */
            try (Workbook workbook = getWorkbookByKqdm(exportParams, rpfxdm, rqdm);
                 ServletOutputStream out = response.getOutputStream()) {
                 // 将 Workbook 中的 Excel 数据写入输出流,客户端会收到文件内容
                 workbook.write(out);
            }
        } catch (Exception e) {
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "导出失败,请稍后重试");
            log.error("==导出异常==");
            e.printStackTrace();
        }
    }



    /**
     * 获取通用Workbook对象
     * 关键步骤:
     *	 可以将字段中文名,字段名,字段显示长度,填入代码,不需要编写Vo实体类:columns.add(new ExcelExportEntity("序号", "xh", 10));
     * @param exportParams 导出参数
     * @param rpfxdm 区分不同查询结果实体类的字段
     * @param rqdm 参数
     * @return
     */
    private Workbook getWorkbookByKqdm(ExportParams exportParams, String rpfxdm, String rqdm){
        List<Map<String,String>> socreDataResult = tbAssKhzpfService.getScoreData(rpfxdm, rqdm);
        List<ExcelExportEntity> columns = new ArrayList<>();
        switch (rpfxdm) {
            case "1002":
                columns.add(new ExcelExportEntity("序号", "xh", 10));
                columns.add(new ExcelExportEntity("1002标题列1", "value1", 20));
                columns.add(new ExcelExportEntity("1002标题列2", "value2", 20));
                columns.add(new ExcelExportEntity("1002标题列3", "value3", 20));
                columns.add(new ExcelExportEntity("1002标题列4", "value4", 20));
                break;

            case "1003":
                columns.add(new ExcelExportEntity("序号", "xh", 10));
                columns.add(new ExcelExportEntity("1003标题列1", "value1", 20));
                columns.add(new ExcelExportEntity("1003标题列2", "value2", 20));
                columns.add(new ExcelExportEntity("1003标题列3", "value3", 20));
                columns.add(new ExcelExportEntity("1003标题列4", "value4", 20));
                columns.add(new ExcelExportEntity("1003标题列5", "value4", 20));
                break;

            default:
                // 默认情况处理
                break;
        }

        return ExcelExportUtil.exportExcel(exportParams, columns, socreDataResult);
    }

posted @ 2025-04-02 18:15  大沐沐沐  阅读(101)  评论(0)    收藏  举报