利用POI实现Excel导入导出工具类(包含样式)

说明:

1、代码实现了将表格内容与Collection<T>之间的转换,T代表对应的实体类。

2、表格内容可以设置起始行和起始列,如需扩展可根据代码继续扩展。

3、此文章参考了多篇文章,仅学习用。

目录

一、导入依赖

二、Annotation

三、实体类

四、excel工具类

五、设置标题与内容样式

六、测试类


代码只是看着有点多,实际上不会很难,希望看完后对您有所帮助,同时也欢迎大家积极交流学习!

一、导入依赖

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

二、Annotation

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 注解
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ExcelAnnotation {
    // excel导出时标题显示的名字,如果没有设置Annotation属性,将不会被导出和导入
    String exportName();
}

三、实体类

import com.innovative.annotation.ExcelAnnotation;
import lombok.Getter;
import lombok.Setter;

import java.util.Date;

/**
 * 用于测试excel工具类的dto
 */
@Getter
@Setter
public class TestDTO {
    @ExcelAnnotation(exportName = "用户名")
    String userName;
    @ExcelAnnotation(exportName = "登录名")
    String loginName;
    @ExcelAnnotation(exportName = "年龄")
    Integer age;
    @ExcelAnnotation(exportName = "收入")
    Long money;
    @ExcelAnnotation(exportName = "时间")
    Date createTime;
}

四、excel工具类

import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.util.*;

import com.innovative.annotation.ExcelAnnotation;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

/**
 * Excel工具类
 */
public class ExcelUtils<T> {

    /**
     * 导入导出的类
     */
    Class<T> clazz;

    /**
     * 日期格式
     */
    private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

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

    /**
     * 导出excel表格
     *
     * @param sheetName sheet标题(默认值为Sheet1)
     * @param startRow  起始行号(第一行是标题,内容接在其后)
     * @param startCol  起始列号(默认值为0)
     * @param dataset   需要导出的数据集合(默认值为0)
     * @param out       输出流
     */
    public void exportExcel(String sheetName, Integer startRow, Integer startCol,
                            Collection<T> dataset, OutputStream out) throws Exception{
        // 参数校验
        if(Objects.isNull(dataset) || dataset.isEmpty()) {
            System.out.println("导出数据为空!");
            return;
        }
        if(Objects.isNull(out)){
            throw new Exception("输出流为空!");
        }
        sheetName = StringUtils.isNotBlank(sheetName) ? sheetName : "Sheet1";
        startRow = Objects.isNull(startRow) ? 0 : startRow;
        startCol = Objects.isNull(startCol) ? 0 : startCol;

        // 得到所有字段
        Field[] fields = clazz.getDeclaredFields();

        List<String> titleList = new ArrayList<>();
        List<Method> getMethodList = new ArrayList<>();
        // 遍历所有filed
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            ExcelAnnotation excelAnnotation = field.getAnnotation(ExcelAnnotation.class);
            // 如果设置了annotation,则需要添加到标题集合中并解析出get方法
            if (excelAnnotation != null) {
                String exportName = excelAnnotation.exportName();
                // 添加到标题列表
                titleList.add(exportName);
                // 需要导出字段get方法名
                String fieldName = field.getName();
                String getMethodName = "get"
                        + fieldName.substring(0, 1).toUpperCase()
                        + fieldName.substring(1);
                // 将get方法添加到集合中
                Method getMethod = clazz.getMethod(getMethodName);
                getMethodList.add(getMethod);
            }
        }
        // 集合的迭代器
        Iterator<T> its = dataset.iterator();
        // 在内存中创建一个Excel文件对象
        XSSFWorkbook workbook = new XSSFWorkbook();
        // 创建Sheet页
        XSSFSheet sheet = workbook.createSheet(sheetName);
        // 设置表格默认列宽度为20个字节
        sheet.setDefaultColumnWidth(20);

        // 写入标题行
        XSSFCellStyle titleStyle = workbook.createCellStyle();
        ExcelStyle.setTitleStyle(workbook, titleStyle);

        XSSFRow titleRow = sheet.createRow(startRow);
        for (int i = 0; i < titleList.size(); i++) {
            // 创建单元格并设置标题
            XSSFCell cell = titleRow.createCell(startCol + i);
            cell.setCellStyle(titleStyle);
            XSSFRichTextString text = new XSSFRichTextString(titleList.get(i));
            cell.setCellValue(text);
        }
        // 写入所有内容行
        XSSFCellStyle bodyStyle = workbook.createCellStyle();
        ExcelStyle.setBodyStyle(workbook, bodyStyle);

        int index = startRow;
        XSSFRow bodyRow = null;
        while (its.hasNext()) {
            //从第startRow+1行开始写,第startRow行是标题
            index++;
            bodyRow = sheet.createRow(index);
            T curObject = (T) its.next();
            for (int k = 0; k < getMethodList.size(); k++) {
                XSSFCell cell = bodyRow.createCell(startCol + k);
                cell.setCellStyle(bodyStyle);
                Method getMethod = getMethodList.get(k);
                Object value = getMethod.invoke(curObject);
                String textValue = getValue(value);
                cell.setCellValue(textValue);
            }
        }
        workbook.write(out);
        // 关闭资源
        workbook.close();
    }

    /**
     * 根据不同类型获取对应的内容(导出用)
     * @param value
     * @return
     */
    public String getValue(Object value) {
        String textValue = "";
        if (value == null) return textValue;
        if (value instanceof Boolean bValue) {
            textValue = "是";
            if (!bValue) {
                textValue = "否";
            }
        } else if (value instanceof Date date) {
            textValue = dateFormat.format(date);
        } else {
            textValue = value.toString();
        }
        return textValue;
    }

    /**
     * 导入excel表格成Collection<T>
     * @param file
     * @param sheetName
     * @param startRow
     * @param startCol
     * @return
     * @throws Exception
     */
    public Collection<T> importExcel(File file, String sheetName, Integer startRow, Integer startCol) throws Exception{
        // 参数校验
        if(Objects.isNull(file)){
            System.out.println("文件为空!");
            return null;
        }
        if(!file.getName().endsWith(".xlsx")){
            throw new Exception("文件格式错误!");
        }
        startRow = Objects.isNull(startRow) ? 0 : startRow;
        startCol = Objects.isNull(startCol) ? 0 : startCol;

        Field[] fields = clazz.getDeclaredFields();
        // 标有Annotation的字段标题名以及对应的set方法
        Map<String, Method> fieldMap = new HashMap<>();
        // 循环读取所有字段,找到标有Annotation的字段并将字段标题名和对应的set方法存到map中
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            ExcelAnnotation excelAnnotation = field.getAnnotation(ExcelAnnotation.class);
            if (excelAnnotation != null) {
                String fieldName = field.getName();
                String setMethodName = "set"
                        + fieldName.substring(0, 1).toUpperCase()
                        + fieldName.substring(1);
                Method setMethod = clazz.getMethod(setMethodName, field.getType());
                // 将这个method以Annotation的名字为key来存入
                fieldMap.put(excelAnnotation.exportName(), setMethod);
            }
        }

        // 将传入的File构造为FileInputStream;
        FileInputStream in = new FileInputStream(file);
        // 通过输入流读取指定的Excel文件
        XSSFWorkbook workbook = new XSSFWorkbook(in);
        // 得到对应sheet页
        XSSFSheet sheet = StringUtils.isNotBlank(sheetName) ?
                workbook.getSheet(sheetName) : workbook.getSheetAt(0);

        // 得到标题行
        XSSFRow titleRow = sheet.getRow(startRow);
        // key:列号,value:对应标题名称
        Map<Integer, String> titleMap = new HashMap<>();
        // 获取标题行中的最后一列的列号
        int lastColNum = titleRow.getLastCellNum();
        for(int i = startCol; i < lastColNum; i++){
            Cell cell = titleRow.getCell(i);
            String value = cell.getStringCellValue();
            titleMap.put(i, value);
        }

        // 解析内容
        startRow++;
        Collection<T> dataset = new ArrayList<>();
        // 获取Sheet页中的最后一行的行号
        int lastRowNum = sheet.getLastRowNum();
        while(startRow <= lastRowNum){
            Row bodyRow = sheet.getRow(startRow);
            // 创建传入类的实例
            T curObject = clazz.newInstance();
            for(int i = startCol; i <= lastColNum; i++){
                Cell cell = bodyRow.getCell(i);
                // 此列对应的标题
                String titleName = titleMap.get(i);
                // 如果这一列的标题和类中的某一列的Annotation相同,则调用此类的的set方法,进行设值
                if (fieldMap.containsKey(titleName)) {
                    Method setMethod = fieldMap.get(titleName);
                    // 得到setter方法的参数列表
                    Type[] parameterTypes = setMethod.getGenericParameterTypes();
                    // 只需要第一个参数的类型
                    String paramType = parameterTypes[0].toString();
                    cell.setCellType(CellType.STRING);
                    if (paramType.equals("class java.lang.String")) {
                        setMethod.invoke(curObject, cell.getStringCellValue());
                    } else if (paramType.equals("class java.util.Date")) {
                        setMethod.invoke(curObject, dateFormat.parse(cell.getStringCellValue()));
                    } else if (paramType.equals("class java.lang.Boolean")) {
                        Boolean boolname = true;
                        if (cell.getStringCellValue().equals("否")) {
                            boolname = false;
                        }
                        setMethod.invoke(curObject, boolname);
                    } else if (paramType.equals("class java.lang.Integer")) {
                        setMethod.invoke(curObject, Integer.parseInt(cell.getStringCellValue()));
                    } else if (paramType.equals("class java.lang.Long")) {
                        setMethod.invoke(curObject, Long.parseLong(cell.getStringCellValue()));
                    }
                }
            }
            dataset.add(curObject);
            startRow++;
        }
        return dataset;
    }
}

五、设置标题与内容样式

import java.awt.Color;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

/**
 * Excel单元格样式
 */
public class ExcelStyle {
    /**
     * 表格标题单元格样式
     * @param workbook
     * @param style
     * @return
     */
    public static XSSFCellStyle setTitleStyle(XSSFWorkbook workbook, XSSFCellStyle style) {
        // 设置背景色
        style.setFillForegroundColor(new XSSFColor(new Color(255,255,255)));
        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        // 设置边框
        style.setBorderBottom(XSSFCellStyle.BORDER_THIN); // 下边框
        style.setBorderRight(XSSFCellStyle.BORDER_THIN);// 右边框
        style.setBorderLeft(XSSFCellStyle.BORDER_THIN);// 左边框
        style.setBorderTop(XSSFCellStyle.BORDER_THIN);// 上边框
        // 设置单元格的中心水平对齐-居中
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        // 设置单元格的垂直对齐类型-居中
        style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
        // 生成字体
        XSSFFont font = workbook.createFont();
        // 设置字体类型
        font.setFontName("微软雅黑");
        // 设置字体大小
        font.setFontHeightInPoints((short) 10);
        // 粗体字体
        font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        // 把字体应用到当前的样式
        style.setFont(font);
        return style;

    }

    /**
     * 表格主体单元格样式
     * @param workbook
     * @param style
     * @return
     */
    public static XSSFCellStyle setBodyStyle(XSSFWorkbook workbook, XSSFCellStyle style) {
        // 设置背景色
        // style.setFillForegroundColor(new XSSFColor(new Color(255,255,255)));
        // style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        // 设置边框
        style.setBorderBottom(XSSFCellStyle.BORDER_THIN); // 下边框
        style.setBorderRight(XSSFCellStyle.BORDER_THIN);// 右边框
        style.setBorderLeft(XSSFCellStyle.BORDER_THIN);// 左边框
        style.setBorderTop(XSSFCellStyle.BORDER_THIN);// 上边框
        // 生成字体
        XSSFFont font = workbook.createFont();
        // 字体类型
        font.setFontName("微软雅黑");
        // 设置字体大小
        font.setFontHeightInPoints((short) 9);
        // 普通字体
        font.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);
        // 把字体应用到当前的样式
        style.setFont(font);
        return style;
    }
}

六、测试类

import com.innovative.service.dto.TestDTO;
import com.innovative.utils.ExcelUtils;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@SpringBootTest
public class ExcelUtilsTest {

    @Test
    public void importTest() throws Exception {
        ExcelUtils<TestDTO> test = new ExcelUtils<>(TestDTO.class);
        File file = new File("D:\\excelTest.xlsx");
        List<TestDTO> result = (ArrayList<TestDTO>) test.importExcel(file,null,null,null);
        // 输出导入信息
        for (int i = 0; i < result.size(); i++) {
            TestDTO testDTO = result.get(i);
            System.out.println("导入的信息为:" + testDTO.getUserName() + "-----" + testDTO.getLoginName() + "----" + testDTO.getAge()
                    + "---" + testDTO.getMoney() + "-----" + testDTO.getCreateTime());
        }
        System.out.println("共转化为List的行数为:" + result.size());
    }

    @Test
    public void exportTest() throws Exception {
        // 构建一个TestDTO来模拟导出
        List<TestDTO> list = new ArrayList<>();
        for (int i = 0; i < 5000; i++) {
            TestDTO pojo = new TestDTO();
            pojo.setLoginName("登录名"+i);
            pojo.setUserName("用户名"+i);
            pojo.setMoney(new Long(1000+i));
            pojo.setCreateTime(new Date());
            pojo.setAge(28);
            list.add(pojo);
        }
        // 构造输出对象,可以从response输出,直接向用户提供下载
        OutputStream out = new FileOutputStream("D:\\excelTest.xlsx");
        // excel工具类
        ExcelUtils<TestDTO> ex = new ExcelUtils<>(TestDTO.class);
        // 导出
        ex.exportExcel(null,null,null, list, out);
        out.close();
    }
}

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值