SpringBoot 项目优雅实现 Excel 导入导出功能

点击上方“Java基基”,选择“设为星标”

做积极的人,而不是积极废人!

每天 14:00 更新文章,每天掉亿点点头发...

源码精品专栏

 

来源:zzuhkp.blog.csdn.net/

article/details/125097026

46c200694fc4955f8adae9d086bd4e21.jpeg


原来

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

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

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

  • 项目地址:https://gitee.com/zhijiantianya/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://gitee.com/zhijiantianya/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内容吧。

df608d7ef6cd006c71890b08526a2f2f.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 中的所有数据收集到内存中,因此比较适合一些比较简单的场景。



欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢

c2ffaf99d9006f2803ef17ac30fc094f.png

已在知识星球更新源码解析如下:

a6c99d4fc3a382db71073f30b5681784.jpeg

734ae90a3b60010c53fe6b7f7e725cd4.jpeg

011338a057da05d11bd8ac34456354bb.jpeg

0a856e657e72d65e1e8b8227cef4cf8d.jpeg

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

提供近 3W 行代码的 SpringBoot 示例,以及超 6W 行代码的电商微服务项目。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值