Java如何实现Excel的导入与导出?

Java如何实现Excel的导入与导出?

一、核心依赖及简要介绍

1、POI是什么?

Apache POI - the Java API for Microsoft Documents,顾名思义,Apache的三方包,用来操作微软office文档的,多数时候用来操作excel,所以这里就以excel方面来说明。POI的组件列表中,针对excel的主要是HSSF和XSSF组件,前者针对97-2007的通用版excel,即后缀xls;后者针对2007或更高版的excel,即后缀xlsx。

2、POI核心类

面向对象面向对象,既然如此,自然去找找一些能表示excel中内容的类。

2.1 工作簿 Workbook

Workbook是创建或维护Excel工作簿的所有类的超接口,属于org.apache.poi.ss.usermodel包。其下有两个实现类:

  • HSSFWorkbook : 有读取.xlsx 格式和写入Microsoft Excel文件的方法。它与微软Office97-2003版本兼容

  • XSSFWorkbook : 有读写Microsoft Excel和OpenOffice的XML文件的格式.xls或.xlsx的方法。它与MS-Office版本2007或更高版本兼容

所以在针对不同版本的excel时,需要对应以上使用不同的Workbook。构造函数中,常用的:

HSSFWorkbook

//直接创建新的
new HSSFWorkbook()

//通过输入流创建
new HSSFWorkbook(java.io.InputStream InputStream)

XSSFWorkbook

//直接创建新的
new XSSFWorkbook()
//通过File类创建
new XSSFWorkbook(java.io.File file)
//通过输入流创建
new XSSFWorkbook(java.io.InputStream is)
2.2 标签页 Sheet

HSSFSheet 和 XSSFSheet 都是Sheet接口的实现类,Sheet可以使用Workbook的两个方法获得:

workbook.createSheet();
workbook.createSheet(String sheetName);
2.3 行 Row

同理,Row是 HSSFRow 和 XSSFRow 的接口,通过Sheet获取:

// rownum为行索引下标
sheet.createRow(int rownum);
2.4 单元格 Cell

同理,Cell是 HSSFCell 和 XSSFCell 的接口,通过Row获取:

// column为行索引下标
row.createCell(int column);
row.createCell(int column, int type);

二、代码的具体实现

1、导入相关依赖

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>4.0.1</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>4.0.1</version>
</dependency>

2、编写相应的工具类

2.1 Excel 注解类
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * @since 2021/7/12 9:19
 */
@Retention(RetentionPolicy.RUNTIME)
public @interface Excel {
    // 标题(类上注解中填写该属性,不可省略)
    String title() default "";
    // 列名(可省略,省略默认为属性名)
    String name() default "";
    // 列的宽度(默认12)
    int columnWidth() default 12;
    // 标题行的高度(默认24)
    int titleRowHeight() default 24;
    // 属性行的高度(默认20)
    int attributeRowHeight() default 20;
    // 内容行的高度(默认18)
    int contentRowHeight() default 18;
    // 单元格数据的类型(默认是String类型)
    ExcelType type() default ExcelType.String;
    // 单元格数据格式化的样式
    // 当@Excel中指定type为ExcelType.Date或者ExcelType.Number时,可以指定格式化样式
    String format() default "";
}
2.2 ExcelType 枚举类
import lombok.Data;

/**
 * @since 2021/7/12 17:44
 */
public enum ExcelType {

    /**
     * 字符类型
     */
    String("字符类型"),
    /**
     * 时间类型
     */
    Date("时间类型"),
    /**
     * 数字类型
     */
    Number("数字类型"),
    /**
     * boolean类型
     */
    Boolean("boolean类型");

    private String message;

    ExcelType(String message){
        this.message = message;
    }

}
2.3 ExcelUtil 工具类
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.HSSFDataFormat;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.*;

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @since 2021/7/12 9:18
 */
@Slf4j
public class ExcelUtil<T> {

    Class<T> clazz;

    public ExcelUtil(Class<T> clazz){
        this.clazz = clazz;
    }

    /**
     * 将List<T>对象转换成Excel表格并输出到指定流,其中<T>为对象的类型,在对象中用@Excel注解进行参数配置
     * @param list 数据对象
     * @param outputStream 输出的Excel文件流
     */
    public void exportExcel(List<T> list, OutputStream outputStream){
        // 创建空白工作簿
        XSSFWorkbook workbook = new XSSFWorkbook();
        try {
            String sheetName = "";
            String titleName = "";
            // 获取该类的所有字段
            Field[] fields = clazz.getDeclaredFields();
            int titleRowHeight;
            int attributeRowHeight;
            int contentRowHeight;
            // 如果这个类上有@Excel注解
            if (clazz.isAnnotationPresent(Excel.class)) {
                Excel excel = (Excel) clazz.getAnnotation(Excel.class);
                titleName = excel.title();
                sheetName = titleName;
                titleRowHeight = excel.titleRowHeight();
                attributeRowHeight = excel.attributeRowHeight();
                contentRowHeight = excel.contentRowHeight();
            }else {
                throw new RuntimeException("该实体类缺少@Excel注解,不能转换");
            }
            // 创建sheet
            Sheet sheet = workbook.createSheet(sheetName);
            // 创建标题行
            Row titleRow = sheet.createRow(0);
            titleRow.setHeightInPoints(titleRowHeight);
            Cell titleCell = titleRow.createCell(0);
            // 创建标题行的样式
            XSSFCellStyle titleCellStyle = workbook.createCellStyle();
            // 设置单元格格式居中对齐
            titleCellStyle.setAlignment(HorizontalAlignment.CENTER);
            titleCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
            // 如果需要前景颜色或背景颜色,一定要指定填充方式,两者顺序无所谓,如果同时存在前景颜色和背景颜色,前景颜色的设置要写在前面
            titleCellStyle.setFillPattern(FillPatternType.LEAST_DOTS);
            titleCellStyle.setFillBackgroundColor(IndexedColors.LIGHT_YELLOW.index);
            // 设置字体
            XSSFFont font = workbook.createFont();
            // 设置sheet默认的列宽12
            sheet.setDefaultColumnWidth(12);
            font.setBold(true);
            font.setColor(IndexedColors.RED.index);
            font.setFamily(FontFamily.ROMAN);
            // 调整字体大小
            font.setFontHeightInPoints((short) 14);
            // 将字体样式加入到单元格样式中
            titleCellStyle.setFont(font);
            titleCell.setCellValue(titleName);
            // 将单元格样式应用到单元格中
            titleCell.setCellStyle(titleCellStyle);
            int cols = 0;
            // 遍历字段,统计出需要导出的字段总数
            for (int j = 0; j < fields.length; j++) {
                // 如果字段上有@Excel注解,则表明需要导出,否则不需要
                if (fields[j].isAnnotationPresent(Excel.class)) {
                    cols++;
                }
            }
            sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, cols - 1));
            // 创建属性列名
            Row attributeRow = sheet.createRow(1);
            // 创建属性行的样式
            XSSFCellStyle attributeCellStyle = workbook.createCellStyle();
            attributeCellStyle.setAlignment(HorizontalAlignment.CENTER);
            attributeCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
            // 如果需要前景颜色或背景颜色,一定要指定填充方式,两者顺序无所谓,如果同时存在前景颜色和背景颜色,前景颜色的设置要写在前面
            attributeCellStyle.setFillPattern(FillPatternType.FINE_DOTS);
            attributeCellStyle.setFillBackgroundColor(IndexedColors.GREY_40_PERCENT.index);
            // 记录当前单元格的索引位置
            int attributeCurrent = 0;
            // 设置属性行的高度
            attributeRow.setHeightInPoints(attributeRowHeight);
            for (int k = 0; k < fields.length; k++) {
                // 如果字段上没有@Excel注解,则不导出
                if (!fields[k].isAnnotationPresent(Excel.class)) {
                    continue;
                }
                // 创建单元格
                Cell cell = attributeRow.createCell(attributeCurrent);
                // 获取字段名
                String columnName = fields[k].getName();
                // 设置默认列宽为12
                int columnWidth = 12;
                if (fields[k].isAnnotationPresent(Excel.class)) {
                    Excel excel = fields[k].getAnnotation(Excel.class);
                    // 如果@Excel注解上的name属性不为空,则
                    if(!"".equals(excel.name())){
                        columnName = excel.name();
                    }
                    columnWidth = excel.columnWidth();
                }
                cell.setCellValue(columnName);
                // 设置指定列的列宽,256 * 50这种写法是因为width参数单位是单个字符的256分之一
                sheet.setColumnWidth(attributeCurrent, columnWidth * 256);
                // 设置样式
                cell.setCellStyle(attributeCellStyle);
                // 设置单元格的下一个索引位置
                attributeCurrent++;
            }
            // 写入数据
            for (int i = 0; i < list.size(); i++) {
                // 从第三行开始写入数据
                Row contentRow = sheet.createRow(i + 2);
                // 设置正文内容的行高
                contentRow.setHeightInPoints(contentRowHeight);
                // 记录当前单元格的索引位置
                int current = 0;
                for (int j = 0; j < fields.length; j++) {
                    // 如果字段上没有@Excel注解,则不导出
                    if (!fields[j].isAnnotationPresent(Excel.class)) {
                        continue;
                    }
                    // 创建单元格
                    Cell cell = contentRow.createCell(current);
                    // 设置单元格的下一个索引位置
                    current++;
                    // 获取字段名称
                    String fieldName = fields[j].getName();
                    // 获取字段类型
                    Class<?> fieldType = fields[j].getType();
                    // 获取字段类型的名称
                    String fieldTypeName = fields[j].getType().getName();
                    // 获取该字段的get方法名
                    String fieldFirstLetterUpper = fieldName.substring(0, 1).toUpperCase();
                    String prefix = "get";
                    if ("boolean".equals(fieldTypeName)) {
                        prefix = "is";
                    }
                    // 拼接出get方法名
                    String methodName = prefix + fieldFirstLetterUpper + fieldName.substring(1);
                    // 获取该get方法
                    Method method = clazz.getMethod(methodName);
                    // 默认类型都为String类型填充
                    ExcelType type = ExcelType.String;
                    String format = "";
                    if (fields[j].isAnnotationPresent(Excel.class)) {
                        Excel excel = fields[j].getAnnotation(Excel.class);
                        // 获取@Excel注解中的字段属性类型
                        type = excel.type();
                        // 获取格式
                        format = excel.format();
                    }
                    // 字符串类型
                    if(ExcelType.String.equals(type)){
                        // 字符串类型
                        XSSFCellStyle stringCellStyle = workbook.createCellStyle();
                        stringCellStyle.setAlignment(HorizontalAlignment.CENTER);
                        stringCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
                        // 填入数据
                        cell.setCellValue((String) method.invoke(list.get(i)));
                        cell.setCellStyle(stringCellStyle);
                    }
                    // 日期类型
                    else if(ExcelType.Date.equals(type)){
                        // 日期格式
                        XSSFCellStyle dateCellStyle = workbook.createCellStyle();
                        dateCellStyle.setAlignment(HorizontalAlignment.CENTER);
                        dateCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
                        XSSFDataFormat dataFormat = workbook.createDataFormat();
                        if("".equals(format)){
                            // 默认的日期格式
                            dateCellStyle.setDataFormat(dataFormat.getFormat("yyyy-MM-dd"));
                        }else {
                            // 指定的日期格式
                            dateCellStyle.setDataFormat(dataFormat.getFormat(format));
                        }
                        // 填入数据
                        cell.setCellValue((Date) method.invoke(list.get(i)));
                        cell.setCellStyle(dateCellStyle);
                    }
                    // 数字类型
                    else if(ExcelType.Number.equals(type)){
                        // 数字格式
                        XSSFCellStyle numberCellStyle = workbook.createCellStyle();
                        numberCellStyle.setAlignment(HorizontalAlignment.CENTER);
                        numberCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
                        if("".equals(format)){
                            // 默认的数字格式
                            numberCellStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat("#0"));
                        }else {
                            // 指定的数字格式
                            numberCellStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat(format));
                        }
                        // method.invoke(list.get(i))返回的有可能是Integer、Long、Float、Double、BigDecimal
                        if(Float.class == fieldType || Float.TYPE == fieldType){
                            // 将Float类型的数据转换成Double类型填入单元格,否则精度有问题
                            cell.setCellValue(((Float)method.invoke(list.get(i))).doubleValue());
                        }else if(BigDecimal.class == fieldType){
                            // 将BigDecimal类型的数据转换成Double类型填入单元格
                            cell.setCellValue(((BigDecimal)method.invoke(list.get(i))).doubleValue());
                        }else if(Integer.class == fieldType || Integer.TYPE == fieldType){
                            cell.setCellValue((Integer)method.invoke(list.get(i)));
                        }else if(Double.class == fieldType || Double.TYPE == fieldType){
                            cell.setCellValue((Double)method.invoke(list.get(i)));
                        }else if(Long.class == fieldType || Long.TYPE == fieldType){
                            // Long类型时,数值太大会出现科学计数法
                            cell.setCellValue((Long)method.invoke(list.get(i)));
                        }
                        cell.setCellStyle(numberCellStyle);
                    }else if(ExcelType.Boolean.equals(type)){
                        // Boolean格式
                        XSSFCellStyle booleanCellStyle = workbook.createCellStyle();
                        booleanCellStyle.setAlignment(HorizontalAlignment.CENTER);
                        booleanCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
                        Boolean result = (Boolean) method.invoke(list.get(i));
                        // 将true和false分别映射成是和否填入单元格
                        cell.setCellValue(result ? "是" : "否");
                        cell.setCellStyle(booleanCellStyle);
                    }

                }
            }
            log.info("数据导出Excel完毕");
            // 写出到输出流中
            workbook.write(outputStream);
            // 关闭资源
            workbook.close();
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 将导入的Excel文件流转换成List<T>数据对象集合
     * @param input 导入的Excel文件流
     * @return List<T>数据对象集合
     */
    public  List<T> importExcel(InputStream input) {
        // 创建List数据对象集合
        List<T> list = new ArrayList<T>();
        try {
            // 读取Excel文件流,创建工作簿
            XSSFWorkbook workbook = new XSSFWorkbook(input);
            // 获取Excel中的第一个sheet
            Sheet sheet = workbook.getSheetAt(0);
            // 获取总行数
            int rows = sheet.getPhysicalNumberOfRows();
            // 有数据时才处理(前两行是标题和属性)
            if (rows > 2) {
                // 获取所有字段
                Field[] fields = clazz.getDeclaredFields();
                // 从索引为2开始创建行,即第三行开始
                int firstRowNum = 2;
                // 获取最后一行的索引
                int lastRowNum = sheet.getLastRowNum();
                // 一行一行获取数据,并填入对象中
                for (int j = firstRowNum; j <= lastRowNum; j++) {
                    // 获取行
                    Row row = sheet.getRow(j);
                    // 记录当前单元格的索引
                    int current = 0;
                    // 创建对象
                    T entity = null;
                    // 遍历字段
                    for (int i = 0; i < fields.length; i++) {
                        Field field = fields[i];
                        // 如果字段上没有@Excel注解,表明它不需要导出,所以不填入数据
                        if (!field.isAnnotationPresent(Excel.class)) {
                            continue;
                        }
                        // 获取当前单元格
                        XSSFCell cell = (XSSFCell) row.getCell(current);
                        // 将当前单元格的数据依据类型和格式转换成对应的字符串
                        String cellValue = getCellValue(cell, field);
                        // 创建对象
                        entity = (entity == null ? clazz.newInstance() : entity);
                        // 将数据填充到对象所对应的字段中
                        cell2Field(entity, cellValue, field);
                        // 记录下一个单元格的索引位置
                        current++;
                    }
                    // 将填充好的对象加入到集合中
                    if (entity != null) {
                        list.add(entity);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }

    /**
     * 将数据填充到对象所对应的字段中
     * @param entity 对象
     * @param cell 数据
     * @param field 字段
     */
    private void cell2Field(T entity, String cell, Field field) throws IllegalAccessException, ParseException, NoSuchMethodException, InvocationTargetException {
        // 获取字段类型
        Class<?> fieldType = field.getType();
        // 获取字段名称
        String fieldName = field.getName();
        // 获取该字段的set方法名
        String methodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
        // 获取该set方法
        Method method = clazz.getMethod(methodName, fieldType);
        if (String.class == fieldType) {
            method.invoke(entity, cell);
        }
        // 处理数字特殊类型
        else if ((Integer.TYPE == fieldType) || (Integer.class == fieldType)) {
            // Integer的1导出到Excel中显示为1,但从Excel中读取到的cell单元格的值却为1.0,所以需要去除小数点
            if(cell.contains(".")){
                cell = cell.substring(0, cell.indexOf("."));
            }
            // 如果该字段为Integer类型,则转换为Integer类型再写入字段
            method.invoke(entity, Integer.valueOf(cell));
        } else if ((Long.TYPE == fieldType) || (Long.class == fieldType)) {
            // 有时Excel表格中会误输入带小数点的数据,如124235789512.00,则需要去除小数点,否则设置字段值会出错
            if(cell.contains(".")){
                cell = cell.substring(0, cell.indexOf("."));
            }
            // 如果该字段为Long类型,则转换为Long类型再写入字段
            method.invoke(entity, Long.valueOf(cell));
        } else if ((Float.TYPE == fieldType) || (Float.class == fieldType)) {
            // 如果该字段为Float类型,则转换为Float类型再写入字段
            method.invoke(entity, Float.valueOf(cell));
        }  else if ((Double.TYPE == fieldType) || (Double.class == fieldType)) {
            // 如果该字段为Double类型,则转换为Double类型再写入字段
            method.invoke(entity, Double.valueOf(cell));
        }else if ((BigDecimal.class == fieldType)) {
            // 如果该字段为BigDecimal类型,则转换为BigDecimal类型再写入字段
            method.invoke(entity, new BigDecimal(cell));
        }
        // 处理日期特殊类型(如果该字段为日期类型)
        else if(Date.class == fieldType){
            if (field.isAnnotationPresent(Excel.class)) {
                Excel excel = field.getAnnotation(Excel.class);
                // 获取@Excel上指定的日期格式
                String format = excel.format();
                // 如果未指定日期格式,则使用默认格式
                if("".equals(format)){
                    format = "yyyy-MM-dd";
                }
                // 按照格式解析字符串为日期
                Date date = new SimpleDateFormat(format).parse(cell);
                // 填入字段
                method.invoke(entity, date);
            }
        }
        // 处理boolean特殊类型
        else if(Boolean.class == fieldType || Boolean.TYPE == fieldType){
            // 转换成true或false填入字段
            Boolean result = "是".equals(cell);
            method.invoke(entity, result);
        }
    }


    /**
     * 依据单元格的数据类型进行相应的处理,并返回相应的字符串数据
     * @param cell 单元格
     * @param field 字段(可以获取字段上的注解信息)
     * @return 字符串单元格数据
     */
    private String getCellValue(XSSFCell cell, Field field) {
        String value = null;
        // 如果单元格不为空才处理
        if (cell != null) {
            // 依据单元格数据的类型进行相应的处理,并返回字符串单元格数据
            switch (cell.getCellType()) {
                // 单元格是函数计算出来的数据
                case FORMULA:
                    try {
                        value = String.valueOf(cell.getNumericCellValue());
                    } catch (Exception e) {
                        value = String.valueOf(cell.getRichStringCellValue());
                    }
                    break;
                // 单元格是数字类型的(包括数字和日期)
                case NUMERIC:
                    // 获取单元格的样式值,即获取单元格格式对应的数值
                    int style = cell.getCellStyle().getDataFormat();
                    // 判断是否是日期格式
                    if (HSSFDateUtil.isCellDateFormatted(cell)) {
                        // 获取单元格的日期
                        Date date = cell.getDateCellValue();
                        // 日期格式化样式
                        String format;
                        // 获取字段上注解中指定的格式化样式
                        Excel excel = field.getAnnotation(Excel.class);
                        format = excel.format();
                        // 如果为指定格式化样式,则使用默认格式化样式
                        if("".equals(format)){
                            format = "yyyy-MM-dd";
                        }
                        // 将日期格式化成对应的字符串
                        value = new SimpleDateFormat(format).format(date);
                    }
                    // 数字类型
                    else {
                        switch (style) {
                            // 单元格格式为百分比,不格式化会直接以小数输出
                            case 9:
                                value = new DecimalFormat("0.00%").format(cell.getNumericCellValue());
                                break;
                            default:
                                // 获取数字类型的单元格数据
                                value = String.valueOf(cell.getNumericCellValue());
                                // 处理科学计数法
                                if(value.contains("E")){
                                    // value = 2.01720181436E11
                                    BigDecimal number = new BigDecimal(value);
                                    // 201720181436
                                    value = number.toString();
                                }
                                // 去除excel中数字类型自带的千位分隔符(1,256.4)
                                value = value.replace(",", "");
                                break;
                        }
                    }
                    break;
                // 单元格是字符串类型的
                case STRING:
                    value = String.valueOf(cell.getRichStringCellValue());
                    break;
                default:
                    break;
            }
        }
        return value;
    }
}

3、实体类

import cn.ecut.file.excel.util.Excel;
import cn.ecut.file.excel.util.ExcelType;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.math.BigDecimal;
import java.util.Date;

/**
 * @since 2021/7/12 9:01
 * 类上@Excel注解中必须指定title属性
 * 类上@Excel注解中的titleRowHeight属性可指定标题的行高(默认24)
 * 类上@Excel注解中的attributeRowHeight属性可指定列名的行高(默认20)
 * 类上@Excel注解中的contentRowHeight属性可指定正文内容的行高(默认18)
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Excel(title = "学生信息登记表")
public class Student {

    /**
     * ID
     * name(可省略)指定生成的Excel列名,如省略name属性,则用字段名生成Excel列名
     * type 默认为ExcelType.String类型,当字段为String类型时,可省略该属性,否则必须指定type
     * columnWidth 指定该列的宽度,默认为12
     */
    @Excel(name = "序号", type = ExcelType.Number, columnWidth = 8)
    private Integer id;

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

    /**
     * 性别
     */
    @Excel(name = "性别")
    private String sex;

    /**
     * 年龄
     */
    @Excel(name = "年龄", type = ExcelType.Number)
    private Integer age;

    /**
     * 出生日
     * 当type为ExcelType.Date或者ExcelType.Number时,可以通过format属性指定格式化样式
     * 当type=ExcelType.Date时,默认样式为yyyy-MM-dd
     */
    @Excel(name = "出生日期", type = ExcelType.Date, format = "yyyy-MM-dd")
    private Date birthday;

    /**
     * 手机号
     */
    @Excel(name = "手机号", columnWidth = 15)
    private String phone;

    /**
     * 已缴学费
     * 当type为ExcelType.Date或者ExcelType.Number时,可以通过format属性指定格式化样式
     * 当type=ExcelType.Number时,默认样式为#0
     */
    @Excel(name = "已缴学费", type = ExcelType.Number, format = "#,##0.00")
    private BigDecimal money;

     /**
     * 是否毕业
     * 当type为ExcelType.Boolean时,true和false会转换成相应的是和否
     */
    @Excel(name = "是否毕业", type = ExcelType.Boolean)
    private Boolean graduate;

    /**
     * 通讯地址
     * 若字段不声明@Excel注解,则表明该属性不需要导出到Excel中
     */
    private String address;

}

4、Service层代码的实现

import cn.ecut.file.excel.entity.Student;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * @since 2021/7/12 9:00
 */
public interface ExcelCustomService {

    /**
     * 导出Excel表格
     * @param response
     * @throws IOException
     */
    void exportExcel(HttpServletResponse response) throws IOException;

    /**
     * 导入Excel表格,将Excel数据转换成List集合数据
     * @param inputStream
     * @return
     */
    List<Student> importExcel(InputStream inputStream);
}
import cn.ecut.file.excel.entity.Student;
import cn.ecut.file.excel.service.ExcelCustomService;
import cn.ecut.file.excel.util.ExcelUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

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

/**
 * @since 2021/7/12 9:00
 */
@Service
@Slf4j
public class ExcelCustomServiceImpl implements ExcelCustomService {

	// 声明默认数据
    private static List<Student> students = new ArrayList<>();

    static {
        Student student1 = new Student(1, "张三", "男", 23, new Date(), "18842568124", new BigDecimal("1256.4"), true, null);
        Student student2 = new Student(2, "李四", "男", 21, new Date(), null,  new BigDecimal("58.1"), false, null);
        Student student3 = new Student(3, "王五", "女", 20, new Date(), null,  new BigDecimal("1456"), true, null);
        students.add(student1);
        students.add(student2);
        students.add(student3);
    }

    @Override
    public void exportExcel(HttpServletResponse response) throws IOException {
        String fileName = "学生信息表汇总.xlsx";
        fileName = URLEncoder.encode(fileName, "UTF-8");
        response.setContentType("application/force-download");
        response.setHeader("Content-Disposition", "attachment;fileName=" + fileName);
        ServletOutputStream outputStream = response.getOutputStream();
        // 将List数据集合导出到Excel中
        new ExcelUtil<Student>(Student.class).exportExcel(students, outputStream);
    }

    @Override
    public List<Student> importExcel(InputStream inputStream) {
        // 将Excel中的数据转换成List数据集合
        return new ExcelUtil<Student>(Student.class).importExcel(inputStream);
    }
}

5、Controller层的实现

import cn.ecut.file.excel.entity.Student;
import cn.ecut.file.excel.service.ExcelCustomService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * @since 2021/7/12 8:59
 */
@RestController
@RequestMapping("/excel")
@Api(value = "EXCEL相关操作接口", tags = "EXCEL相关操作接口")
public class ExcelController {

    @Autowired
    private ExcelCustomService excelCustomService;

    @GetMapping("/exportExcel")
    @ApiOperation(value = "导出Excel")
    public void exportExcel(HttpServletResponse response){
        try {
            excelCustomService.exportExcel(response);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @PostMapping("/importExcel")
    @ApiOperation(value = "导入Excel")
    public List<Student> importExcel(MultipartFile file){
        List<Student> list = new ArrayList<>();
        try {
            InputStream inputStream = file.getInputStream();
            list = excelCustomService.importExcel(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }
}

三、测试效果

在这里插入图片描述

1、Excel的导出测试

请求接口,下载导出的Excel文件

在这里插入图片描述

打开Excel表格

在这里插入图片描述

2、Excel的导入测试

请求接口,上传Excel表格

在这里插入图片描述

响应结果正确,完美导入

在这里插入图片描述

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

总是提示已注册

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值