SpringBoot-EasyPoi

x33g5p2x  于2021-09-22 转载在 Spring  
字(17.8k)|赞(0)|评价(0)|浏览(540)

SpringBoot-EasyPoi

http://doc.wupaas.com/docs/easypoi/easypoi-1c10lpehvgv0j 官方文档

Easypoi 介绍

在项目中,有时会出现需要将数据库数据导出报表等功能,这时一般会用到poi库。poi是一个专门给Java程序提供格式文档读写功能的API接口,包括各种微软的格式文档入excel、word等。

最常用的还是处理Excel格式导入导出(其他都不咋地)。
Easypoi是在poi接口基础上进行了封装,简化了操作,基于注解的方式。

Maven

SpringBoot的Maven

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

普通项目的Maven

<dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-base</artifactId>
            <version>4.1.0</version>
        </dependency>
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-web</artifactId>
            <version>4.1.0</version>
        </dependency>
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-annotation</artifactId>
            <version>4.1.0</version>
        </dependency>

excel实体类(重点)

@Excel的各个参数可介绍

属性类型默认值功能
nameStringnull列名,支持name_id
needMergebooleanfasle是否需要纵向合并单元格(用于含有list中,单个的单元格,合并list创建的多个row)
orderNumString“0”列的排序,支持name_id
replaceString[]{}值得替换 导出是{a_id,b_id} 导入反过来
savePathString“upload”导入文件保存路径,如果是图片可以填写,默认是upload/className/ IconEntity这个类对应的就是upload/Icon/
typeint1导出类型 1 是文本 2 是图片,3 是函数,10 是数字 默认是文本
widthdouble10列宽
heightdouble10列高,后期打算统一使用@ExcelTarget的height,这个会被废弃,注意
isStatisticsbooleanfasle自动统计数据,在追加一行统计,把所有数据都和输出[这个处理会吞没异常,请注意这一点]
isHyperlinkbooleanfalse超链接,如果是需要实现接口返回对象
isImportFieldbooleantrue校验字段,看看这个字段是不是导入的Excel中有,如果没有说明是错误的Excel,读取失败,支持name_id
exportFormatString“”导出的时间格式,以这个是否为空来判断是否需要格式化日期
importFormatString“”导入的时间格式,以这个是否为空来判断是否需要格式化日期
formatString“”时间格式,相当于同时设置了exportFormat 和 importFormat
databaseFormatString“yyyyMMddHHmmss”导出时间设置,如果字段是Date类型则不需要设置 数据库如果是string 类型,这个需要设置这个数据库格式,用以转换时间格式输出
numFormatString“”数字格式化,参数是Pattern,使用的对象是DecimalFormat
imageTypeint1导出类型 1 从file读取 2 是从数据库中读取 默认是文件 同样导入也是一样的
suffixString“”文字后缀,如% 90 变成90%
isWrapbooleantrue是否换行 即支持\n
mergeRelyint[]{}合并单元格依赖关系,比如第二列合并是基于第一列 则{0}就可以了
mergeVerticalbooleanfasle纵向合并内容相同的单元格
fixedIndexint-1对应excel的列,忽略名字
isColumnHiddenbooleanfalse导出隐藏列

下面我们创建2个用例:

package com.easypoi.pojo;

import cn.afterturn.easypoi.excel.annotation.Excel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class User {

    /** * 用户名 */
    @Excel(name = "用户名")
    private String username;

    /** * 姓名 */
    @Excel(name = "姓名")
    private String name;

    /** * 年龄 */
    @Excel(name = "年龄")
    private Integer age;

    /** * 性别,数值0表示男,1表示女 自动替换 */

    @Excel(name = "性别",replace = {"男_0", "女_1"})
    private String sex;

    /** * 籍贯 */
    @Excel(name = "籍贯")
    private String address;
}
package com.easypoi.pojo;

import cn.afterturn.easypoi.excel.annotation.Excel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Company {
    @Excel(name = "公司名称",width =20)
    private String name;

    /** * type为 2 表示字段类型为图片 * imageType为 1 表示从file读取 */
    @Excel(name = "公司logo",width =20,type = 2,imageType = 1)
    private String logo;

    @Excel(name = "公司介绍",width =100)
    private String dec;
}

excel样式

package com.easypoi.utils;

import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.afterturn.easypoi.excel.entity.params.ExcelForEachParams;
import cn.afterturn.easypoi.excel.export.styler.IExcelExportStyler;
import org.apache.poi.ss.usermodel.*;

/** * @author 胡安民 * @date 2019/11/04 */
public class ExcelStyleUtil implements IExcelExportStyler {
    private static final short STRING_FORMAT = (short) BuiltinFormats.getBuiltinFormat("TEXT");
    private static final short FONT_SIZE_TEN = 9; //字体大小
    private static final short FONT_SIZE_ELEVEN = 12;//列大小
    private static final short FONT_SIZE_TWELVE = 15;//大标题
    /** * 大标题样式 */
    private CellStyle headerStyle;
    /** * 每列标题样式 */
    private CellStyle titleStyle;
    /** * 数据行样式 */
    private CellStyle styles;

    public ExcelStyleUtil(Workbook workbook) {
        this.init(workbook);
    }

    /** * 初始化样式 * * @param workbook */
    private void init(Workbook workbook) {
        this.headerStyle = initHeaderStyle(workbook);
        this.titleStyle = initTitleStyle(workbook);
        this.styles = initStyles(workbook);
    }

    /** * 大标题样式 * * @param color * @return */
    @Override
    public CellStyle getHeaderStyle(short color) {
        return headerStyle;
    }

    /** * 每列标题样式 * * @param color * @return */
    @Override
    public CellStyle getTitleStyle(short color) {
        return titleStyle;
    }

    /** * 数据行样式 (控制全部行的样式) * @param parity 表示奇偶行 * @param entity 数据内容 * @return 样式 */
    @Override
    public CellStyle getStyles(boolean parity, ExcelExportEntity entity) {
        return styles;
    }

    /** * 获取样式方法 * * @param dataRow 数据行 * @param obj 对象 * @param data 数据 */
    @Override
    public CellStyle getStyles(Cell cell, int dataRow, ExcelExportEntity entity, Object obj, Object data) {
        return getStyles(true, entity);
    }

    /** * 模板使用的样式设置 */
    @Override
    public CellStyle getTemplateStyles(boolean isSingle, ExcelForEachParams excelForEachParams) {
        return null;
    }

    /** * 初始化--大标题样式 * * @param workbook * @return */
    private CellStyle initHeaderStyle(Workbook workbook) {
        CellStyle style = getBaseCellStyle(workbook);
        style.setFont(getFont(workbook, FONT_SIZE_TWELVE, true));
        return style;
    }

    /** * 初始化--每列标题样式 * * @param workbook * @return */
    private CellStyle initTitleStyle(Workbook workbook) {
        CellStyle style = getBaseCellStyle(workbook);
        style.setFont(getFont(workbook, FONT_SIZE_ELEVEN, false));
        //背景色
// style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); //灰色
// style.setFillForegroundColor(IndexedColors.AQUA.getIndex()); //浅蓝色
        style.setFillForegroundColor(IndexedColors.SEA_GREEN.getIndex()); //海藻绿


        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        return style;
    }

    /** * 初始化--数据行样式 * * @param workbook * @return */
    private CellStyle initStyles(Workbook workbook) {
        CellStyle style = getBaseCellStyle(workbook);
        style.setFont(getFont(workbook, FONT_SIZE_TEN, false));
        style.setDataFormat(STRING_FORMAT);
        return style;
    }

    /** * 基础样式 * * @return */
    private CellStyle getBaseCellStyle(Workbook workbook) {
        CellStyle style = workbook.createCellStyle();
        //下边框
        style.setBorderBottom(BorderStyle.THIN);
        //左边框
        style.setBorderLeft(BorderStyle.THIN);
        //上边框
        style.setBorderTop(BorderStyle.THIN);
        //右边框
        style.setBorderRight(BorderStyle.THIN);
        //水平居中
        style.setAlignment(HorizontalAlignment.CENTER);
        //上下居中
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        //设置自动换行
        style.setWrapText(true);
        return style;
    }

    /** * 字体样式 * * @param size 字体大小 * @param isBold 是否加粗 * @return */
    private Font getFont(Workbook workbook, short size, boolean isBold) {
        Font font = workbook.createFont();
        //字体样式
        font.setFontName("宋体");
        //是否加粗
        font.setBold(isBold);
        //字体大小
        font.setFontHeightInPoints(size);
        return font;
    }
}

excel倒入导出工具类

package com.easypoi.utils;

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 cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.hutool.core.util.StrUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;

/** * Excel导入导出工具类 */

public class ExcelUtils {

    /** 允许导出的最大条数 */
    private static final Integer EXPORT_EXCEL_MAX_NUM = 10000;

    /** * excel 导出 * * @param list 数据列表 * @param fileName 导出时的excel名称 * @param response */
    public static void exportExcel(List<Map<String, Object>> list, String fileName, HttpServletResponse response) throws IOException {
        defaultExport(list, fileName, response);

    }

    /** * 默认的 excel 导出 * * @param list 数据列表 * @param fileName 导出时的excel名称 * @param response */
    private static void defaultExport(List<Map<String, Object>> list, String fileName, HttpServletResponse response) throws IOException {

        //把数据添加到excel表格中
        Workbook workbook = ExcelExportUtil.exportExcel(list, ExcelType.HSSF);
        downLoadExcel(fileName, response, workbook);
    }

    /** * excel 导出 * * @param list 数据列表 * @param pojoClass pojo类型 * @param fileName 导出时的excel名称 * @param response * @param exportParams 导出参数(标题、sheet名称、是否创建表头,表格类型) */
    private static void defaultExport(List<?> list, Class<?> pojoClass, String fileName, HttpServletResponse response, ExportParams exportParams) throws IOException {
        //把数据添加到excel表格中
        Workbook workbook = ExcelExportUtil.exportExcel(exportParams, pojoClass, list);
        downLoadExcel(fileName, response, workbook);
    }

    /** * excel 导出 * * @param list 数据列表 * @param pojoClass pojo类型 * @param fileName 导出时的excel名称 * @param exportParams 导出参数(标题、sheet名称、是否创建表头,表格类型) * @param response */
    public static void exportExcel(List<?> list, Class<?> pojoClass, String fileName, ExportParams exportParams, HttpServletResponse response) throws IOException {
        defaultExport(list, pojoClass, fileName, response, exportParams);
    }

    /** * excel 导出 * * @param list 数据列表 * @param title 表格内数据标题 * @param sheetName sheet名称 * @param pojoClass pojo类型 * @param fileName 导出时的excel名称 * @param response */
    public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass, String fileName, HttpServletResponse response) throws IOException {
        //给文件名拼接上日期
        SimpleDateFormat formatter = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss");
        String dateString = formatter.format (new Date());
        fileName = fileName +  dateString;
        //判断导出数据是否为空
        if (list == null) {
            list = new ArrayList<>();
        }
        //判断导出数据数量是否超过限定值
        if (list.size() > EXPORT_EXCEL_MAX_NUM) {
            title = "导出数据行数超过:" + EXPORT_EXCEL_MAX_NUM + "条,无法导出、请添加导出条件!";
            list = new ArrayList<>();
        }
        //获取导出参数
        ExportParams exportParams = new ExportParams(title, sheetName, ExcelType.XSSF);
        //设置导出样式
        exportParams.setStyle(ExcelStyleUtil.class);
        //设置行高
        exportParams.setHeight((short) 6);


        defaultExport(list, pojoClass, fileName, response, exportParams);
    }



    /** * 根据模板生成excel后导出 * @param templatePath 模板路径 * @param map 数据集合 * @param fileName 文件名 * @param response * @throws IOException */
    public static void exportExcel(TemplateExportParams templatePath, Map<String, Object> map, String fileName, HttpServletResponse response) throws IOException {
        Workbook workbook = ExcelExportUtil.exportExcel(templatePath, map);
        downLoadExcel(fileName, response, workbook);
    }


    /** * excel下载 * * @param fileName 下载时的文件名称 * @param response * @param workbook excel数据 */
    private static void downLoadExcel(String fileName, HttpServletResponse response, Workbook workbook) throws IOException {
        try {
            response.setCharacterEncoding("UTF-8");
            response.setHeader("content-Type", "application/vnd.ms-excel");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName + ".xlsx", "UTF-8"));
            workbook.setForceFormulaRecalculation(true); //强制开启excel公式计算
            workbook.write(response.getOutputStream());
        } catch (Exception e) {
            throw new IOException(e.getMessage());
        }
    }


    /** * excel 导入 * * @param file excel文件 * @param pojoClass pojo类型 * @param <T> * @return */
    public static <T> List<T> importExcel(MultipartFile file, Class<T> pojoClass) throws IOException {
        return importExcel(file, 1, 1, pojoClass);
    }

    /** * excel 导入 * * @param filePath excel文件路径 * @param titleRows 表格内数据标题行 * @param headerRows 表头行 * @param pojoClass pojo类型 * @param <T> * @return */
    public static <T> List<T> importExcel(String filePath, Integer titleRows, Integer headerRows, Class<T> pojoClass) throws IOException {
        if (StringUtils.isBlank(filePath)) {
            return null;
        }
        ImportParams params = new ImportParams();
        params.setTitleRows(titleRows);
        params.setHeadRows(headerRows);
        params.setNeedSave(true);
        params.setSaveUrl("/excel/");
        try {
            return ExcelImportUtil.importExcel(new File(filePath), pojoClass, params);
        } catch (NoSuchElementException e) {
            throw new IOException("模板不能为空");
        } catch (Exception e) {
            throw new IOException(e.getMessage());
        }
    }

    /** * excel 导入 * * @param file 上传的文件 * @param titleRows 表格内数据标题行 * @param headerRows 表头行 * @param pojoClass pojo类型 * @param <T> * @return */
    public static <T> List<T> importExcel(MultipartFile file, Integer titleRows, Integer headerRows, Class<T> pojoClass) throws IOException {
        if (file == null) {
            return null;
        }
        try {
            return importExcel(file.getInputStream(), titleRows, headerRows, pojoClass);
        } catch (Exception e) {
            throw new IOException(e.getMessage());
        }
    }

    /** * excel 导入 * * @param inputStream 文件输入流 * @param titleRows 表格内数据标题行 * @param headerRows 表头行 * @param pojoClass pojo类型 * @param <T> * @return */
    public static <T> List<T> importExcel(InputStream inputStream, Integer titleRows, Integer headerRows, Class<T> pojoClass) throws IOException {
        if (inputStream == null) {
            return null;
        }
        ImportParams params = new ImportParams();
        params.setTitleRows(titleRows);
        params.setHeadRows(headerRows);
        params.setSaveUrl("/excel/");
        params.setNeedSave(true);
        try {
            return ExcelImportUtil.importExcel(inputStream, pojoClass, params);
        } catch (NoSuchElementException e) {
            throw new IOException("excel文件不能为空");
        } catch (Exception e) {
            throw new IOException(e.getMessage());
        }
    }

测试接口

package com.easypoi.controller;

import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import com.easypoi.pojo.Company;
import com.easypoi.pojo.User;
import com.easypoi.utils.ExcelUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

@RestController
@RequestMapping("/easypoi")
public class EasypoiController {
    /** * 导入excel数据 * @param file * @return * @throws IOException */
    @RequestMapping(value = "/import", method = RequestMethod.POST)
    public ResponseEntity<String> importExcel(@RequestParam("file") MultipartFile file) throws IOException {
        List<User> list = ExcelUtils.importExcel(file, User.class);
// int i = userService.insertByBatch(list); //将数据写入到数据库中
// if (i != 0) {
// return ResponseEntity.ok( "导入成功");
// } else {
// return ResponseEntity.ok( "导入失败");
// }

        return ResponseEntity.ok( "导入成功");
    }


    

    /** * 导出数据 * // http://localhost:1011/easypoi/exportExcel * @param response * @throws IOException */
    @GetMapping("/exportExcel")
    public void exportExcel( HttpServletResponse response) throws IOException {
        List<User> list=new ArrayList<User>(){{
            add(User.builder().username("我是大白鲨").age(12).name("胡安民").sex("0").address("北京市").build());
            add(User.builder().username("我是大白鲨1").age(12).name("胡安民1").sex("1").address("北京市1").build());
            add(User.builder().username("我是大白鲨1").age(12).name("胡安民1").sex("男").address("北京市1").build());

        }};

        ExcelUtils.exportExcel(list, "用户信息统计表Title", "用户表Sheet", User.class, "用户信息统计File", response);

    }

    
    

    /** * excel带图片的导出 * // http://localhost:1011/easypoi/imgexport * @param response * @throws IOException */
    @GetMapping("/imgexport")
    public void imgExport(HttpServletResponse response) throws IOException {
        List<Company> list = new ArrayList<>();
        //图片的路径自定义,但必须要正确
        list.add(new Company("百度", "E:/img/1.jpg", "百度一下你就知道"));
        list.add(new Company("腾讯", "E:/img/3.jpg", "腾讯qq,交流的世界"));
        list.add(new Company("阿里巴巴", "E:/img/2.jpg", "阿里巴巴,马云的骄傲"));

        ExcelUtils.exportExcel(list, "图片excelTile", "图片excelSheet", Company.class, "图片excelFile", response);
    }

    /** * excel带图片的导入 只支持在linux服务器上 (可以自行查看源码) * // http://localhost:1011/easypoi/imgexport * @param file * @return * @throws IOException */
    @PostMapping("/imgimport")
    public ResponseEntity imgImport(@RequestParam("file") MultipartFile file) throws IOException {

        List<Company> list = ExcelUtils.importExcel(file, Company.class);
        return  ResponseEntity.ok("导入成功:"+list);
    }



    /** * 使用模板excel导出 (专门处理一些复杂情况下的数据导出) * //http://localhost:1011/easypoi/excelTemplate * @param response * @throws Exception */
    @GetMapping("/excelTemplate")
    public void makeExcelTemplate(HttpServletResponse response) throws Exception {
        List<User> list=new ArrayList<User>(){{
            add(User.builder().username("我是大白鲨").age(12).name("胡安民").sex("0").address("北京市").build());
            add(User.builder().username("我是大白鲨1").age(12).name("胡安民1").sex("1").address("北京市1").build());
            add(User.builder().username("我是大白鲨1").age(12).name("胡安民1").sex("男").address("北京市1").build());

        }};

        TemplateExportParams templatePath = new TemplateExportParams("E:/test.xlsx");
        Map<String, Object> map = new HashMap<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        map.put("date", sdf.format(new Date()));
        map.put("user", "admin");
        map.put("userList", list);
        ExcelUtils.exportExcel(templatePath, map, "使用模板excel导出File", response);
    }
}

application.yml

server:
  port: 1011

spring:
  main:
    allow-bean-definition-overriding: true  #easypoi启用覆盖
  datasource:
    driverClassName: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/voidme?useUnicode=true&characterEncoding=utf8&autoReconnect=true&failOverReadOnly=false&serverTimezone=UTC
    username: root
    password: root
    hikari.idle-timeout: 60000
    hikari.maximum-pool-size: 30
    hikari.minimum-idle: 10


#spring集成Mybatis环境
#实体类别名扫描包 如果使用接口的话这个可以省略
# 加载Mybatis映射文件 classpath:mapper/*Mapper.xml 代表是 resources 下mapper包里所有是 ..Mapper.xml结尾的xml配置文件 如果使用接口的话这个可以省略
mybatis:
  type-aliases-package: com.easypoi.pojo
  mapper-locations: classpath:mybaitis/*Mapper.xml
  configuration:
    map-underscore-to-camel-case: true

启动类

package com.easypoi;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync

public class EasypoiAppllication {

    public static void main(String[] args) {
        SpringApplication.run(EasypoiAppllication.class,args);
    }

}

效果图

导出效果图

带图片的导出效果图

使用模板excel导出效果图

使用模板excel导出,@Excel注解(无效) 这个是BUG占时官方没有解决

excel模板导出规则

在上面我们已经提供了接口了, 但是excel的模板格式 和规则是什么呢???

在两个大括号里写对应的数据名称。

$fe用来遍历数据 , : list数据源 (变量默认t,不需要写)

{{$fe: maplist   t.id }}

http://doc.wupaas.com/docs/easypoi/easypoi-1c10lfhut694k (官方,一般不建议使用代码操作太复杂的表格了)

相关文章