ps:基於HuTool工具類ExcelWriter合並單元格並且使用 jdk1.8 lambda表達式
一、原始數據模板
二、合並后的數據
按照班級名稱、班級分數、小組名稱、小組得分、人物名稱、人物總分進行單元格合並
合並后效果:
三、導入依賴
ps:pom依賴版本不合適可以換其他版本
導出是項目中最常見的功能,例如考勤記錄導出,賬單明細導出,訂單記錄導出等等。導出的工具類有許多種,目前常見的有poi,easypoi,poi...,今天我要說的是基於hutool-poi的導出,hutool-poi是將poi做了封裝,簡化了大量的代碼編寫。 使用方式: maven 在項目的pom.xml中引入 <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>4.5.1</version> </dependency> gradle 在項目的build.gradle中引入 compile 'cn.hutool:hutool-all:5.7.3'
四、代碼邏輯
1.查找數據庫返回數據voList;
2.設置導出表頭數據;
3.用lambda表達式獲取字段分組數據;
4.遍歷數據,設置合並規則;
5.將數據保存在list中;
6.ExcelWriter導出excel文件
五、代碼
1.需實現將人物信息導出到excel文件中並且還要按照班級名稱,小組名稱,人物名稱動態合並單元格,所以先創建人物對象:
@Data @AllArgsConstructor //生成所有參數的構造器 public class Person { //班級名稱 private String className; //班級分數 private double classScore; //小組名稱 private String groupName; //小組分數 private double groupScore; //人物姓名 private String personName; //人物總分 private double personScore; //學科名稱 private String subjectName; //學科分數 private double subjectScore; }
2.導出核心代碼:
@Slf4j @RestController @RequestMapping("/person") public class PersonController { /** * 將頁面的數據導出並合並單元格 * @param response */ @ApiOperation(value = "導出數據到excel") @ApiImplicitParams({ @ApiImplicitParam(name = "response", value = "響應體對象", dataType = "HttpServletResponse") }) @GetMapping("/export") public void export(HttpServletResponse response)throws Exception{ //1.模擬一些人物對象數據(工作中從數據庫查出來) List<Person> list = new ArrayList<>(); list.add(new Person("一班",90,"一組",89,"孫悟空",89,"語文",89)); list.add(new Person("一班",90,"一組",89,"孫悟空",89,"數學",98)); list.add(new Person("一班",90,"一組",89,"唐僧",78,"語文",98)); list.add(new Person("一班",90,"一組",89,"唐僧",78,"數學",78)); list.add(new Person("一班",90,"二組",90,"沙悟凈",90,"語文",90)); list.add(new Person("一班",90,"二組",90,"沙悟凈",90,"數學",90)); list.add(new Person("二班",91,"一組",97,"魯智深",98,"語文",89)); list.add(new Person("二班",91,"一組",97,"魯智深",98,"數學",98)); list.add(new Person("二班",91,"二組",89,"宋江",89,"語文",98)); list.add(new Person("二班",91,"二組",89,"宋江",89,"數學",78)); list.add(new Person("二班",91,"二組",89,"林沖",88,"語文",90)); list.add(new Person("二班",91,"二組",89,"林沖",88,"數學",90)); //2.定義基礎數據 List<String> rowHead = CollUtil.newArrayList("班級名稱","班級分數","小組名稱","小組分數","角色姓名","角色總分","學科名稱","學科分數"); //3.通過ExcelUtil.getBigWriter()創建Writer對象,BigExcelWriter用於大數據量的導出,不會引起溢出; ExcelWriter writer = ExcelUtil.getBigWriter(); //4.寫入標題 writer.writeHeadRow(rowHead); ServletOutputStream out = null; //5.實現核心邏輯 try { //6.定義容器保存人物數據 List<List<Object>> rows = new LinkedList<>(); //7.按照班級進行分組 LinkedHashMap<String, List<Person>> classList = list.stream().collect(Collectors.groupingBy(item -> item.getClassName(), LinkedHashMap::new, Collectors.toList())); //8.定義起始行(方便分組后合並時從哪一行開始) //因為標題已經占了一行,所以數據從第二行開始寫(excel第一行索引為0) //因需要合並到人物分數單元格所以需定義如下起始坐標 int indexClassName = 1; //班級名稱起始行 int indexClassScore = 1; int indexGroupName = 1; int indexGroupScore = 1; int indexPersonName = 1; int indexPersonScore = 1; //9.遍歷按班級名分組后的list(用entrySet效率比keySet效率高) for (Map.Entry<String, List<Person>> classNameListEntry : classList.entrySet()) { //10.獲取按照班級名分組后的集合 List<Person> classValue = classNameListEntry.getValue(); //11.計算此集合的長度 int classSize = classValue.size(); //12.如果只有一行數據不能調用merge方法合並數據,否則會報錯 if (classSize == 1){ indexClassName += classSize; indexClassScore += classSize; indexGroupName += classSize; indexGroupScore += classSize; indexPersonName += classSize; indexPersonScore += classSize; }else{ //13.根據班級名稱進行合並單元格 //合並行,第一個參數是合並行的開始行號(行號從0開始),第二個參數是合並行的結束行號,第三個參數是合並的列號開始(列號從0開始), //第四個參數是合並的列號結束,第五個參數是合並后的內容,null不設置,第六個參數指是否支持設置樣式,true指的是。 writer.merge(indexClassName, indexClassName + classSize - 1, 0, 0, null, true); //14.合並完后起始索引移到下一個合並點 indexClassName += classSize; //15.因為班級分數與班級名稱相關聯,所以不需要對班級分數分組,直接在此基礎上對班級分數合並 writer.merge(indexClassScore, indexClassScore + classSize - 1, 1, 1, null, true); indexClassScore += classSize; //16.按照小組名進行分組(以下分組與班級名合並類似) LinkedHashMap<String, List<Person>> groupList = classValue.stream().collect(Collectors.groupingBy(item -> item.getGroupName(), LinkedHashMap::new, Collectors.toList())); for (Map.Entry<String, List<Person>> groupListEntry : groupList.entrySet()) { List<Person> groupValue = groupListEntry.getValue(); int groupSize = groupValue.size(); if (groupSize == 1){ indexGroupName += groupSize; indexGroupScore += groupSize; indexPersonName += groupSize; indexPersonScore += groupSize; }else{ //合並小組 writer.merge(indexGroupName, indexGroupName + groupSize - 1, 2, 2, null, true); indexGroupName += groupSize; //合並小組分數 writer.merge(indexGroupScore, indexGroupScore + groupSize - 1, 3, 3, null, true); indexGroupScore += groupSize; //17.按照人物名稱進行分組 LinkedHashMap<String, List<Person>> personList = groupValue.stream().collect(Collectors.groupingBy(item -> item.getPersonName(), LinkedHashMap::new, Collectors.toList())); for (Map.Entry<String, List<Person>> personListEntry : personList.entrySet()) { List<Person> personValue = personListEntry.getValue(); int personSize = personValue.size(); if (personSize == 1){ indexPersonName += personSize; indexPersonScore += personSize; }else{ //合並人物 writer.merge(indexPersonName, indexPersonName + personSize - 1, 4, 4, null, true); indexPersonName += personSize; //合並人物總分 writer.merge(indexPersonScore, indexPersonScore + personSize - 1, 5, 5, null, true); indexPersonScore += personSize; } } } } } //18.保存數據 classValue.forEach( sList->{ List<Object> rowA = null; rowA = CollUtil.newArrayList( sList.getClassName(), sList.getClassScore(), sList.getGroupName(), sList.getGroupScore(), sList.getPersonName(), sList.getPersonScore(), sList.getSubjectName(), sList.getSubjectScore() ); rows.add(rowA); } ); } //19.導出數據 //logger.info("導出數據:{}",rows.toString()); // 一次性寫出內容,使用默認樣式,強制輸出標題 writer.write(rows, true); //response為HttpServletResponse對象 response.setContentType("application/vnd.ms-excel;charset=utf-8"); //獲取當前日期作為文件名 Date currentDate = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); String date = sdf.format(currentDate); //test.xls是彈出下載對話框的文件名,不能為中文,中文請自行編碼 //response.setHeader("Content-Disposition", "attachment;filename=file.xlsx"); response.setHeader("Content-Disposition", "attachment;filename=report_"+date+".xlsx"); out = response.getOutputStream(); writer.flush(out, true); }finally { //關閉輸出Servlet流 IoUtil.close(out); //關閉writer,釋放內存 writer.close(); } } }
六、測試
1.使用postman測試
2.結果:
借鑒地址:
https://juejin.cn/post/6982853657679101982
https://blog.csdn.net/zqy_CSDN_name/article/details/119643968