easyExcel合并数据导出(一对多)

语言 java

框架 ssm

需求 :看图  也是导出效果

 

数据库查询为(关系为一对多) 一个学生对应多个课程

 

 

 实现步骤

1.实体类配置, 建议单独写个实体用来导出使用()

学生信息字段正常配置  , 课程表字段 使用  @ExcelProperty({"学生和选课中间表","学生编号"})

StudentExcel.java

package com.example.mybatisplus.pojo;

import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * easy_excel导出
 * @author three
 * @date 2021/8/23 16:13
 */
@ApiModel("easy_excel导出实体类")
@Data
public class StudentExcel implements Serializable {
    private static final long serialVersionUID = 1L;

    // ----学生信息表( 一 )

    @ExcelProperty("学生姓名")
    @ApiModelProperty("学生姓名")
    private String sname;

    @ExcelProperty("性别")
    @ApiModelProperty("性别")
    private String sgender;

    @ExcelProperty("出生年月")
    @ApiModelProperty("出生年月")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date sbirth;

    //----学生和选课中间表(多)----

    @ExcelProperty({"学生和选课中间表","学生编号"})
    @ApiModelProperty("学生编号")
    private Integer sno;

    @ExcelProperty({"学生和选课中间表","课程编号"})
    @ApiModelProperty("课程编号")
    private String cno;

    @ExcelProperty({"学生和选课中间表","分数"})
    @ApiModelProperty("分数")
    private String score;
}
View Code

2.代码 工具类  ExcelFillCellMergeStrategy.java

package com.example.mybatisplus.utils;

import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;

import java.util.List;

public class ExcelFillCellMergeStrategy implements CellWriteHandler {

    private int[] mergeColumnIndex;
    private int mergeRowIndex;

    public ExcelFillCellMergeStrategy(int mergeRowIndex, int[] mergeColumnIndex) {
        this.mergeRowIndex = mergeRowIndex;
        this.mergeColumnIndex = mergeColumnIndex;
    }

    @Override
    public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {

    }

    @Override
    public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {

    }

    @Override
    public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer integer, Boolean aBoolean) {

    }

    @Override
    public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {
        int curRowIndex = cell.getRowIndex();
        int curColIndex = cell.getColumnIndex();
        if (curRowIndex > mergeRowIndex) {
            for (int i = 0; i < mergeColumnIndex.length; i++) {
                if (curColIndex == mergeColumnIndex[i]) {
                    mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);
                    break;
                }
            }
        }
    }

    /**
     * 当前单元格向上合并
     *
     * @param writeSheetHolder
     * @param cell             当前单元格
     * @param curRowIndex      当前行
     * @param curColIndex      当前列
     */
    private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {
        Object curData = cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();
        Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex);
        Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() : preCell.getNumericCellValue();
        // 将当前单元格数据与上一个单元格数据比较
        Boolean dataBool = preData.equals(curData);
        if (dataBool) {
            Sheet sheet = writeSheetHolder.getSheet();
            List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();
            boolean isMerged = false;
            for (int i = 0; i < mergeRegions.size() && !isMerged; i++) {
                CellRangeAddress cellRangeAddr = mergeRegions.get(i);
                // 若上一个单元格已经被合并,则先移出原有的合并单元,再重新添加合并单元
                if (cellRangeAddr.isInRange(curRowIndex - 1, curColIndex)) {
                    sheet.removeMergedRegion(i);
                    cellRangeAddr.setLastRow(curRowIndex);
                    sheet.addMergedRegion(cellRangeAddr);
                    isMerged = true;
                }
            }
            // 若上一个单元格未被合并,则新增合并单元
            if (!isMerged) {
                CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex, curColIndex);
                sheet.addMergedRegion(cellRangeAddress);
            }
        }
    }

}
View Code

3. EasyExcelController.java

  3.1 int[] mergeColumeIndex = {0,1,2};  数据重复部分会合并成一个单元格,只需标出需要合并的列数

  3.2  int mergeRowIndex = 0; 标出合并的开始列数 从0开始

package com.example.mybatisplus.controller;

import com.alibaba.excel.EasyExcel;
import com.example.mybatisplus.pojo.StudentExcel;
import com.example.mybatisplus.pojo.StudentinfoEntity;
import com.example.mybatisplus.service.StudentinfoService;
import com.example.mybatisplus.utils.ExcelFillCellMergeStrategy;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.http.HttpRequest;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;

/**
 * EasyExcel test
 * 测试地址 http://localhost:8088/easy-excel/export
 * 传输数据 [1,2,3]
 * @author zou
 * @date 2021/8/23 15:51
 */
@Api(tags = "easy-excel的使用")
@RestController
@RequestMapping("/easy-excel")
public class EasyExcelController {

    @Resource
    private StudentinfoService studentinfoService;

    @PostMapping("/export")
    @ApiOperation("导出excel(一对多关系)")
    public void excel(HttpServletResponse response,@RequestBody Integer[] sno) throws IOException {
        List<StudentExcel> studentinfoEntities = studentinfoService.studentToElectives(sno);
        // 设置响应格式
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        //需要合并的列
        int[] mergeColumeIndex = {0,1,2};
        // 从那一列开始合并
        int mergeRowIndex = 0;
        String fileName = URLEncoder.encode("one-to-many", "UTF-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), StudentExcel.class)
                .sheet("one-to-many")
                .registerWriteHandler(new ExcelFillCellMergeStrategy(mergeRowIndex, mergeColumeIndex))
                .doWrite(studentinfoEntities);
    }
}
View Code

4.服务层,持久层略去一千行....

....

posted @ 2021-08-23 18:01  三只坚果  阅读(6765)  评论(1编辑  收藏  举报