SpringBoot+EasyPoi实现excel导出功能

在实际项目开发中,对于Excel的导入导出还是很常见的需求,比如说将数据根据模板批量导入到数据库中,以及将数据库中的数据批量导出陈Excel的形式

现有需求: 根据检索条件查询列表并将结果导出到excel

Easypoi文档:https://easypoi.mydoc.io/#text_186900

EasyPoi的主要特点

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

 

实现过程

1.创建一个Spring Boot项目

快速生成链接:start.spring.io

在这里插入图片描述

2.引入EasyPoi的pom依赖

<!--EasyPoi导入导出-->
<dependency>
 <groupId>cn.afterturn</groupId>
 <artifactId>easypoi-base</artifactId>
 <version>4.3.0</version>
</dependency>
<dependency>
 <groupId>cn.afterturn</groupId>
 <artifactId>easypoi-web</artifactId>
 <version>4.3.0</version>
</dependency>
<dependency>
 <groupId>cn.afterturn</groupId>
 <artifactId>easypoi-annotation</artifactId>
 <version>4.3.0</version>
</dependency>
  • easypoi-base 导入导出的工具包,可以完成Excel导出,导入,Word的导出,Excel的导出功能
  • easypoi-web 耦合了spring-mvc 基于AbstractView,极大的简化spring-mvc下的导出功能
  • easypoi-annotation 基础注解包,作用与实体对象上,拆分后方便maven多工程的依赖管理

sax 导入使用xercesImpl这个包(这个包可能造成奇怪的问题哈),word导出使用poi-scratchpad,都作为可选包了

pom.xml中的所有依赖:

<dependencies>
   <!-- 导入web支持:SpringMVC开发支持,Servlet相关的程序 -->
   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-web</artifactId>
   </dependency>

   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-devtools</artifactId>
       <scope>runtime</scope>
       <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>
   <!-- mybatis相关的依赖 -->
   <!--mybatis-plus自动的维护了mybatis以及mybatis-spring的依赖,
   在springboot中这三者不能同时的出现,避免版本的冲突,表示:跳进过这个坑-->
   <!--mybatis-plus-->
   <dependency>
       <groupId>com.baomidou</groupId>
       <artifactId>mybatis-plus-boot-starter</artifactId>
       <version>3.4.3</version>
   </dependency>
   <!--mysql驱动-->
   <dependency>
       <groupId>mysql</groupId>
       <artifactId>mysql-connector-java</artifactId>
       <scope>runtime</scope>
   </dependency>
   <!-- alibaba的druid数据库连接池 -->
   <dependency>
       <groupId>com.alibaba</groupId>
       <artifactId>druid</artifactId>
       <version>1.1.20</version>
   </dependency>
   <!-- alibaba的druid数据库连接池 -->
   <dependency>
       <groupId>com.alibaba</groupId>
       <artifactId>druid-spring-boot-starter</artifactId>
       <version>1.1.20</version>
   </dependency>
   <!--swagger2依赖-->
   <dependency>
       <groupId>io.springfox</groupId>
       <artifactId>springfox-swagger2</artifactId>
       <version>2.9.2</version>
       <!--排除自身的依赖1.5.20版本-->
       <exclusions>
           <exclusion>
               <groupId>io.swagger</groupId>
               <artifactId>swagger-models</artifactId>
           </exclusion>
       </exclusions>
   </dependency>
   <dependency>
       <groupId>io.springfox</groupId>
       <artifactId>springfox-swagger-ui</artifactId>
       <version>2.9.2</version>
   </dependency>
   <!--此版本解决 example="" 造成的 空字符串""无法转成Number 问题-->
   <dependency>
       <groupId>io.swagger</groupId>
       <artifactId>swagger-models</artifactId>
       <version>1.5.21</version>
   </dependency>
   <!--EasyPoi导入导出-->
   <dependency>
       <groupId>cn.afterturn</groupId>
       <artifactId>easypoi-base</artifactId>
       <version>4.3.0</version>
   </dependency>
   <dependency>
       <groupId>cn.afterturn</groupId>
       <artifactId>easypoi-web</artifactId>
       <version>4.3.0</version>
   </dependency>
   <dependency>
       <groupId>cn.afterturn</groupId>
       <artifactId>easypoi-annotation</artifactId>
       <version>4.3.0</version>
   </dependency>

   <!--fastjson-->
   <dependency>
       <groupId>com.alibaba</groupId>
       <artifactId>fastjson</artifactId>
       <version>1.2.71</version>
   </dependency>
</dependencies>

3.编写excel工具类

package com.example.easypoiexceldemo.utils;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.BeanUtils;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

/**
* excel工具类
* @author qzz
*/
public class ExcelUtils {

  /**
   * Excel导出
   *
   * @param response      response
   * @param fileName      文件名
   * @param list          数据List
   * @param pojoClass     对象Class
   */
  public static void exportExcel(HttpServletResponse response, String fileName, Collection<?> list, Class<?> pojoClass) throws IOException {
      if (StringUtils.isBlank(fileName)) {
          //当前日期
          SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
          fileName = df.format(new Date());
      }
      Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(fileName, fileName, ExcelType.HSSF), pojoClass, list);
      response.setCharacterEncoding("UTF-8");
      response.setHeader("content-Type", "application/vnd.ms-excel");
      response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") + ".xls");
      ServletOutputStream out = response.getOutputStream();
      workbook.write(out);
      out.flush();
  }

  /**
   * Excel导出,先sourceList转换成List<targetClass>,再导出
   *
   * @param response      response
   * @param fileName      文件名
   * @param sourceList    原数据List
   * @param targetClass   目标对象Class
   */
  public static void exportExcelToTarget(HttpServletResponse response, String fileName, Collection<?> sourceList, Class<?> targetClass) throws Exception {
      List targetList = new ArrayList<>(sourceList.size());
      for (Object source : sourceList) {
          Object target = targetClass.newInstance();
          BeanUtils.copyProperties(source, target);
          targetList.add(target);
      }
      exportExcel(response, fileName, targetList, targetClass);
  }


  /**
   * Excel导出----设置title---sheetName---要求Collection<?> list是Class<?> pojoClass类型的
   *
   * @param response      response
   * @param fileName      文件名
   * @param list          数据List
   * @param pojoClass     对象Class
   */
  public static void exportExcel(HttpServletResponse response, String title, String sheetName, String fileName, Collection<?> list, Class<?> pojoClass) throws IOException {
      if (StringUtils.isBlank(fileName)) {
          //当前日期
          SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
          fileName = df.format(new Date());
      }
      Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(title, sheetName, ExcelType.HSSF), pojoClass, list);
      response.setCharacterEncoding("UTF-8");
      response.setHeader("content-Type", "application/vnd.ms-excel");
      response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") + ".xls");
      ServletOutputStream out = response.getOutputStream();
      workbook.write(out);
      out.flush();
  }
}

4.在实体类上加注解@Excel

我这边使用了lombok。getter setter和构造方法通过注解 @Data @AllArgsConstructor进行添加,不使用lombok也可手动添加。

要导出的数据可在实体类对应属性上方加**@Excel()注解**。可定义导出列的名称、宽度,以及性别可区分化(一般数据库中存储的性别为1和2),日期格式化等等。

package com.example.easypoiexceldemo.excel;

import cn.afterturn.easypoi.excel.annotation.Excel;
import lombok.Data;

import java.util.Date;

/**
* 商品
* @author qzz
*/
@Data
public class ProductExcel {

  /**
   * 商品id
   */
  @Excel(name = "商品id")
  private Integer product_id;
  /**
   * 商品标题
   */
  @Excel(name="商品标题")
  private String title;
  /**
   * 商品副标题
   */
  @Excel(name="商品副标题")
  private String sub_title;
  /**
   * 商品售价
   */
  @Excel(name="商品售价")
  private Double sale_price;
  /**
   * 创建者
   */
  @Excel(name="创建者")
  private Integer create_by;
  /**
   * 创建时间
   */
  @Excel(name="创建时间", format = "yyyy-MM-dd")
  private Date create_time;
  /**
   * 修改时间
   */
  @Excel(name="修改时间", format = "yyyy-MM-dd")
  private Date update_time;
  /**
   * 修改者id
   */
  @Excel(name="修改者id")
  private Integer update_by;
}

@Excel 作用到filed上面,是对Excel一列的一个描述

@Excel 的属性介绍:

在这里插入图片描述
在这里插入图片描述

5.Controller

/**
   * excel导出
   * @param response
   */
  @GetMapping("/excel")
  @ApiOperation("根据检索条件查询列表,导出excel")
  public void export( HttpServletResponse response) throws IOException {
      //根据条件检索列表
      QueryWrapper<Product> queryWrapper = new QueryWrapper();
      //根据条件检索商品列表
      List<Map<String, Object>> list = productService.selectList(queryWrapper);
      //将List<Map<String, Object>>结果集转换成List<ProductExcel>
      List<ProductExcel> productList = MapToEntity.setList(list,ProductExcel.class);
      //导出excel
      ExcelUtils.exportExcel(response,null,productList, ProductExcel.class);
  }

setList方法为工具类,用于将List<Map<String, Object>>结果集转换成List

MapToEntity工具类:

package com.example.easypoiexceldemo.utils;

import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
* List<Map<String,Object>>到List<T>数据转换
* @author qzz
*/
public class MapToEntity {

  /**
   * List<Map<String, Object>> 到 List<T> 数据转换
   */
  public static <T> List<T> setList(final List<Map<String, Object>> srcList, Class<T> clazz) {
      List<T> list = new ArrayList<>();
      for (int i=0;i<srcList.size();i++){
          try {
              T t = clazz.newInstance();
              Field[] fields = t.getClass().getDeclaredFields();
              for (Field field : fields) {
                  if (!"serialVersionUID".equals(field.getName())) {
                      //设置对象的访问权限,保证对private的属性的访问
                      field.setAccessible(true);
                      //读取配置转换字段名,并从map中取出数据
                      Object v = srcList.get(i).get(field.getName());
                      field.set(t, convert(v, field.getType()));
                  }
              }
              list.add(t);
          } catch (Exception ex) {
              ex.toString();
          }

      };
      return list;
  }

  /**
   * 字段类型转换
   */
  private static <T> T convert(Object obj, Class<T> type) throws ParseException {
      if (obj != null && StringUtils.isNotBlank(obj.toString())) {
          if (type.equals(String.class)) {
              return (T) obj.toString();
          } else if (type.equals(BigDecimal.class)) {
              return (T) new BigDecimal(obj.toString());
          }else if(type.equals(Double.class)){
              return (T) Double.valueOf(obj.toString());
          }else if(type.equals(Integer.class)){
              return (T) Integer.valueOf(obj.toString());
          }else if(type.equals(Date.class)){
              if(obj!=null){
                  String timeStr = String.valueOf(obj);
                  String s[] = timeStr.split("T");
                  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                  return (T) sdf.parse(s[0]+" "+s[1]);
              }else{
                  return null;
              }
          }
          else{
              //其他类型转换
              return (T) obj.toString();
          }

      }
      return null;
  }
}

6.启动项目,进行测试

项目启动成功后,在浏览器中输入 http://localhost:8083/product/excel,进行访问:

在这里插入图片描述

打开导出的excel文档:

在这里插入图片描述

关于SpringBoot+EasyPoi实现excel导出的文章就介绍至此,更多相关SpringBoot实现excel导出内容请搜索编程宝库以前的文章,希望大家多多支持编程宝库

单例模式,顾名思义,就是全局只保存有一个实例并且能够避免用户去手动实例化,所以单例模式的各种写法都有一个共同点,不能通过new关键字去创建对象,因此,如果能够通过构造方法实例化,那么就一定要将其声明为私有。  ...