赞
踩
前段时间,写(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对象 和 创建单元格对象时进行设置,复杂的我也没有进行深入研究,后续如果有遇到,我们再进行拓展补充。
好了,以上就是本文的全部内容,我有个臭毛病,不是很擅长言语表达,动不动就是直接上代码,直来直去,码文字,权当记录和锻炼,如果觉得还可以,给个回复或给个赞,感谢。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。