Excel下载(easyExcel)




一 框架及版本

  • springboot: 2.1.3.RELEASE
  • hutool工具
  • easyExcel
 <dependency>
     <groupId>com.alibaba</groupId>
     <artifactId>easyexcel</artifactId>
     <version>2.1.4</version>
 </dependency>

二 数据准备

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {

    @ExcelProperty(value = {"年级"}, index = 0)
    private String grade;

    @ExcelProperty(value = {"姓名"}, index = 1)
    private String name;

    @ExcelProperty(value = {"年龄"}, index = 2)
    private Integer age;

    @ExcelProperty(value = {"性别"}, index = 3)
    private String sex;

    @ExcelProperty(value = {"综合素质评价"}, index = 4)
    @ColumnWidth(50)
    private String evaluate;

    @ExcelProperty(value = {"综合评分"}, index = 5)
    @ColumnWidth(20)
    private String score;

}
public class DataReady {

    public static List<Student> listStudent() {
        // 综合素质评价
        List<String> evaluateList = evaluateList();

        List<Student> students = new ArrayList<>();
        students.add(new Student("三年一班", "小东", 12, "男", evaluateList.get(0), "优"));
        students.add(new Student("三年一班", "小南", 12, "男", evaluateList.get(1), "优"));
        students.add(new Student("三年二班", "小西", 13, "男",evaluateList.get(2), "优"));
        students.add(new Student("三年二班", "小北", 12, "男",evaluateList.get(3), "优"));
        students.add(new Student("三年二班", "小红", 12, "女",evaluateList.get(4), "优"));
        students.add(new Student("三年三班", "小独", 12, "男",evaluateList.get(5), "优"));
        return students;
    }

    private static List<String> evaluateList() {
        List<String> strings = new ArrayList<>();
        strings.add("你活泼乐观,自信心强,尊敬老师,是你的最大优点,作业能按时完成,有强烈的好奇心,可惜的是你上课管不住自己,不守纪律,老师提出问题不经过深思熟虑");
        strings.add("该生在校期间学习态度端正,成绩优良");
        strings.add("积极参与各项实践活动,全面的锻炼自己。");
        strings.add("你是个天性好动的男孩。想到你,浮现在老师眼前的是你积极劳动、礼貌待人的身影。");
        strings.add("热情活泼,全面发展,对于自己喜欢的工作,能投入极大的热情去做,哪怕再苦再累,也不计较。");
        strings.add("好");
        return strings;
    }
}

三 基础下载

效果
在这里插入图片描述


EasyExcelController

@GetMapping("/download")
public void download(HttpServletResponse response) throws IOException {
    service.download(response);
}

EasyExcelService

/**
 * 基础下载
 */
void download(HttpServletResponse response) throws IOException;

EasyExcelServiceImpl

/**
 * 基础下载
 */
@Override
public void download(HttpServletResponse response) throws IOException {

    String message = "下载文件失败";
    String filename = "学生信息.xlsx";

    try {
        // 设置响应头
        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "utf-8"));
        response.setContentType("application/octet-stream;charset=UTF-8"); // 类型
        response.setCharacterEncoding("utf-8");

        // 获取导出数据
        List<Student> students = DataReady.listStudent();

        // 数据导出
        EasyExcel.write(response.getOutputStream(), Student.class)
                .sheet("Sheet1").doWrite(students);

    } catch (Exception e) {
        e.printStackTrace();
        // 重置response
        response.reset();
        response.setContentType("application/json");
        response.setCharacterEncoding("utf-8");
        response.getWriter().println(JsonUtil.writeValueAsString(message));
    }
}

测试
浏览器访问: http://localhost:8060/easyExcel/download 下载Excel


​四 单元格样式设置

目标

  • 单元格字体居中
  • 超出单元格部分,自适应高度显示

效果
在这里插入图片描述


自定义样式

public class ExcelUtils {

    /**
     * 单元格水平样式策略
     */
    public static HorizontalCellStyleStrategy setHorizontalCellStyleStrategy(){
        // 头部样式
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();

        // 内容样式
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        contentWriteCellStyle.setWrapped(true); // 数据超出换行
        contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); // 垂直居中
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); // 水平居中

        // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现
        return new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
    }
    
}

注册自定义样式
在这里插入图片描述


五 单元格行合并

目标

  • 将同一年级的行进行合并

效果
在这里插入图片描述

1 合并统计

统计“指定列“ 的“哪几行”需要进行合并


使用Map集合进行统计

Map<String, List<RowRange>> merStrategyMap 
  • key: 需要合并的列
  • value: 指定列中需要合并的行

每一个列有多个 rowRange, 每个rowRange表示这个列合并行的开始和结束的位置

在这里插入图片描述

RowRange

/**
 * 用于记录 Excel某一列, 某一类型的
 * 合并的开始和结束位置
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class RowRange {

    /**
     * 行合并开始位置
     */
    private int start;

    /**
     * 行合并结束位置
     */
    private int end;
}

EasyExcelServiceImpl

/**
 * 添加合并策略
 */
private Map<String, List<RowRange>> addMerStrategy(List<Student> students) {

    // key: 表示需要合并的列  value: 表示该列需要合并的行集合
    Map<String, List<RowRange>> strategyMap = new HashMap<>();

    // 前一条数据。 (用于判断是否需要合并)
    Student preStudent = null;
    for (int i = 0; i < students.size(); i++) {

        Student student = students.get(i);
        if (preStudent != null) {
            // 年级合并
            if (student.getGrade().equals(preStudent.getGrade())) {
                fillStrategyMap(strategyMap, "0", i);
            }
        }
        preStudent = student;
    }

    return strategyMap;
}
/**
 * 计算需要合并的行
 *
 */
public static void fillStrategyMap(Map<String, List<RowRange>> strategyMap, String key, int index) {

    List<RowRange> rowRangeList = strategyMap.get(key) == null ? new ArrayList<>() : strategyMap.get(key);

    // 判断是否新增分段
    boolean flag = false;

    for (RowRange dto : rowRangeList) {
        //分段list中是否有end索引是上一行索引的,如果有,则索引+1
        if (dto.getEnd() == index) {
            dto.setEnd(index + 1);
            flag = true;
        }
    }
    //如果没有,则新增分段
    if (!flag) {
        rowRangeList.add(new RowRange(index, index + 1));
    }
    strategyMap.put(key, rowRangeList);
}

2 合并策略类

在上一步已经统计出了,哪些列的行需要进行合并, 具体的合并工作在这个类完成

/**
 * 合并类
 */
public class MergeStrategy  extends AbstractMergeStrategy {

    // Map<列, 要进行合并的行>
    private Map<String, List<RowRange>> strategyMap;

    public MergeStrategy(Map<String, List<RowRange>> strategyMap) {
        this.strategyMap = strategyMap;
    }

    /**
     * 每一个单元格都会进入到该方法
     *    第一个单元格进入到该方法时就进行合并操作,其余单元格进入到该方法时不进行合并操作
     */
    @Override
    protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {

        int rowIndex = cell.getRowIndex();
        int columnIndex1 = cell.getColumnIndex();

        if (rowIndex == 1 && columnIndex1 == 0) {
            for (Map.Entry<String, List<RowRange>> entry : strategyMap.entrySet()) {
                // 哪一列的行需要进行合并
                int columnIndex = Integer.parseInt(entry.getKey());
                entry.getValue().forEach(rowRange -> {
                    // 对行进行合并(四个参数: 行开始 行结束 列开始 列结束)
                    sheet.addMergedRegionUnsafe(new CellRangeAddress(rowRange.getStart(), rowRange.getEnd(), columnIndex, columnIndex));
                });
            }
        }

    }
}

关于 if (rowIndex == 1 && columnIndex1 == 0) 的说明
在这里插入图片描述

3 注册合并策略

EasyExcelServiceImpl
在这里插入图片描述


六 行高设置

1 非动态设置行高

效果 行高发生了变化
在这里插入图片描述


在实体中添加注解即可设置
在这里插入图片描述

注意
对超出单元格部分的数据不会自适应高度显示了。这是正常的,因为设置了行高将单元格的高度固定了。
在这里插入图片描述

2 动态设置行高

效果: 行高发生变化且超出单元格部分自适应高度显示
在这里插入图片描述

思路: 某一行中,如果某个单元格数据超出了单元格则不设置该行的行高,则该行的行高会根据 “四 单元格样式设置” 中的配置进行自适应高度显示


行高样式策略类

/**
 * 自定义行高
 * 注意: 实体类上不可加 @HeadRowHeight(value = 30) 注解,不然此方法失效(会进入到SimpleRowHeightStyleStrategy)
 */
public class EvaSysRowHeightStyleStrategy extends AbstractRowHeightStyleStrategy {

    private Map<Integer, Integer> map = new HashMap<>();
    // 列数(用于判断当前行是否执行结束了)
    private  Integer cellNum;
    // 行高
    private static final Float height = 30f;
    // 需要设置行高的限制值(如果数据长度 < heightLimit 则需要设置行高,否则不需要)
    private  static  final Integer heightLimit = 40;


    public EvaSysRowHeightStyleStrategy(int cellNum) {
        this.cellNum = cellNum;
    }

    /**
     * 设置标题的行高
     */
    @Override
    protected void setHeadColumnHeight(Row row, int i) {
        row.setHeightInPoints((float)40);
    }

    @Override
    protected void setContentColumnHeight(Row row, int i) {

        row.forEach(cell -> {

            // 设置行高和解决数据显示不完整问题
            // 当前行号
            int currentNum = cell.getRow().getRowNum();
            // 当前数据的长度
            Integer currentLength = getDataLength(cell);
            // 当前单元格列数
            int currentCellNum = cell.getColumnIndex()+1;
            // 如果已经是最后一列,则判断是否需要设置行高
            if (cellNum == currentCellNum) {
                // 如果数据最大长度 <= 20 则设置行高
                Integer max = map.get(currentNum);
                max = max > currentLength? max: currentLength;
                if(max <= heightLimit) {
                    cell.getRow().setHeightInPoints(height);
                }
            } else {
                // 获取当前行最大的数据长度。因为可能是新的行,获取数据时可能为null,如果为null,我们就置max为0
                Integer max = map.get(currentNum) == null? 0: map.get(currentNum);
                // 比较获取最大的数据长度更新max的值
                max = max > currentLength? max: currentLength;
                map.put(currentNum, max);
            }

        });

    }

    /**
     * 获取数据长度
     */
    private Integer getDataLength(Cell cell) {
        CellType type = cell.getCellTypeEnum();
        String data;
        switch (type) {
            case STRING: data = cell.getStringCellValue(); break;
            case FORMULA: data = cell.getCellFormula(); break;
            case NUMERIC: data = String.valueOf(cell.getNumericCellValue()); break;
            default: data = "";
        }
        return data.length();

    }
}

注: 实体类中不可加 @HeadRowHeight, 不然该策略类会失效(会使用 SimpleRowHeightStyleStrategy 进行行高的设置)


注册策略类
EasyExcelServiceImpl
在这里插入图片描述

Java可以使用EasyExcel框架将数据下载Excel表格。EasyExcel是阿里巴巴开源的一个Excel处理框架,以使用简单、节省内存著称。它能够快速、简洁地解决大文件内存溢出的问题,让你在不用考虑性能和内存等因素的情况下,快速完成Excel的读取和写入等功能。 使用EasyExcel进行下载数据到Excel表格的步骤如下: 1. 引入EasyExcel的依赖:在你的Java项目中,需要添加EasyExcel的依赖,可以通过Maven或Gradle进行添加。 2. 创建ExcelWriter对象:使用EasyExcel的API,创建一个ExcelWriter对象,用于写入数据到Excel表格。 3. 定义Excel表格的表头:通过ExcelWriter对象的write方法,传入表头数据,并指定表格的sheet名称和表头的类型。 4. 写入数据行:使用ExcelWriter对象的write方法,传入数据行的集合,将数据写入到Excel表格的数据区域。 5. 关闭ExcelWriter对象:在写入完数据后,需要关闭ExcelWriter对象,以释放相关资源。 这样,你就可以通过Java使用EasyExcel框架下载数据到Excel表格了。详细的使用方法可以参考EasyExcel官方文档提供的示例和文档。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [使用java解析和读取excel表格(EasyExcel的简单使用)](https://blog.csdn.net/weixin_72979483/article/details/128676578)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [48、数据导出到ExceleasyExcel)](https://blog.csdn.net/qq_45695621/article/details/128403615)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值