Java 使用POI导出数据到 excel,单 sheet 和多 sheet

        前段时间,写(shui)了一个上传文件的博客(Java 上传附件后端接口大体流程和逻辑),今天做项目时,刚好又遇到导出excel的功能,前期就一直想做个归纳记录,但一直都是被各种各样的事(tuo)情(yan)耽搁了,今天刚好遇到导出数据到多 sheet的需求,开发完后,顺手来记录一下。

       凡事都是由简入繁,我们首先从Java导出excel 单sheet开始,这个场景遇到的比较多,比较普遍。

前期准备:

单 sheet 和 多 sheet,用到的jar都是一样的,无非就是多创建一个 sheet的问题,以下是需要用到的jar包,在对应模块的pom.xml 中引入即可

        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.9</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.9</version>
        </dependency>

导出开始:

从前到后,首先我们要在controller 层中开放一个GET请求接口,因为当前场景设定为列表导出,会涉及到页面查询条件,所以controller 层代码如下:

    /**
     * 导出列表
     * @return
     */
    @RequestMapping(value = "/export", method = RequestMethod.GET)
    public String selectExport(@RequestParam(name = "name", required = false) String name,
                               @RequestParam(value = "ids", required = false) String ids,
                               HttpServletRequest request, HttpServletResponse response) {
        Map dataMap = new HashMap();
        dataMap.put("name", name);
        dataMap.put("ids", ids);
        return getResult(Result.OK,iProService.selectExportList(dataMap, request, response));
    }

如上述代码所示, @RequestMapping 中设置当前请求为 GET请求,方便前端调用,方法参数中使用 @RequetParam 设置入参名称,并使用 required=false 设置当前参数非必填。

底部的 getResult(***) 这个为我们当前项目封装的返回值方法,cmsPropertyModelService.selectExportCmsPropertyModelList 为处理当前导出任务的接口。

service层接口:

    /**
     * 导出列表
     * @return
     */
    public boolean selectExportList(Map dataMap, HttpServletRequest request, HttpServletResponse response);

讲了那么多,接下来是重点部分,导出接口的实现类,处理我们的业务逻辑和导出逻辑

单 sheet 导出 serviceImpl:

    /**
     * 导出列表
     *
     * @param dataMap
     * @param request
     * @param response
     * @return
     */
    @Override
    public boolean selectExportList(Map dataMap, HttpServletRequest request, HttpServletResponse response) {
        String ids = MapUtils.getString(dataMap, "ids");
        if (StringUtils.isNotEmpty(ids)) {
            dataMap.put("ids", ids.split(","));
        }
        //查询需要导出的数据
        List<CmsPropertyModel> cmsPropertyModelList = Mapper层数据库查询;

        //第一步:创建一个webbook,对应一个Excel文件
        HSSFWorkbook wb = new HSSFWorkbook();

        //第一步:创建单元格,并设置值表头 设置表头居中
        HSSFCellStyle style = wb.createCellStyle();
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 创建一个居中格式
        //表头加粗
        HSSFFont titleFont = wb.createFont();
        titleFont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        style.setFont(titleFont);
        //第三步:创建 sheet,并分别设置 标题
        HSSFSheet sheet1 = wb.createSheet("父级sheet");
        HSSFRow row1 = sheet1.createRow(0);
        String[] sheet1Title = {"名称", "备注"};
        //创建sheet1标题
        for (int i = 0 ; i < sheet1Title.length; i ++) {
            Cell cell = row1.createCell(i);
            cell.setCellStyle(style);     //设置标题样式
            cell.setCellValue(sheet1Title[i]);
            sheet1.setColumnWidth(i, 10000);   //设置列宽
        }

        //第四步:往sheet中设置值
        if (null != cmsPropertyModelList && cmsPropertyModelList.size() > 0) {
            for (int i = 0; i < cmsPropertyModelList.size(); i ++) {
                CmsPropertyModel cmsPropertyModel = cmsPropertyModelList.get(i);

                row1 = sheet1.createRow(sheet1.getLastRowNum() + 1); //获取当前行下一行
                row1.createCell(0).setCellValue(cmsPropertyModel.getName()); 
                row1.createCell(1).setCellValue(cmsPropertyModel.getDescription()); 
            }
        }

        //第五步:导出
        try {
            //excel文件名
            String fileName = "列表_" + DateFormatUtils.format(new Date(), "yyyyMMdd_HHmmss") + ".xls";
            //导出设置
            fileName = new String(fileName.getBytes(), "ISO8859-1");
            response.setContentType("application/octet-stream;charset=ISO8859-1");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            response.addHeader("Pargam", "no-cache");
            response.addHeader("Cache-Control", "no-cache");
            //开始导出
            OutputStream os = response.getOutputStream();
            wb.write(os);
            os.flush();
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(">>> 导出列表发生异常!" + e.getMessage());
        }

        return true;
    }

以上就是单个 sheet 的excel导出,查询出数据后,开始创建 excel 对象等操作,里面首先设置sheet页标题,设置好后,通过循环我们数据库查询到的数据,一条一条一次追加,其中  sheet1.createRow(sheet1.getLastRowNum() + 1); 这句代码中的 sheet1.getLastRowNum() 是获取当前sheet 最新的一行,获取后 + 1 ,表示创建在当前最新一下后面创建一行,一次来保证行连续,且我们可以不用去管具体行号是多少,当然如果具体业务有需要,可以修改这个跟当前循环次数进行关联。

DateFormatUtils.java 是 apache commons-langs 公共包中的工具类,maven导包如下:
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.4</version>
            <scope>provided</scope>
        </dependency>

 以上就是单 sheet execl 导出过程,接下来是多个的,我这边用两个sheet来演示,其余的以此类推,我们的数据结构是父级中带有子集列表,如下所示:

{
    "name":"父级名称",
    "description":"描述",
    "cmsPropertyList":[		//子集列表
        {
            "proName":"子集名称",
            ......
    ]
}

大家每个人的实际业务需求不同,处理和实现的逻辑也会有不用,这里只是介绍一个我遇到的,应该是比较常见的场景,好了,不废话了,直接上代码。

多 sheet 导出 serviceImpl:

    /**
     * 导出列表
     *
     * @param dataMap
     * @param request
     * @param response
     * @return
     */
    @Override
    public boolean selectExportList(Map dataMap, HttpServletRequest request, HttpServletResponse response) {
        String ids = MapUtils.getString(dataMap, "ids");
        if (StringUtils.isNotEmpty(ids)) {
            dataMap.put("ids", ids.split(","));
        }
        //查询需要导出的数据
        List<CmsPropertyModel> cmsPropertyModelList = Mapper层数据库查询数据

        //第一步:创建一个webbook,对应一个Excel文件
        HSSFWorkbook wb = new HSSFWorkbook();

        //第一步:创建单元格,并设置值表头 设置表头居中
        HSSFCellStyle style = wb.createCellStyle();
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 创建一个居中格式
        //表头加粗
        HSSFFont titleFont = wb.createFont();
        titleFont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        style.setFont(titleFont);
        //第三步:分别创建 sheet,并分别设置 标题
        //创建sheet1
        HSSFSheet sheet1 = wb.createSheet("父级sheet");
        HSSFRow row1 = sheet1.createRow(0);
        String[] sheet1Title = {"名称", "备注"};
        //设置sheet1标题
        for (int i = 0 ; i < sheet1Title.length; i ++) {
            Cell cell = row1.createCell(i);
            cell.setCellStyle(style);     //设置标题样式
            cell.setCellValue(sheet1Title[i]);
            sheet1.setColumnWidth(i, 10000);   //设置列宽
        }

        //创建sheet1
        HSSFSheet sheet2 = wb.createSheet("子级sheet");
        HSSFRow row2 = sheet2.createRow(0);
        String[] sheet2Title = {"父级名称", "子集名称", ……};
        //设置sheet2标题
        for (int i = 0 ; i < sheet2Title.length; i ++) {
            Cell cell = row2.createCell(i);
            cell.setCellStyle(style);     //设置标题样式
            cell.setCellValue(sheet2Title[i]);
            sheet2.setColumnWidth(i, 10000);   //设置列宽
        }

        //第四步:往sheet中设置值
        if (null != cmsPropertyModelList && cmsPropertyModelList.size() > 0) {
            for (int i = 0; i < cmsPropertyModelList.size(); i ++) {
                CmsPropertyModel cmsPropertyModel = cmsPropertyModelList.get(i);

                //设置 sheet1 中的值
                row1 = sheet1.createRow(sheet1.getLastRowNum() + 1); //获取当前行下一行
                row1.createCell(0).setCellValue(cmsPropertyModel.getName());        //父级名称
                row1.createCell(1).setCellValue(cmsPropertyModel.getDescription()); //父级备注

                //设置 sheet2 中的值
                List<CmsProperty> cmsPropertyList = cmsPropertyModel.getCmsPropertyList();
                if (null != cmsPropertyList && cmsPropertyList.size() > 0) {
                    for (int j = 0; j < cmsPropertyList.size(); j ++) {
                        CmsProperty cmsProperty = cmsPropertyList.get(j);
                        String proSeq = (null == cmsProperty.getProSeq()) ? "" : String.valueOf(cmsProperty.getProSeq());
                        row2 = sheet2.createRow(sheet2.getLastRowNum() + 1);    //获取sheet2当前行下一行
                        row2.createCell(0).setCellValue(cmsProperty.getProModelName());     //子集名称
                        ……………… 往 sheet2 当前行的单元格中设值 …………
                    }
                }
            }
        }

        //第五步:导出
        try {
            //excel文件名
            String fileName = "列表_" + DateFormatUtils.format(new Date(), "yyyyMMdd_HHmmss") + ".xls";
            //导出设置
            fileName = new String(fileName.getBytes(), "ISO8859-1");
            response.setContentType("application/octet-stream;charset=ISO8859-1");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            response.addHeader("Pargam", "no-cache");
            response.addHeader("Cache-Control", "no-cache");
            //开始设置
            OutputStream os = response.getOutputStream();
            wb.write(os);
            os.flush();
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(">>> 导出列表发生异常!" + e.getMessage());
        }
        return true;
    }

单个sheet 和多个 sheet 其实差别并不大,无非就是多创建一个 sheet,并进行设值而已。

需要声明的是:这只是简单的excel导出,适用于普通的导出,并没有涉及到过多的excel样式设置,如果项目中对excel样式有要求,可以在前面几步,创建 HSSFWork对象 和 创建单元格对象时进行设置,复杂的我也没有进行深入研究,后续如果有遇到,我们再进行拓展补充。

好了,以上就是本文的全部内容,我有个臭毛病,不是很擅长言语表达,动不动就是直接上代码,直来直去,码文字,权当记录和锻炼,如果觉得还可以,给个回复或给个赞,感谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值