SpringBoot集成阿里EasyExcel导出excel高级实战

news/2024/7/21 7:16:12 标签: spring boot, excel, java

目录

  • 参考
  • 一、引入包
  • 二、导出到文件并输出到后台
  • 三、过滤字段
    • 方式1:类上加注解 @ExcelIgnoreUnannotated,过滤属性没有@ExcelProperty注解的字段
    • 方式2:指定字段加注解
    • 方式3:代码指定过滤字段, 同一个excel生成两个sheet分别过滤不同字段
  • 四、冻结列
    • 冻结列, 冻结姓名列
    • 注册handler
  • 五、格式化
    • 把保留2位小数
    • 统一数字转换器
    • 枚举转换器
    • 自定义格式转换器
    • 自定义转换器
    • 配置excel导出模型
  • 六、导出
    • 通过controller导出
    • 统一导出转换器导出
  • 七、效果

参考

easyexcel使用教程-导出篇

一、引入包


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

二、导出到文件并输出到后台

java">

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import lombok.SneakyThrows;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;

/**
 * excel导出
 * @create 2022-12-09
 */
public class ExcelUtil {

    private ExcelWriter excelWriter;
    private  File file;
    private String fileName;
    private HttpServletResponse response;
    private WriteSheet writeSheet;


    @SneakyThrows
    public static <T> ExcelUtil create(HttpServletResponse response,String fileNamePrefix,  Class<T> excelModeClass){
        ExcelUtil excelUtil = new ExcelUtil();
        excelUtil.response = response;
        excelUtil.fileName = fileNamePrefix+ ".xlsx";
        // 临时文件
        String filePath =  "/" +fileNamePrefix+ System.currentTimeMillis() + ".xlsx";
        excelUtil.file = new File(filePath);
            // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
        excelUtil.excelWriter = EasyExcel.write(filePath, excelModeClass).build();
        excelUtil.writeSheet = EasyExcel.writerSheet("第一页").build();

            // 写入数据
        return excelUtil;
    }

    @SneakyThrows
    public void export(){
            ServletOutputStream out = response.getOutputStream();

            // 千万别忘记finish 会帮忙关闭流
            excelWriter.finish();

            // 导出
            String fileName = new String(this.fileName
                    .getBytes(StandardCharsets.UTF_8), "iso8859-1");
            response.setHeader("Content-disposition", "attachment;filename="+fileName);
            response.setContentType("multipart/form-data");
            response.setCharacterEncoding("utf-8");
            //4.获取要下载的文件输入流
            InputStream in = Files.newInputStream(Paths.get(this.file.getPath()));
            int len;
            //5.创建数据缓冲区
            byte[] buffer = new byte[1024];
            //6.通过response对象获取OutputStream流
            //7.将FileInputStream流写入到buffer缓冲区
            while ((len = in.read(buffer)) > 0) {
                //8.使用OutputStream将缓冲区的数据输出到客户端浏览器
                out.write(buffer,0,len);
            }
            in.close();
            this.file.deleteOnExit();
            out.flush();
    }


    @SneakyThrows
    public <T> void writeData(List<T> data){
        excelWriter.write(data, writeSheet);
    }
}

三、过滤字段

过滤字段不生成excel

方式1:类上加注解 @ExcelIgnoreUnannotated,过滤属性没有@ExcelProperty注解的字段

java">@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor  // 一定要有无参构造方法
@ExcelIgnoreUnannotated
public class Student {
    .....
}

方式2:指定字段加注解

java">@ExcelIgnore // demo2不生成excel
private String demo2;

excelsheet_125">方式3:代码指定过滤字段, 同一个excel生成两个sheet分别过滤不同字段

java">/**
 * 过滤字段
 */
@Test
public void exportExcludeColumn() {
    Consumer<ExcelWriter> consumer = writer ->
            writer.write(generateStudent(10), EasyExcel.writerSheet(1, "学生信息")
                    .excludeColumnFiledNames(Arrays.asList("name", "sex")) // sheet1过滤姓名、性别
                    .head(Student.class)
                    .build());
    consumer = consumer.andThen(writer ->
            writer.write(generateStudent(10), EasyExcel.writerSheet(2, "学生信息2")
                    .excludeColumnFiledNames(Arrays.asList("birthday", "weight")) // sheet2过滤生日和体重
                    .head(Student.class)
                    .build()));
    export("D:/报表.xlsx", consumer);

四、冻结列

冻结列, 冻结姓名列

冻结列handler,FreezeNameHandler.java

java">package com.learning.easyexcel.converter;

import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import org.apache.poi.ss.usermodel.Sheet;

/**
 * 冻结姓名列
 */
public class FreezeNameHandler implements SheetWriteHandler {
    @Override
    public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {

    }

    @Override
    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
        // 获取到当前的sheet
        Sheet sheet = writeSheetHolder.getSheet();
        /**
         *第一个参数:冻结的列数
         *第二个参数:冻结的行数
         *第三个参数:冻结后第一列的列号
         *第四个参数:冻结后第一行的行号
         **/
        sheet.createFreezePane(1, 0, 1, 0);
    }
}

注册handler

java">  /**
     * 冻结姓名列
     */
    @Test
    public void exportFreezeColumn() {
        Consumer<ExcelWriter> consumer = writer -> {
            writer.write(generateStudent(10), EasyExcel.writerSheet("学生信息")
                    .registerWriteHandler(new FreezeNameHandler()) // 冻结姓名列
                    .head(Student.class)
                    .build());
        };
        export("D:/报表.xlsx", consumer);

五、格式化

把保留2位小数

  • 方法1,@NumberFormat 注解。修改Student类,如下做法会以字符串导出到excel,单元格靠左
java">@ExcelProperty(value = "体重KG")
@NumberFormat("0.##") // 会以字符串形式生成单元格,要计算的列不推荐
private BigDecimal weight;
  • 方法2:@ContentStyle(dataFormat = 2) 注解 ,我们新建一个字段weight2,会以数字导出,单元格中靠右

@ContentStyle(dataFormat = 2)
private BigDecimal weight2;

统一数字转换器

java">package com.test.easyexcel.converter;

import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty;

import java.math.BigDecimal;
import java.math.RoundingMode;

public class BigDecimalConverter implements Converter<BigDecimal> {

    @Override
    public Class supportJavaTypeKey() {
        return BigDecimal.class;
    }

    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.NUMBER;
    }

    @Override
    public BigDecimal convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
        return cellData.getNumberValue();
    }

    @Override
    public CellData convertToExcelData(BigDecimal value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
        return new CellData(value.setScale(2, RoundingMode.DOWN));
    }

枚举转换器

java">public class StatusConverter implements Converter<Integer> {

    @Override
    public Class<Integer> supportJavaTypeKey() {
        return Integer.class;
    }

    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    @Override
    public Integer convertToJavaData(CellData cellData, ExcelContentProperty excelContentProperty, GlobalConfiguration globalConfiguration) {
        return "正常".equals(cellData.getStringValue()) ? 1 : 0;
    }

    @Override
    public CellData<String> convertToExcelData(Integer integer, ExcelContentProperty excelContentProperty, GlobalConfiguration globalConfiguration)  {
        return new CellData<>(integer.equals(1) ? "正常" : "异常");
    }
}

自定义格式转换器

java">@Target(value = {ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExcelPropertyExt {
    String expression() default "";
}

自定义转换器

java">
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

/**
 * easyExcel枚举转换
 * @create 2022-12-07
 */
public class CommonIntegerConverter implements Converter<Integer> {

    @Override
    public Class<Integer> supportJavaTypeKey() {
        return Integer.class;
    }

    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    @Override
    public Integer convertToJavaData(CellData cellData, ExcelContentProperty excelContentProperty, GlobalConfiguration globalConfiguration) {
        return "正常".equals(cellData.getStringValue()) ? 1 : 0;
    }

    @Override
    public CellData<String> convertToExcelData(Integer integer, ExcelContentProperty excelContentProperty, GlobalConfiguration globalConfiguration)  {
        String value = integer.toString();
        Field field = excelContentProperty.getField();
        ExcelPropertyExt annotation = field.getAnnotation(ExcelPropertyExt.class);
        if(annotation != null){
            Method[] meth = annotation.annotationType().getDeclaredMethods();
            for(Method me : meth){
                if(!me.isAccessible()){
                    me.setAccessible(true);
                }
                try {
                    //给字段重新赋值
                    String expression = (String) me.invoke(annotation);
                    List<String> list =  StringUtil.split(expression, SymbolConstants.SEMICOLON);
                    for(String dic : list){
                        List<String> items = StringUtil.split(dic, SymbolConstants.C_COMMA);
                        String key = items.get(0);
                        String v = items.get(1);
                        if(value.equals(key)) {
                            value = v;
                            break;
                        }
                    }
//                    System.out.println("expression:"+expression);
                } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
        return new CellData<>(value);
    }
}

excel_365">配置excel导出模型

java">@Data
@AllArgsConstructor
@NoArgsConstructor
public class DataModelDTO implements Serializable {

    private static final long serialVersionUID = 15353L;

    @ExcelProperty(value = "设备名称")
    private String deviceName;

    @ExcelPropertyExt(expression = "0,停止;1,上;2,下")
    @ExcelProperty(value = "运行方向",converter = CommonIntegerConverter.class)
    private Integer direction;

    @ExcelProperty(value = "状态", converter = StatusConverter.class)
    private Integer Status;

    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
    @ExcelProperty(value = "数据上报时间")
    private Date timestamp;
}

六、导出

通过controller导出

java">@Operation(summary = "导出")
@GetMapping("/data/export")
void export(HttpServletResponse response) {
    ExcelUtil excelUtil = ExcelUtil.create(response,"设备实时数据", DataModelDTO.class);
    // 写入数据
	excelUtil.writeData( getData());
	        // 导出
	excelUtil.export();
}

private List<UserDataModelDTO> getData(){
	List<UserDataModelDTO> list = new ArrayList<>();
	DataModelDTO data1 = new DataModelDTO("设备1",1,1,new Date());
	DataModelDTO data2 = new DataModelDTO("设备2",1,1,new Date());
	list.add(data1);
	list.add(data2);
	return list ;
}
        

统一导出转换器导出

java">Consumer<ExcelWriter> consumer = writer -> {
            writer.write(generateStudent(10), EasyExcel.writerSheet("学生信息")
                    .registerConverter(new BigDecimalConverter())
                    .head(Student.class)
                    .build());
        };
        export("D:/报表.xlsx", consumer);

七、效果

在这里插入图片描述


http://www.niftyadmin.cn/n/16505.html

相关文章

abap学习日志--语法4

流程控制 条件语句 if语句 IF . . ELSEIF . . ELSE. ENDIF. ​ case 语句 CASE <f>. WHEN <f1>. <statement block>. WHEN <f2>. <statement block>. WHEN ... WHEN OTHERS. <statement block>. ENDCASE.循环语句 计数循环 使用DO指定…

水泥路面、桥梁基建、隧道裂痕裂缝检测数据集

在我之前的博文中已经写过几篇关于特定场景下的裂痕裂缝检测的模型实践文章&#xff0c;后面也有很项目应用都是基于此构建的&#xff0c;这里主要是对前面几篇博文的数据集进行介绍。 相应的系列文章如下&#xff0c;感兴趣的话可以自行移步阅读即可。 《基于yolov5sbifpn实…

接口功能测试经验及策略总结,希望可以帮到你

目录 前言 一、接口测试范围 二、接口测试策略 接口设计检查 接口依赖关系检查 接口输入/输出验证 密码重置接口 用户经验值查询接口 比赛成绩同步接口 三、总结 四、重点&#xff1a;配套学习资料和视频教学 前言 由于平台服务器是通过接口来与客户端交互数据提供…

Springboot数码终端一站式服务平台302ol计算机毕业设计

Springboot数码终端一站式服务平台302ol计算机毕业设计 【免费赠送源码】Springboot数码终端一站式服务平台302ol计算机毕业设计-课程设计-期末作业-毕设程序代做本源码技术栈&#xff1a; 项目架构&#xff1a;B/S架构 开发语言&#xff1a;Java语言 开发软件&#xff1a;i…

代码随想录算法训练营第六天| 哈希表理论基础 ,242.有效的字母异位词 , 349. 两个数组的交集 ,202. 快乐数,1. 两数之和

代码随想录算法训练营第六天| 哈希表理论基础 &#xff0c;242.有效的字母异位词 &#xff0c; 349. 两个数组的交集 &#xff0c;202. 快乐数&#xff0c;1. 两数之和 哈希表理论基础 建议&#xff1a;大家要了解哈希表的内部实现原理&#xff0c;哈希函数&#xff0c;哈希碰…

C中的auto、static、register、extern、const和volitate

C语言中的每一个变量和函数有两个属性&#xff1a;数据类型和数据的存储类别。数据类型&#xff08;整形、字符型等&#xff09;&#xff0c;存储类别是指数据在内存中存储的方法&#xff0c;存储方法有两大类&#xff1a;静态存储类和动态存储类。具体包括四种&#xff1a;自动…

Spring AOP 的实现机制

AOP&#xff08;Aspect Orient Programming&#xff09;&#xff0c;一般称为面向切面编程&#xff0c;作为面向对象的一种补充&#xff0c;用于处理系统中分布于各个模块的横切关注点&#xff0c;比如事务管理、日志、缓存等等。AOP实现的关键在于AOP框架自动创建的AOP代理&am…

markdown中插入数学公式

文章目录标识空格边界脚标分数极限修饰省略号希腊字母顶部符号向量夹角线性矩阵边框矩阵扩展标记分块阵列线性方程组二元一次方程组三元一次方程组多元一次方程组refsvscode-markdown-math KaTeX supported functions/symbols: sorted by type, sorted alphabetically. MathJ…