[Caso de combate] SpringBoot integra EasyExcel para realizar la función de exportación de listas

Este artículo le dará una operación práctica de la función de exportar una lista a una tabla de Excel. Creo que también encontrará la necesidad de exportar una lista en su trabajo diario. Después de leer este artículo, puede integrar fácilmente la función de exportar una lista.

inserte la descripción de la imagen aquí

La herramienta de exportación utilizada esta vez es EasyExcel de código abierto de Alibaba. Aquí hay una breve introducción sobre EasyExcel:

Sabemos que los marcos más famosos para el análisis de Java y la generación de Excel incluyen Apache poi y jxl. Pero todos tienen un problema grave que consume mucha memoria.POI tiene una API en modo SAX que puede resolver algunos problemas de desbordamiento de memoria hasta cierto punto, pero POI todavía tiene algunos defectos, como la descompresión de la versión 07 de Excel y el almacenamiento después de la descompresión. Se hace en la memoria, y el consumo de memoria sigue siendo muy grande.

easyexcel reescribe el análisis de poi de la versión 07 de Excel. Un excel de 3M con análisis de saxofón de POI todavía necesita alrededor de 100 M de memoria. El uso de easyexcel puede reducirlo a unos pocos M, y no importa qué tan grande sea el excel, no habrá desbordamiento de memoria; versión 03 depende del modo sax de POI que encapsula la conversión del modelo en la capa superior, lo que lo hace más fácil y conveniente para los usuarios.

inserte la descripción de la imagen aquí

Bien, comencemos a integrar EasyExcel para realizar la función de exportación.

El primer paso: primero creamos un proyecto Maven y lo integramos en un proyecto SpringBoot.

  • Agregue dependencias, cree interfaces de prueba y asegúrese de que el proyecto pueda ejecutarse.
  • dependencia de unión pom.xml
		<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
        <relativePath/>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
        </dependency>
    </dependencies>
  • definir la clase principal
/**
 * @author lixiang
 * @date 2023/5/26 16:02
 */
@SpringBootApplication
public class ExcelApplication {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(ExcelApplication.class, args);
    }
}
  • crear controlador
/**
 * @author lixiang
 * @date 2023/5/26 16:00
 */
@RestController
@RequestMapping("/excel")
public class ExcelController {
    
    

    @GetMapping("/create")
    public String create(){
    
    
        String msg = "SUCCESS";
        return msg;
    }

}
  • prueba de funcionamiento

inserte la descripción de la imagen aquí

Paso 2: presente la dependencia de EasyExcel y encapsule la clase de herramienta

        <dependency>
            <groupId>com.pig4cloud.excel</groupId>
            <artifactId>excel-spring-boot-starter</artifactId>
            <version>0.5.0</version>
        </dependency>
package com.lixiang.util;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
import com.alibaba.excel.write.handler.RowWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

/**
 * 导出excel 表格 工具类
 * @author lixiang
 * @date 2023/5/26 10:18 
 */
public class EasyExcelUtil implements RowWriteHandler {
    
    

    private int mergeRowIndex;//从哪一行开始合并
    private int[] mergeColumnIndex;//excel合并的列
    private int[] signNum;//合并的唯一标识
    private int total;//总行数
    private int lastRow;
    private int firstCol;
    private int lastCol;
    private int firstRow;
    private int mergeCount = 1;

    private EasyExcelUtil(){
    
    }

    private EasyExcelUtil(int mergeRowIndex, int[] mergeColumnIndex, int[] signNum, int total) {
    
    
        this.mergeRowIndex = mergeRowIndex;
        this.mergeColumnIndex = mergeColumnIndex;
        this.signNum = signNum;
        this.total = total;
    }

    /**
     * 导出excel
     * @param response
     * @param fileName 文件名称
     * @param exportList 导出数据
     * @param clazz 导出实体bean class对象
     * @param <T>
     * @throws IOException
     */
    public static <T> void createExcel(HttpServletResponse response, String fileName, List<T> exportList,
      Class<T> clazz)
      throws IOException {
    
    
        createExcel(response,fileName,exportList,clazz,null);
    }

    /**
     * 导出excel
     * @param response
     * @param fileName 文件名称
     * @param exportList 导出数据
     * @param clazz 导出实体bean class对象
     * @param cellMerge 单元格合并规则
     * @param <T>
     * @throws IOException
     */
    public static <T> void createExcel(HttpServletResponse response, String fileName, List<T> exportList,
      Class<T> clazz, CellMerge cellMerge)
      throws IOException {
    
    
        // 设置下载信息
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        fileName = URLEncoder.encode(fileName, "UTF-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");

        //定义ExcelWriterSheetBuilder
        ExcelWriterSheetBuilder excelWriterSheetBuilder = EasyExcel
          .write(response.getOutputStream(), clazz)
          .sheet(fileName);

        //合并单元格
        if (cellMerge != null) {
    
    
            // 从那一行开始合并
            int mergeRowIndex = 1;
            EasyExcelUtil
              excelMergeRowByRowStrategy = new EasyExcelUtil(mergeRowIndex, cellMerge.getMergeColumIndex(),
              cellMerge.getMergeRuleColumIndex(), exportList.size());
            excelWriterSheetBuilder.registerWriteHandler(excelMergeRowByRowStrategy);
        }

        //设置头样式
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        //设置内容格式
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        HorizontalCellStyleStrategy horizontalCellStyleStrategy =
          new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
        //设计内容居中
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        //设置内容自动换行
        contentWriteCellStyle.setWrapped(true);
        excelWriterSheetBuilder.registerWriteHandler(horizontalCellStyleStrategy);

        //调用doWrite方法
        excelWriterSheetBuilder.doWrite(exportList);
    }

    @Override
    public void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Integer integer, Integer integer1, Boolean aBoolean) {
    
    

    }

    @Override
    public void afterRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer integer, Boolean aBoolean) {
    
    

    }

    @Override
    public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row,
      Integer relativeRowIndex, Boolean isHead) {
    
    
        //当前行
        int curRowIndex = row.getRowNum();
        //每一行的最大列数
        short lastCellNum = row.getLastCellNum();

        if (curRowIndex == 1) {
    
    
            //赋初值 第一行
            firstRow = curRowIndex;
        }
        //开始合并位置
        if (curRowIndex > mergeRowIndex && !row.getCell(0).getStringCellValue().equals("")) {
    
    
            for (int i = 0; i < lastCellNum; i++) {
    
    
                if (i == mergeColumnIndex[i]) {
    
    
                    //当前行号 当前行对象 合并的标识位
                    mergeWithPrevAnyRow(writeSheetHolder.getSheet(), curRowIndex, row, signNum);
                    break;//已经进入到合并单元格操作里面了,执行一次就行
                }
            }
        }
    }

    public void mergeWithPrevAnyRow(Sheet sheet, int curRowIndex, Row row, int[] signNum) {
    
    
        Row preRow = row.getSheet().getRow(curRowIndex - 1);
        List<String> rowDataList = new ArrayList<>();
        List<String> preDataList = new ArrayList<>();

        for (int i : signNum) {
    
    
            Object currentData =
              row.getCell(i).getCellTypeEnum() == CellType.STRING ? row.getCell(i).getStringCellValue() :
                row.getCell(i).getNumericCellValue();
            Object preData =
              preRow.getCell(i).getCellTypeEnum() == CellType.STRING ? preRow.getCell(i).getStringCellValue() :
                preRow.getCell(i).getNumericCellValue();
            rowDataList.add(String.valueOf(currentData));
            preDataList.add(String.valueOf(preData));
        }

        String rowDataStr = String.join(",", rowDataList);
        String preDataStr = String.join(",", preDataList);

        //判断是否合并单元格
        boolean curEqualsPre = rowDataStr.equals(preDataStr);
        //判断前一个和后一个相同 并且 标识位相同
        if (curEqualsPre) {
    
    
            lastRow = curRowIndex;
            mergeCount++;
        }
        //excel过程中合并
        if (!curEqualsPre && mergeCount > 1) {
    
    
            mergeSheet(firstRow, lastRow, mergeColumnIndex, sheet);
            mergeCount = 1;
        }

        //excel结尾处合并
        if (mergeCount > 1 && total == curRowIndex) {
    
    
            mergeSheet(firstRow, lastRow, mergeColumnIndex, sheet);
            mergeCount = 1;
        }

        if (!curEqualsPre) {
    
    
            firstRow = curRowIndex;
        }

    }

    private void mergeSheet(int firstRow, int lastRow, int[] mergeColumnIndex, Sheet sheet) {
    
    
        for (int colNum : mergeColumnIndex) {
    
    
            firstCol = colNum;
            lastCol = colNum;
            CellRangeAddress cellRangeAddress = new CellRangeAddress(firstRow, lastRow, firstCol, lastCol);
            sheet.addMergedRegion(cellRangeAddress);
        }
    }

    /**
     * 单元格合并类
     */
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class CellMerge {
    
    
        private int[] mergeColumIndex;
        private int[] mergeRuleColumIndex;
    }

    /**
     * 设置单元格合并规则
     * @param mergeColumIndex
     * @param mergeRuleColumIndex
     * @return
     */
    public static CellMerge setCellMerge(int[] mergeColumIndex,int[] mergeRuleColumIndex){
    
    
        EasyExcelUtil excelUtil = new EasyExcelUtil();
        CellMerge cellMerge = excelUtil.new CellMerge();
        cellMerge.setMergeColumIndex(mergeColumIndex);
        cellMerge.setMergeRuleColumIndex(mergeRuleColumIndex);
        return cellMerge;
    }
}

Paso 3: Simular datos de prueba

  • Crear clase de entidad de estudiante

/**
 * @ColumnWidth(20) 这个是设置单元格长度的
 * @ExcelProperty("")  这个是设置表格头部的
 * @author lixiang
 * @date 2023/5/26 16:30
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@ColumnWidth(20)
public class Student {
    
    

    @ExcelProperty("年级")
    private String gradeName;

    @ExcelProperty("班级")
    private String className;

    @ExcelProperty("姓名")
    private String name;

    @ExcelProperty("年龄")
    private Integer age;

    @ExcelProperty("性别")
    private String sex;

}

  • simular datos de estudiantes
/**
 * @author lixiang
 * @date 2023/5/26 16:13
 */
@Service
public class StudentService {
    
    

    List<String> classNames;

    List<String> gradeNames;

    {
    
    
        classNames = new ArrayList<>();
        classNames.add("一班");
        classNames.add("二班");
        classNames.add("三班");
        gradeNames = new ArrayList<>();
        gradeNames.add("2017级");
        gradeNames.add("2018级");
        gradeNames.add("2019级");
    }

    public List<Student> getStudentData(){
    
    
        List<Student> list = new ArrayList<>();
        for (int i = 1; i < 20; i++) {
    
    
            Student student = new Student();
            student.setName("李祥"+i);
            student.setClassName(getClassName());
            student.setGradeName(getGradeName());
            student.setSex("男");
            student.setAge(18);
            list.add(student);
        }

        return list;
    }

    /**
     * 获取班级
     * @return
     */
    private String getClassName(){
    
    
        Random rand = new Random();
        return classNames.get(rand.nextInt(classNames.size()));
    }

    /**
     * 获取年级
     * @return
     */
    private String getGradeName(){
    
    
        Random rand = new Random();
        return gradeNames.get(rand.nextInt(gradeNames.size()));
    }
}
/**
 * @author lixiang
 * @date 2023/5/26 16:00
 */
@RestController
@RequestMapping("/excel")
public class ExcelController {
    
    

    @Autowired
    private StudentService  studentService;

    @GetMapping("/create")
    public List<Student> create(){
    
    

        List<Student> studentData = studentService.getStudentData();

        return  studentData;
    }

}

inserte la descripción de la imagen aquí

Paso 4: En base a estos datos, los exportamos a excel

/**
 * @author lixiang
 * @date 2023/5/26 16:00
 */
@RestController
@RequestMapping("/excel")
public class ExcelController {
    
    

    @Autowired
    private StudentService  studentService;

    @GetMapping("/create")
    public void create(HttpServletResponse response) throws Exception{
    
    

        List<Student> studentData = studentService.getStudentData();
        String fileName  =  "学生列表";
        /**
         * 第一个参数:HttpServletResponse
         * 第二个参数:文件名称
         * 第三个参数:数据集
         * 第四个参数:数据集实体class对象
         */
        EasyExcelUtil.createExcel(response,fileName,studentData, Student.class);
    }

}

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

Bien, ahora queremos fusionar celdas y fusionar las celdas de la misma clase en el mismo grado.

    @GetMapping("/create")
    public void create(HttpServletResponse response) throws Exception{
    
    

        List<Student> studentData = studentService.getStudentData();
        String fileName  =  "学生列表";
        /**
         * 第一个参数:HttpServletResponse
         * 第二个参数:文件名称
         * 第三个参数:数据集
         * 第四个参数:数据集实体class对象
         * 第五个参数:合并单元格的规则
         *  EasyExcelUtil.setCellMerge(meargeColl, meargeColl);
         *  第一个参数 是 我们要合并的那些列,第二个是合并的规则。
         */
        int[] meargeColl = new int[]{
    
    0,1};
        EasyExcelUtil.CellMerge cellMerge = EasyExcelUtil.setCellMerge(meargeColl, meargeColl);
        EasyExcelUtil.createExcel(response,fileName,studentData, Student.class,cellMerge);
    }

inserte la descripción de la imagen aquí

Tenga en cuenta que al fusionar, los datos deben ordenarse para garantizar que los datos del mismo grado y clase estén todos juntos. Ahora ordenamos los datos primero.

  • Definir la herramienta de clasificación china
/**
 * @author lixiang
 * @date 2023/5/26 17:14
 */
public class ChineseNumberUtil {
    
    
    public static int chineseNumber2Int(String chineseNumber){
    
    
        int result = 0;
        int temp = 1;//存放一个单位的数字如:十万
        int count = 0;//判断是否有chArr
        char[] cnArr = new char[]{
    
    '一','二','三','四','五','六','七','八','九'};
        char[] chArr = new char[]{
    
    '十','百','千','万','亿'};
        for (int i = 0; i < chineseNumber.length(); i++) {
    
    
            boolean b = true;//判断是否是chArr
            char c = chineseNumber.charAt(i);
            for (int j = 0; j < cnArr.length; j++) {
    
    //非单位,即数字
                if (c == cnArr[j]) {
    
    
                    if(0 != count){
    
    //添加下一个单位之前,先把上一个单位值添加到结果中
                        result += temp;
                        temp = 1;
                        count = 0;
                    }
                    // 下标+1,就是对应的值
                    temp = j + 1;
                    b = false;
                    break;
                }
            }
            if(b){
    
    //单位{'十','百','千','万','亿'}
                for (int j = 0; j < chArr.length; j++) {
    
    
                    if (c == chArr[j]) {
    
    
                        switch (j) {
    
    
                            case 0:
                                temp *= 10;
                                break;
                            case 1:
                                temp *= 100;
                                break;
                            case 2:
                                temp *= 1000;
                                break;
                            case 3:
                                temp *= 10000;
                                break;
                            case 4:
                                temp *= 100000000;
                                break;
                            default:
                                break;
                        }
                        count++;
                    }
                }
            }
            if (i == chineseNumber.length() - 1) {
    
    //遍历到最后一个字符
                result += temp;
            }
        }
        return result;
    }
}
  • servicio para ordenar
public List<Student> getStudentData(){
    
    
        List<Student> list = new ArrayList<>();
        for (int i = 1; i < 20; i++) {
    
    
            Student student = new Student();
            student.setName("李祥"+i);
            student.setClassName(getClassName());
            student.setGradeName(getGradeName());
            student.setSex("男");
            student.setAge(18);
            list.add(student);
        }
  			//排序逻辑
        list.sort((s1,s2)->{
    
    
            Integer flag = Integer.parseInt(s1.getGradeName().substring(0,4)) - Integer.parseInt(s2.getGradeName().substring(0,4));
            if(flag == 0){
    
    
                return Integer.compare(ChineseNumberUtil.chineseNumber2Int(s1.getClassName().substring(0,2)),
                        ChineseNumberUtil.chineseNumber2Int(s2.getClassName().substring(0,2)));
            }
            return flag;
        });
        return list;
    }

inserte la descripción de la imagen aquí

OK, podemos fusionar después de ordenar.

				int[] meargeColl = new int[]{
    
    0,1};
        EasyExcelUtil.CellMerge cellMerge = EasyExcelUtil.setCellMerge(meargeColl, meargeColl);
        EasyExcelUtil.createExcel(response,fileName,studentData, Student.class,cellMerge);

inserte la descripción de la imagen aquí

Vemos que las mismas filas se han fusionado, bien, hemos terminado con la integración de Excel.

Supongo que te gusta

Origin blog.csdn.net/weixin_47533244/article/details/130891333
Recomendado
Clasificación