EasyExcel--导入和导出Excel的方法

原文网址:EasyExcel--导入和导出Excel的方法_IT利刃出鞘的博客-CSDN博客

简介

本文介绍SpringBoot整合EasyExcel导入和导出Excel的方法。

使用

Excel导入

实体类

java 复制代码
@Data
public class OrderImportBO {
    @ExcelProperty("订单号")
    @NotBlank(message = "订单号不能为空")
    private String scOrderPoolId;

    @ExcelProperty("金额")
    private String amount;
}

Controller

java 复制代码
@PostMapping("importOrder")
public void importOrder(@RequestPart MultipartFile file) {
    List<OrderImportBO> orderImportBOList = ExcelUtil.importExcel(file, OrderImportBO.class);
}

Excel导出

实体类

java 复制代码
@Data
public class OrderExportBO {
    @ExcelProperty("订单号")
    @NotBlank(message = "订单号不能为空")
    private String scOrderPoolId;

    @ExcelProperty("金额")
    private String amount;
}

Service

java 复制代码
List<OrderExportVO> exportVOS = new ArrayList();
ExcelUtil.exportExcel(exportVOS, OrderExportVO.class);

详细代码

依赖

EasyExcel

XML 复制代码
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>2.2.11</version>
</dependency>

整个pom.xml

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.knife</groupId>
    <artifactId>demo_EasyExcel_SpringBoot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo_EasyExcel_SpringBoot</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>easyexcel</artifactId>
			<version>2.2.11</version>
		</dependency>

        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-boot-starter</artifactId>
            <version>3.0.3</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version>
            <scope>provided</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.0.RELEASE</version>
            </plugin>
        </plugins>
    </build>

</project>

Excel配置

字符串转换器

java 复制代码
package com.knife.excel.handler;


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;

public class StringConverter implements Converter<String> {

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

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

    /**
     * 将excel对象转成Java对象,这里读的时候会调用
     */
    @Override
    public String convertToJavaData(CellData cellData, 
ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
        return cellData.getStringValue().trim();
    }

    /**
     * 将Java对象转成String对象,写出的时候调用
     */
    @Override
    public CellData convertToExcelData(String value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
        return new CellData(value);
    }
}

writeHandler

java 复制代码
package com.knife.excel.halper;

import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.VerticalAlignment;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ExcelHandler extends AbstractColumnWidthStyleStrategy {

    private static final int MAX_COLUMN_WIDTH = 255;
    
    //因为在自动列宽的过程中,有些设置地方让列宽显得紧凑,所以做出了个判断
    private static final int COLUMN_WIDTH = 20;
    
    private  Map<Integer, Map<Integer, Integer>> CACHE = new HashMap(8);

    public ExcelHandler() {
    }

    @Override
    protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
        boolean needSetWidth = isHead || !CollectionUtils.isEmpty(cellDataList);
        if (needSetWidth) {
            Map<Integer, Integer> maxColumnWidthMap = (Map)CACHE.get(writeSheetHolder.getSheetNo());
            if (maxColumnWidthMap == null) {
                maxColumnWidthMap = new HashMap(16);
                CACHE.put(writeSheetHolder.getSheetNo(), maxColumnWidthMap);
            }

            Integer columnWidth = this.dataLength(cellDataList, cell, isHead);
            if (columnWidth >= 0) {
                if (columnWidth > MAX_COLUMN_WIDTH) {
                    columnWidth = MAX_COLUMN_WIDTH;
                }else {
                    if(columnWidth<COLUMN_WIDTH){
                        columnWidth =columnWidth*2;
                    }
                }

                Integer maxColumnWidth = (Integer)((Map)maxColumnWidthMap).get(cell.getColumnIndex());
                if (maxColumnWidth == null || columnWidth > maxColumnWidth) {
                    ((Map)maxColumnWidthMap).put(cell.getColumnIndex(), columnWidth);
                    writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(),  columnWidth* 256);
                }
            }
        }
    }

    private  Integer dataLength(List<CellData> cellDataList, Cell cell, Boolean isHead) {
        if (isHead) {
            return cell.getStringCellValue().getBytes().length;
        } else {
            CellData cellData = (CellData)cellDataList.get(0);
            CellDataTypeEnum type = cellData.getType();
            if (type == null) {
                return -1;
            } else {
                switch(type) {
                    case STRING:
                        return cellData.getStringValue().getBytes().length;
                    case BOOLEAN:
                        return cellData.getBooleanValue().toString().getBytes().length;
                    case NUMBER:
                        return cellData.getNumberValue().toString().getBytes().length;
                    default:
                        return -1;
                }
            }
        }
    }
    public static HorizontalCellStyleStrategy getStyleStrategy(){
        // 头的策略
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        // 背景设置为灰色
        headWriteCellStyle.setFillForegroundColor(IndexedColors.ROYAL_BLUE.getIndex());
        WriteFont headWriteFont = new WriteFont();
        headWriteFont.setFontHeightInPoints((short)11);
        // 字体样式
        headWriteFont.setFontName("Arial Unicode MS");
        headWriteFont.setColor(IndexedColors.WHITE.getIndex());
        headWriteCellStyle.setWriteFont(headWriteFont);
        //自动换行
        headWriteCellStyle.setWrapped(false);
        // 水平对齐方式
        headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        // 垂直对齐方式
        headWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);

        // 内容的策略
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        // 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定
        // contentWriteCellStyle.setFillPatternType(FillPatternType.SQUARES);
        // 背景白色
        contentWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
        WriteFont contentWriteFont = new WriteFont();
        // 字体大小
        contentWriteFont.setFontHeightInPoints((short)11);
        // 字体样式
        contentWriteFont.setFontName("宋体");
        contentWriteCellStyle.setWriteFont(contentWriteFont);
        //是否换行
        contentWriteCellStyle.setWrapped(false);
        //  垂直对齐方式
        contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现
        return new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
    }
}

数据校验

java 复制代码
package com.bondex.oms.excel;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.knife.util.BeanHelper;
import com.knife.util.ValidateUtil;

public class ExcelValidateListener<T> extends AnalysisEventListener<T> {
    @Override
    public void invoke(T bo, AnalysisContext analysisContext) {
        // 如果是空行,不处理
        if (BeanHelper.allFieldAreNull(bo)) {
            return;
        }

        int row = analysisContext.readRowHolder().getRowIndex() + 1;
        try {
            // 校验输入字段
            ValidateUtil.validate(bo);
        } catch (Exception e) {
            throw new RuntimeException("第[" + row + "]行数据校验失败:" + e.getMessage());
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {

    }
}

Bean工具

java 复制代码
package com.knife.util;

import org.springframework.beans.BeanUtils;
import org.springframework.cglib.core.ReflectUtils;
import org.springframework.util.CollectionUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class BeanHelper {
    public static <T> List<T> convert(List<?> sources, Class<T> target) {
        if (CollectionUtils.isEmpty(sources)) {
            return new ArrayList<>();
        }

        List<T> targets = new LinkedList<>();
        for (Object source : sources) {
            T t = null;
            try {
                t = target.newInstance();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }

            BeanUtils.copyProperties(source, t);
            targets.add(t);
        }

        return targets;
    }

    public static <T> T convert(Object source, Class<T> target) {
        if (source == null) {
            return null;
        }

        T t;
        try {
            t = target.newInstance();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        BeanUtils.copyProperties(source, t);
        return t;
    }

    public static boolean allFieldAreNull(Object o) {
        Class<?> aClass = o.getClass();

        PropertyDescriptor[] beanProperties = ReflectUtils.getBeanProperties(aClass);
        for (PropertyDescriptor beanProperty : beanProperties) {
            Method readMethod = beanProperty.getReadMethod();
            try {
                Object value = readMethod.invoke(o);
                if (value != null) {
                    return false;
                }
            } catch (IllegalAccessException | InvocationTargetException e) {
                throw new RuntimeException(e);
            }
        }

        return true;
    }
}

Excel工具类

java 复制代码
package com.bondex.oms.util;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.knife.entity.UserDTO;
import com.knife.util.UserDtoUtils;
import com.knife.excel.helper.ExcelHandler;
import com.knife.excel.helper.ExcelValidateListener;
import com.knife.excel.helper.HeadRowListener;
import com.knife.excel.helper.StringConverter;
import org.springframework.util.Assert;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Date;
import java.util.List;

public class ExcelUtil {
    public static <T> void exportExcel(List<T> dataList,
                                       Class<T> tClass) {

        ServletRequestAttributes servletRequestAttributes =
                (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();

        Assert.notNull(servletRequestAttributes, "RequestAttributes不能为null");

        HttpServletResponse response = servletRequestAttributes.getResponse();

        Assert.notNull(response, "Response不能为null");

        ServletOutputStream out = null;
        try {
            out = response.getOutputStream();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        String fileName = "测试文件.xlsx";
        try {
            // 必须要转一下,否则中文文件名会乱码
            fileName = URLEncoder.encode(fileName, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }

        // 通知浏览器以附件的形式下载处理,设置返回头要注意文件名有中文
        response.setHeader("Content-disposition", "attachment;filename=" + fileName);
        response.setContentType("multipart/form-data");
        response.setCharacterEncoding("utf-8");

        // 输出流到浏览器下载
        EasyExcel.write(out)
                .needHead(true)
                .head(tClass)
                .excelType(ExcelTypeEnum.XLSX)
                .autoCloseStream(true)
                .registerWriteHandler(new ExcelHandler())
                .registerWriteHandler(ExcelHandler.getStyleStrategy())
                .sheet(0, "Sheet1")
                .doWrite(dataList);
    }

    public static <T> List<T> importExcel(MultipartFile file, Class<T> tClass) {
        return importExcel(file, tClass, 1, null);
    }

    public static <T> List<T> importExcel(MultipartFile file, Class<T> tClass, String sheet) {
        return importExcel(file, tClass, 1, sheet);
    }

    public static <T> List<T> importExcel(MultipartFile file,
                                          Class<T> tClass,
                                          Integer headRowNumber,
                                          String sheet) {
        InputStream inputStream;
        try {
            inputStream = file.getInputStream();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        List<T> list = null;

        list = EasyExcel.read(inputStream)
                .registerConverter(new StringConverter())
                .registerReadListener(new ExcelValidateListener<T>())
                .head(tClass)
                // 可以指定sheet名字,不指定或null则表示第1个
                .sheet(sheet)
                .headRowNumber(headRowNumber)
                .doReadSync();

        list.removeIf(BeanHelper::allFieldAreNull);

        return list;
    }
}
相关推荐
CircleMouse6 小时前
如何设置wps单元格下拉选项设置
excel·wps
zhangjin122211 小时前
kettle插件-excel插件,kettle读取excel动态表头,kettle根据列名读取excel
excel·kettle·kettle excel插件·kettle 动态excel
远洪1 天前
excel 找出两列不同的数据
excel
pcplayer1 天前
非常好用的 Excel 读写控件
excel·delphi·office
Navicat中国1 天前
使用 Navicat 导入向导导入 Excel 数据时,系统提示导入成功,表中也能看到数据,但行数统计显示为 0,这是什么原因?
数据库·excel·导入
穿着内裤的外星人1 天前
触控精灵远程读写Excel步骤配置
excel
是孑然呀2 天前
【小记】excel vlookup一对多(第二篇)
excel
开开心心就好2 天前
专为视障人士设计的免费辅助工具
windows·计算机视觉·计算机外设·excel·散列表·推荐算法·csdn开发云
transformer_WSZ2 天前
excel两列数据绘制折线图
excel·折线图
蒋胜山2 天前
Excel 练习题(5)
经验分享·excel