SpringBoot 实现 Excel 导入导出,百万数据量,不在话下!

👉 这是一个或许对你有用的社群

🐱 一对一交流/面试小册/简历优化/求职解惑,欢迎加入「芋道快速开发平台」知识星球。下面是星球提供的部分资料: 

634d71e3052e965de227ae8317e5a33d.gif

👉这是一个或许对你有用的开源项目

国产 Star 破 10w+ 的开源项目,前端包括管理后台 + 微信小程序,后端支持单体和微服务架构。

功能涵盖 RBAC 权限、SaaS 多租户、数据权限、商城、支付、工作流、大屏报表、微信公众号等等功能:

  • Boot 地址:https://gitee.com/zhijiantianya/ruoyi-vue-pro

  • Cloud 地址:https://gitee.com/zhijiantianya/yudao-cloud

  • 视频教程:https://doc.iocoder.cn

来源:zzuhkp.blog.csdn.net/
article/details/125097026

15bd0d99af07cd3a17e65a6c9d573330.jpeg


原来

Excel 与导出是项目中的一个功能很容易导入中的 Excel,由于 Java 导出。poi,在高处常用导入与运行 OOM 或完全使用 Excel,基于 Easy项目。

简化计算功能,轻松将Excel与解决对象简化了一个API映射Excel之间的简单关系,几行代码除了实现复杂的导入功能,通过导入了。

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro

  • 视频教程:https://doc.iocoder.cn/video/

EasyExcel 问题

一切都是美好的,不过经常把Excel导入与发布的发现,一样的Excel还是没有完美的。

首先,导入与导出的 Excel 本质是将 Excel 文件内容与 Java 对象之间做一个功能映射,轻松将 Excel 的只是在这之间多转换。如果项目中的 Excel 导入与导出比较,会大量的样板式代码,使用体验类似于 JDBC。

另外,还会附带另外一种校验功能,这是 Easy Excel 不支持的功能。

而目前的 spring boot 已经成为必备的 Java 开发框架,excel 也没有进行整合。

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/yudao-cloud

  • 视频教程:https://doc.iocoder.cn/video/

分析与解决

导入内容和导出方法通常会发生在 Web 环境中,对于 Spring MVC 来说,可以将请求信息转换为各种类型的控制器方法参数,将控制器返回值作为客户端支持的。

如果使用自定义板的控制器参数接收 Excel 文件内容,将方法控制器的方法返回值转换为 Excel 文件,可以直接从 Excel 导入与导出时的样式代码。

另外在将转换为控制器方法参数时还可以加入自定义请求的逻辑。

Excel 与外接样板代码、看问题的业务逻辑,这里可以单独拿出来,我在 EasyExcel 的基础上板式项目中封装了一个 easyexcel-spring-booter 的项目,导入了 EasyExcel 上手的尺寸窗帘,对用户而言只需要使用 EasyExcel 定义的注解提供映射关系就可以了,适用于场景的简单导入关系。

项目代码已上传:

https://github.com/zzuhkp/easyexcel-spring-boot-starter

下面就来看看如何使用吧。

Spring Boot Excel 导入与导出

引入依

首先需要依赖,坐标如下。

<dependency>
    <groupId>com.zzuhkp</groupId>
    <artifactId>easyexcel-spring-boot-starter</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

很可能是当前项目的物品传输中央,需要的小伙伴可以自行上传到仓库或直接把代码嵌入自己的仓库。

Excel导入

首先看下要导入的Excel内容吧。

4360ca269cc2eb262d4cb0ff90c7588f.png

为了接收 Excel 文件内容,我们需要定义一个 Model 类。

@Data
public class DemoData {

    @ExcelProperty(index = 0)
    private Integer integer;

    @ExcelProperty(index = 1)
    private String string;

    @ExcelProperty(index = 2)
    private Date date;
}
导入基本功能

然后使用List<T>参数接收。

@PostMapping("/list/obj")
public List<DemoData> listObj(@ExcelParam List<DemoData> list) {
    return list;
}

注意参数前添加了@ExcelParam 注解,使用标识Excel文件参数。这样,一个导入实现功能了,是不是很简单呢?

下接收名称为文件的格式不作为 Excel 文件修改,如果满足还可以默认。

@ExcelParam(value = "file", required = true)
进阶导入功能

例如,Excel 这个对象可能是我们比较有趣的对象的元数据,Excel 是第几行记录产生的,这个对象的字段几列,这时我们可以使用ReadRows<T>接收。

@PostMapping("/list/rows")
public ReadRows<DemoData> readRows(@ExcelParam ReadRows<DemoData> readRows) {
    return readRows;
}

ReadRows 使用两个字段记录行映射关系与列映射关系。

public class ReadRows<T> {

    private ExcelReadHeadProperty excelReadHeadProperty;

    private List<ReadRow<T>> rows;
}

ExcelReadHeadProperty是Excel自带的类,列映射关系的元数据。ReadRow是自定义的类,表示Easy行映射关系的元数据。

看下ReadRow定义吧。

public class ReadRow<T> {

    // 行索引,从 0 开始
    private final Integer rowIndex;

    // 行记录对应对象
    private final T data;
}

使用ExcelReadHeadProperty获取字段的索引列的示例。

// 对象字段名称 -> 从 0 开始的列索引
Map<String, Integer> fieldColumnIndexMap = readRows.getExcelReadHeadProperty().getHeadMap().values()
        .stream().collect(Collectors.toMap(Head::getFieldName, Head::getColumnIndex));

Excel 导出

这里对Excel的导出进行了简单的支持。将List<T>定义为controller方法返回值认知。

@ExcelResponse
@GetMapping("/list/download")
public List<DemoData> downloadList() {
    return Arrays.asList(new DemoData(1, "hello", new Date()), new DemoData(2, "excel", new Date()));
}

需要注意的是使用@ExcelResponse注解表示响应内容为 Excel 文件。默认情况下,下载的文件名称为default.xlxs,写入名称为 Sheet1 的工作表中。如果不满足需求可以修改。

@ExcelResponse(fileName = "测试文件", sheetName = "工作表1")

Excel导入参数校验

的参数是滑Excel的导入功能,在这里进行了常用的支持,使用如荔枝般顺顺的弹簧靴。

恰巧

与spring boot解使用方式一样,将@Validated @Valid注添加到@ExcelParam参数上即可。

@PostMapping("/list/obj")
public List<DemoData> listObj(@ExcelParam @Validated List<DemoData> list) {
    return list;
}
智能规则定义
Bean Validation 定义验证规则

下框架使用JSR-303 Bean Validation规范定义的校验可解校验,需要手动情况spring-boot-starter-validation,通过设置环境变量默认值easyexcel.validator.default.enable=false

@Data
public class DemoData {

    @NotNull(message = "参数不能为空")
    private Integer integer;

    private String string;

    private Date date;
}

还可以自定义另外对对象表示感谢。

... 省略其他元注解
@Constraint(validatedBy = {DemoDataValid.DemoDataValidator.class})
public @interface DemoDataValid {
  ... 省略注解属性
  
    class DemoDataValidator implements ConstraintValidator<DemoDataValid, DemoData> {

        @Override
        public boolean isValid(DemoData value, ConstraintValidatorContext context) {
            context.disableDefaultConstraintViolation();
            context.buildConstraintViolationWithTemplate("测试对象校验").addConstraintViolation();
            return false;
        }
    }

}
@DemoDataValid
public class DemoData {
    ... 省略属性
}
ExcelValidator 接口定义校验规则

Bean Validation注解只能定义为对某个对象或对象,如果需要所有的对象进行验证,然后可以实现框架定义的ExcelValidator接口,将实现 Bean。

这个接口定义如下。

public interface ExcelValidator<T> {

    ExcelValidErrors validate(ReadRows<T> readRows);
}

ExcelValidErrors接收确认的错误信息,分别用于使用接口ExcelValidObjectErrorExcelValidFieldError接口定义行错误信息和单元格错误信息。

public class ExcelValidErrors {
 // 行错误信息或单元格错误信息列表
    private final List<ExcelValidObjectError> errors;
}

public interface ExcelValidObjectError {

    // 获取行号,从 1 开始
    Integer getRow();

    // 获取错误消息
    String getMessage();
}

public interface ExcelValidFieldError extends ExcelValidObjectError {

    // 获取列,从 1 开始
    Integer getColumn();
}

例如,如果需要对所有的 DemoData 替换整数字段的值不能重复,可以使用替换的代码。

@Component
public class CustomExcelValidator implements ExcelValidator<DemoData> {
    @Override
    public ExcelValidErrors validate(ReadRows<DemoData> readRows) {
        ExcelValidErrors errors = new ExcelValidErrors();

        Map<Integer, List<ReadRow<DemoData>>> group = readRows.getRows().stream()
                .collect(Collectors.groupingBy(item -> item.getData().getInteger()));

        for (Map.Entry<Integer, List<ReadRow<DemoData>>> entry : group.entrySet()) {
            if (entry.getValue().size() > 1) {
                for (ReadRow<DemoData> readRow : entry.getValue()) {
                    errors.addError(new DefaultExcelObjectError(readRow.getRowIndex() + 1, "参数重复"));
                }
            }
        }
        return errors;
    }
}
校验结果接收

与 Spring MVC 类似设计,这里也提供了接收会话结果的方式。

异常智能手机结果

开启异常方式后,如果信息通知结果中包含错误,错误信息封装ExcelValidException,可以通过异常异常和异常收集。

@RestControllerAdvice
public class GlobalExceptionControllerAdvice {

    @ExceptionHandler(ExcelValidException.class)
    public String handleException(ExcelValidException e) {
        ExcelValidErrors errors = e.getErrors();
        return JSON.toJSONString(errors);
    }
}
控制器方法参数验证结果

如果不想通过异常信息的方式接收到错误的信息,还可以将其添加到@ExcelParam参数的背面,示例代码如下。

@PostMapping("/list/obj")
public List<DemoData> listObj(@ExcelParam @Validated List<DemoData> list, ExcelValidErrors errors) {
    if (errors.hasErrors()) {
        String messages = errors.getAllErrors().stream().map(ExcelValidObjectError::getMessage).collect(Collectors.joining(" | "));
        throw new RuntimeException("发现异常:" + messages);
    }
    return list;
}

总结

easyexcel-spring-boot-starter应用了前面文章的各种 Spring 知识量并不大,对具体的小伙伴可以自行统一代码。由于这个框架把 Excel 中的所有数据收集到内存中,因此比较适合一些比较简单的场景。


欢迎加入我的知识星球,全面提升技术能力。

👉 加入方式,长按”或“扫描”下方二维码噢

5dbf74a621307bdc411f99ac53690c10.png

星球的内容包括:项目实战、面试招聘、源码解析、学习路线。

0b8288335b14fbe2d95ed425ae3718bc.png

fb4c2678a94d28045931f94bb892dad7.png479d7fb31a87284e4510a81f178ecc2c.pngd63298ecf94e8ebead6b86e5452c71bf.png4620260ebf95ea42e20a1427a8c1e060.png

文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot可以通过使用Apache POI库来实现Excel导入导出。以下是实现步骤: 1. 添加依赖 在pom.xml文件中添加以下依赖: ``` <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>4.1.2</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.1.2</version> </dependency> ``` 2. 实现导出 创建一个ExcelUtil类,实现导出功能。以下是示例代码: ``` public class ExcelUtil { public static void export(List<User> userList, OutputStream outputStream) throws IOException { XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet = workbook.createSheet("User List"); // 创建表头 XSSFRow headerRow = sheet.createRow(); headerRow.createCell().setCellValue("ID"); headerRow.createCell(1).setCellValue("Name"); headerRow.createCell(2).setCellValue("Age"); // 填充数据 int rowNum = 1; for (User user : userList) { XSSFRow row = sheet.createRow(rowNum++); row.createCell().setCellValue(user.getId()); row.createCell(1).setCellValue(user.getName()); row.createCell(2).setCellValue(user.getAge()); } // 输出Excel文件 workbook.write(outputStream); workbook.close(); } } ``` 3. 实现导入 创建一个ExcelUtil类,实现导入功能。以下是示例代码: ``` public class ExcelUtil { public static List<User> importFile(InputStream inputStream) throws IOException { List<User> userList = new ArrayList<>(); XSSFWorkbook workbook = new XSSFWorkbook(inputStream); XSSFSheet sheet = workbook.getSheetAt(); // 读取数据 for (int i = 1; i <= sheet.getLastRowNum(); i++) { XSSFRow row = sheet.getRow(i); User user = new User(); user.setId((int) row.getCell().getNumericCellValue()); user.setName(row.getCell(1).getStringCellValue()); user.setAge((int) row.getCell(2).getNumericCellValue()); userList.add(user); } workbook.close(); return userList; } } ``` 以上就是使用Spring Boot实现Excel导入导出的步骤。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值