Spring Boot集成EasyPoi实现导入导出操作


参考博客
1.官网

Spring Boot集成EasyPoi实现导入导出操作

0 简要说明

Excel自适应xls和xlsx两种格式,word只支持docx模式
主要特点

1.设计精巧,使用简单
2.接口丰富,扩展简单
3.默认值多,write less do more
4.spring mvc支持,web导出可以简单明了

在这里插入图片描述

1 环境搭建

1.1 项目目录

在这里插入图片描述

1.2 依赖管理

        <!--Spring 环境-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>xerces</groupId>
            <artifactId>xercesImpl</artifactId>
            <version>2.9.1</version>
        </dependency>
        <!--MySQL 驱动包-->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>8.0.31</version>
        </dependency>

        <!--自动配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

        <!--实体类优化-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!--单元测试-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <!--接口平台-->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-boot-starter</artifactId>
            <version>2.0.7</version>
        </dependency>

        <!--commons-lang3工具包-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.12.0</version>
        </dependency>

        <!--Mybatis Plus 扩展包-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-extension</artifactId>
            <version>3.5.1</version>
        </dependency>

        <!--Mybatis Plus 依赖包-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>

        <!--easypoi-->
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-spring-boot-starter</artifactId>
            <version>4.4.0</version>
        </dependency>

        <!--easyexcel-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.1.1</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.9.1</version>
        </dependency>

        <!--接口平台-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-boot-starter</artifactId>
            <version>3.0.0</version>
        </dependency>

2.3 关于swagger处理

依赖

        <!--接口平台-->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-boot-starter</artifactId>
            <version>2.0.7</version>
        </dependency>
        <!--接口平台-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-boot-starter</artifactId>
            <version>3.0.0</version>
        </dependency>

配置类

package com.geekmice.springbootselfexercise.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

/**
 * @BelongsProject: spring-boot-scaffold
 * @BelongsPackage: com.geekmice.sbhelloworld.com.geekmice.sbpagehelper.config
 * @Author: pingmingbo
 * @CreateTime: 2023-07-30  15:45
 * @Description: TODO
 * @Version: 1.0
 */
@Configuration
public class Knife4jConfig {
    @Bean(value = "defaultApi2")
    public Docket customDocket() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.geekmice.springbootselfexercise.controller"))
                .build();
    }

    /**
     * 构建 api文档的详细信息函数
     * @return
     */
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("现货交易")
                .version("1.0.0")
                .description("现货交易详情")
                .contact(new Contact("geekmice","http://geekmice.cn","2437690868@qq.com"))
                .build();
    }
}

访问地址:http://localhost:端口号/doc.html
在这里插入图片描述

2.4 关于切面处理耗时

1 自定义注解
package com.geekmice.springbootselfexercise.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author PMB
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodExporter {
}
2 定义切面类
package com.geekmice.springbootselfexercise.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

/**
 * @BelongsProject: spring-boot-scaffold
 * @BelongsPackage: com.geekmice.com.geekmice.sbpagehelper.utils
 * @Author: pmb
 * @CreateTime: 2023-07-26  21:52
 * @Description: TODO
 * @Version: 1.0
 */
@Aspect
@Component
@Slf4j
public class MethodExporterAspect {
    @Around("@annotation(com.geekmice.springbootselfexercise.annotation.MethodExporter)")
    public Object methodExporter(ProceedingJoinPoint point) throws Throwable {
        long start = System.currentTimeMillis() / 1000;
        Object proceed = point.proceed();
        long end = System.currentTimeMillis() / 1000;
        log.info("【耗时:】{}s", (end - start));
        return proceed;
    }
}
3 如何使用

直接在控制层方法上面添加注解,调用接口即可生效

    @PostMapping(value = "uploadFileByEasyPoi")
    @MethodExporter
    @ApiOperation(value = "通过easypoi上传文件")
    public AjaxResult uploadFileByEasyPoi(@RequestPart MultipartFile file){
        userService.uploadFileByEasyPoi(file);
        return AjaxResult.success();
    }

在这里插入图片描述

2.5 核心导入操作

    @Override
    public void uploadFileByEasyPoi(MultipartFile file) {

        InputStream inputStream;
        try {
            inputStream = file.getInputStream();
        } catch (IOException e) {
            log.error("error msg 【{}】", e);
            throw new IllegalArgumentException(e);
        }
        try {
            List<UserDomain> result = ExcelImportUtil.importExcel(inputStream, UserDomain.class, new ImportParams());
            for (UserDomain userDomain : result) {
                log.info("导入数据:【{}】", userDomain.toString());
            }
            this.saveBatch(result);
            log.info("录入结束");
        } catch (Exception e) {
            log.error("error msg 【{}】", e);
            throw new IllegalArgumentException(e);
        }
    }

2.6 核心导出操作

ExcelExportUtil是easypoi里面工具类

    public void downloadFileByEasyPoi() {
        List<UserDomain> list = new ArrayList(16);
        for (int i = 0; i < 10; i++) {
            UserDomain item = UserDomain.builder().userName(RandomStringUtils.randomAlphabetic(6)).address(RandomStringUtils.randomAlphabetic(10))
                    .birthday(new Date())
                    .sex("男")
                    .build();
            list.add(item);
        }
        Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), UserDomain.class, list);
        FileOutputStream outputStream;
        try {
            outputStream = new FileOutputStream("D:\\easypoi.xlsx");
            workbook.write(outputStream);
        } catch (FileNotFoundException e) {
            log.error("error msg 【{}】", e);
            throw new IllegalArgumentException(e);
        } catch (IOException e) {
            log.error("error msg 【{}】", e);
            throw new IllegalArgumentException(e);
        }
    }

2 最佳实线

2.1 导入操作

1 实体类说明

关于注解说明
easypoi起因就是Excel的导入导出,最初的模板是实体和Excel的对应,model–row,filed–col 这样利用注解我们可以和容易做到excel到导入导出
经过一段时间发展,现在注解有5个类分别是
@Excel 作用到filed上面,是对Excel一列的一个描述
@ExcelCollection 表示一个集合,主要针对一对多的导出,比如一个老师对应多个科目,科目就可以用集合表示
@ExcelEntity 表示一个继续深入导出的实体,但他没有太多的实际意义,只是告诉系统这个对象里面同样有导出的字段
@ExcelIgnore 和名字一样表示这个字段被忽略跳过这个导导出
@ExcelTarget 这个是作用于最外层的对象,描述这个对象的id,以便支持一个对象可以针对不同导出做出不同处理

package com.geekmice.springbootselfexercise.domain;

import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.annotation.ExcelIgnore;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

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

/**
 * (User)实体类
 *
 * @author pingmingbo
 * @since 2023-08-06 09:51:28
 */
@Data
@ApiModel
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName(value = "user")
public class UserDomain implements Serializable {
    private static final long serialVersionUID = 723356122339609354L;
    /**
     * 编号
     */
    @ApiModelProperty(value = "编号")
    @ExcelIgnore
    @TableId(type = IdType.AUTO)
    private Long id;

    /**
     * 用户名
     */
    @ApiModelProperty(value = "用户名")
    @Excel(name = "用户名")
    @TableField(value = "user_name")
    private String userName;
    /**
     * 生日
     */
    @ApiModelProperty(value = "生日")
    @Excel(name="生日")
    @TableField(value = "birthday")
    private Date birthday;
    /**
     * 性别
     */
    @Excel(name = "性别")
    @ApiModelProperty(value = "性别")
    @TableField(value = "sex")
    private String sex;
    /**
     * 地址
     */
    @ApiModelProperty(value = "地址")
    @Excel(name = "地址")
    @TableField(value = "address")
    private String address;


}
2 业务层
public interface UserService extends IService<UserDomain> {

    void uploadFileByEasyPoi(MultipartFile file);
}

package com.geekmice.springbootselfexercise.service.impl;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.geekmice.springbootselfexercise.dao.UserDao;
import com.geekmice.springbootselfexercise.domain.UserDomain;
import com.geekmice.springbootselfexercise.service.UserService;
import com.sun.corba.se.impl.corba.ExceptionListImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * (User)表服务实现类
 *
 * @author pingmingbo
 * @since 2023-08-06 09:51:28
 */
@Service("userService")
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserDao, UserDomain> implements UserService {
    @Resource
    private UserDao userDao;

    @Override
    public void uploadFileByEasyPoi(MultipartFile file) {

        InputStream inputStream;
        try {
            inputStream = file.getInputStream();
        } catch (IOException e) {
            log.error("error msg 【{}】", e);
            throw new IllegalArgumentException(e);
        }
        try {
            List<UserDomain> result = ExcelImportUtil.importExcel(inputStream, UserDomain.class, new ImportParams());
            for (UserDomain userDomain : result) {
                log.info("导入数据:【{}】", userDomain.toString());
            }
            this.saveBatch(result);
            log.info("录入结束");
        } catch (Exception e) {
            log.error("error msg 【{}】", e);
            throw new IllegalArgumentException(e);
        }
    }
}
3 效果

在这里插入图片描述

JDBC Connection [HikariProxyConnection@880330951 wrapping com.mysql.cj.jdbc.ConnectionImpl@55e295a5] will not be managed by Spring
==> Preparing: INSERT INTO user ( user_name, sex, address ) VALUES ( ?, ?, ? )
==> Parameters: pDwITO(String), 男(String), gqrkCeEpHh(String)
==> Parameters: TvOJNo(String), 男(String), BsAivNwjhP(String)
==> Parameters: miTVeL(String), 男(String), SMZOmxceID(String)
==> Parameters: siFTKf(String), 男(String), LcBfUNnITp(String)
==> Parameters: KGnyWX(String), 男(String), JXPbQboTdH(String)
==> Parameters: RyZYiE(String), 男(String), TydYPZxLah(String)
==> Parameters: JrcAnl(String), 男(String), bCttkDXCAN(String)
==> Parameters: nYMiAc(String), 男(String), uGXhBfyKgK(String)
==> Parameters: nDgzmK(String), 男(String), ZunMUZSYXa(String)
==> Parameters: xdLspA(String), 男(String), CLNrrpNHPw(String)
2023-08-06 14:00:51.218 INFO 9244 — [nio-8081-exec-3] c.g.s.service.impl.UserServiceImpl : 录入结束
在这里插入图片描述

3 控制层
    @PostMapping(value = "uploadFileByEasyPoi")
    @MethodExporter
    @ApiOperation(value = "通过easypoi上传文件")
    public AjaxResult uploadFileByEasyPoi(@RequestPart MultipartFile file){
        userService.uploadFileByEasyPoi(file);
        return AjaxResult.success();
    }

2.2 导出操作

核心代码

    @Override
    public void downloadFileByEasyPoi() {
        List<UserDomain> list = new ArrayList(16);
        for (int i = 0; i < 10; i++) {
            UserDomain item = UserDomain.builder().userName(RandomStringUtils.randomAlphabetic(6)).address(RandomStringUtils.randomAlphabetic(10))
                    .birthday(new Date())
                    .sex("男")
                    .build();
            list.add(item);
        }
        Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), UserDomain.class, list);
        FileOutputStream outputStream;
        try {
            outputStream = new FileOutputStream("D:\\easypoi.xlsx");
            workbook.write(outputStream);
        } catch (FileNotFoundException e) {
            log.error("error msg 【{}】", e);
            throw new IllegalArgumentException(e);
        } catch (IOException e) {
            log.error("error msg 【{}】", e);
            throw new IllegalArgumentException(e);
        }
    }

2.3 大数据量处理

大数据导出是当我们的导出数量在几万,到上百万的数据时,一次从数据库查询这么多数据加载到内存然后写入会对我们的内存和CPU都产生压力,这个时候需要我们像分页一样处理导出分段写入Excel缓解Excel的压力 EasyPoi提供的是两个方法 *强制使用 xssf版本的Excel *

        <dependency>
            <groupId>xerces</groupId>
            <artifactId>xercesImpl</artifactId>
            <version>2.9.1</version>
        </dependency>

importExcelBySax方法


    /**
     * Excel 通过SAX解析方法,适合大数据导入,不支持图片
     * 导入 数据源本地文件,不返回校验结果 导入 字 段类型 Integer,Long,Double,Date,String,Boolean
     * 
     * @param inputstream
     * @param pojoClass
     * @param params
     * @param handler
     */
    public static void importExcelBySax(InputStream inputstream, Class<?> pojoClass,
                                        ImportParams params, IReadHandler handler) {
        new SaxReadExcel().readExcel(inputstream, pojoClass, params, handler);
    }
    @Override
    public void uploadBigFileByEasyPoi(MultipartFile file) {
        InputStream inputStream;
        try {
            inputStream = file.getInputStream();
        } catch (IOException e) {
            log.error("error msg 【{}】", e);
            throw new IllegalArgumentException(e);
        }
        ExcelImportUtil.importExcelBySax(inputStream,UserDomain.class,new ImportParams(),new UserHandler<UserDomain>());
    }

10w条数据,35s
与正常导入,10w数据,20s

4 问题

4.1 日期类型字段特殊处理

format属性指定一下日期格式

    @Excel(name="生日",format = "yyyy-MM-dd")
    private Date birthday;

4.2 文件上传

修改默认上传大小

  servlet:
    multipart:
      max-file-size: 50MB
      max-request-size: 50MB

4.3 指定导出路径

核心代码


 FileOutputStream outputStream = new FileOutputStream("D:\\test.xlsx"); // 指定输出流位置   
 workbook.write(outputStream) // 写到workbook中

业务层

        List<UserDomain> list = new ArrayList(16);
        for (int i = 0; i < 100000; i++) {
            UserDomain item = UserDomain.builder().userName(RandomStringUtils.randomAlphabetic(6)).address(RandomStringUtils.randomAlphabetic(10))
                    .birthday(new Date())
                    .sex("男")
                    .build();
            list.add(item);
        }
        Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), UserDomain.class, list);
        FileOutputStream outputStream;
        try {
            outputStream = new FileOutputStream("D:\\easypoi.xlsx");
            workbook.write(outputStream);
        } catch (FileNotFoundException e) {
            log.error("error msg 【{}】", e);
            throw new IllegalArgumentException(e);
        } catch (IOException e) {
            log.error("error msg 【{}】", e);
            throw new IllegalArgumentException(e);
        }
        log.info("easypoi导出结束");
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用Spring BootEasyPOI导出Excel文件的步骤如下: 1. 在pom.xml文件中添加EasyPOI的依赖: ``` <dependency> <groupId>cn.afterturn</groupId> <artifactId>easypoi-base</artifactId> <version>4.2.0</version> </dependency> ``` 2. 创建一个POJO类,用于表示Excel中的每一行数据。 3. 在Controller中创建一个请求处理方法,用于处理导出Excel文件的请求。在该方法中,使用EasyPOI创建Excel文件并将其写入输出流中,然后返回一个ResponseEntity对象,该对象包含Excel文件的数据和响应头信息。 以下是一个示例Controller方法: ``` @GetMapping("/export") public ResponseEntity<byte[]> exportExcel() throws IOException { // 创建Excel文件 List<MyData> dataList = getDataList(); Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), MyData.class, dataList); // 将Excel文件写入输出流中 ByteArrayOutputStream out = new ByteArrayOutputStream(); workbook.write(out); // 设置响应头信息 HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); headers.setContentDisposition(ContentDisposition.attachment().filename("data.xlsx").build()); return new ResponseEntity<>(out.toByteArray(), headers, HttpStatus.OK); } private List<MyData> getDataList() { // 返回需要导出的数据的集合 } ``` 在这个示例中,我们首先创建了一个MyData类,用于表示Excel中的每一行数据。然后,在Controller中创建了一个请求处理方法,该方法使用EasyPOI创建Excel文件,并将其写入输出流中。最后,我们设置了响应头信息,将Excel文件作为响应体返回给客户端。 希望这个示例能够帮助您理解如何使用Spring BootEasyPOI导出Excel文件。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值