Bootstrap

java Excel导出工具类

Excel工具类

一、开发原因

最近工作的时候,正在写关于Excel导出功能,由于当前使用的工具类不太灵活和不易看懂,自己从头写又很浪费时间等原因,我决定自己写一款很简单的Excel导出的工具类,仅仅是出于学习的目的。

二、工具类的使用

基于HSSFWorkbook,介绍如下:
首先需要一个Maven依赖:

        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>5.0.0</version>
        </dependency>

工具类的名称是ExcelUtil,类中包含两个主要的方法可以来调用:

在这里插入图片描述

本方法有两个形参,分别是String fileName(文件名), List<List> dataList(数据列表)

具体使用方法如下:
首先创建一个数据列表,一般都是从数据库获取,这里我手动创建一个:

public static List<List<Object>> listData() {

        List<List<Object>> dataList = new ArrayList<>();  //所需要的数据列表的类型
        String[] thStrings = {"id", "名字", "性别", "年龄", "籍贯", "学历"};
        //表头数据
        ArrayList<Object> th = new ArrayList<>(Arrays.asList(thStrings));
        dataList.add(th);   // 将表头数据放入数据列表中

        //表格数据
        ArrayList<Object> data = new ArrayList<>();
        data.add("001");
        data.add("iKun");
        data.add("man");
        data.add(18);
        data.add("美国");
        data.add("rap博士");

        for (int i = 0; i < 200; i++) {
            dataList.add(data);  // 循环将200个iKun放入数据列表中
        }

        return dataList;

    }

在main中使用:

    public static void main(String[] args) {
        String title = "Excel";   // 文件名
        List<List<Object>> listData = listData(); // 数据列表

        ExcelUtil excelUtil = new ExcelUtil();
        Boolean result = excelUtil.exportExcelList(title, listData);
        System.out.println("result = " + result);


    }

导出成功后会返回一个:
在这里插入图片描述
导出的文件如下:
在这里插入图片描述

第二个方法是基于类的的反射和注解,主要是导出对应的实体类对象列表数据
在这里插入图片描述

exportExcelClass形参是三个,分别是String fileName(导出Excel的文件名), Class<?>
aClass(导出对应实体类类的反射), List dataList(对象集合的数据列表)

本方法是基于类的反射和注解实现的,首先在需要导出的实体类中的属性上方添加一注解,如下:
在这里插入图片描述
此注解有两个参数:value(表头)order(表格的列顺序,从小到大,从左向右排列,默认值为0)
在这里插入图片描述

将注解写在实体类的属性上以后,还是首先创建一个数据列表:

 private static List<Student> studentListData() {
        List<Student> studentList = new ArrayList<>();
        Student iKun = new Student(18, "KunKun", 2.5, new Date());
        for (int i = 0; i < 10; i++) {
            studentList.add(iKun);
        }

        return studentList;
    }

在main中使用:

 public static void main(String[] args) {
        String title = "iKun花名册";   // 文件名
        List<Student> studentList = studentListData();  //数据列表

        ExcelUtil<Student> excelUtil = new ExcelUtil<>();
        Boolean aBoolean = excelUtil.exportExcelClass(title, Student.class, studentList);
        System.out.println("aBoolean = " + aBoolean);

    }

最终导出的结果:

在这里插入图片描述

上述就是工具类的使用。

三、工具类的介绍

类有以下几个属性和方法:

在这里插入图片描述

其中 wb; getWb() getSheet() outputFile() 不必过于关注。

主要是剩余方法:
setCellStyle(设置单元格的样式)
exportExcelClass(根据实体类导出数据)
exportExcelList(根据list列表导出数据)
其中exportExcelClass调用了exportExcelList,exportExcelList调用了setCellStyle

1、表头样式
在这里插入图片描述
2、数据样式
在这里插入图片描述
数据分为文本数据和数字数据,可根据需要修改

3、标题样式
在这里插入图片描述

四、源码

注解接口类:

import java.lang.annotation.*;

@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
public @interface ExportExcel {
    String value() default "";  //表头

    int order() default 0;  // 顺序
}

工具实现类:

import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;

import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;


/**
 * 一个Excel文件对应于一个workbook(HSSFWorkbook),
 * 一个workbook可以有多个sheet(HSSFSheet)组成,
 * 一个sheet是由多个row(HSSFRow)组成,
 * 一个row是由多个cell(HSSFCell)组成。
 */
public class ExcelUtil<T> {
    private final HSSFWorkbook wb = new HSSFWorkbook();


    public HSSFWorkbook getWb() {
        return wb;
    }

    /**
     * 获取HSSFSheet,内部方法不必关注
     *
     * @param fileName 文件名
     * @param wb       HSSFWorkbook
     * @return HSSFSheet
     */
    private static HSSFSheet getSheet(String fileName, HSSFWorkbook wb) {
        return wb.createSheet(fileName);
    }

    /**
     * 通过类的反射导出 Excel
     *
     * @param fileName 文件名
     * @param aClass   类对象
     * @param dataList 数据列表
     * @return 是否成功
     */
    public Boolean exportExcelClass(String fileName, Class<?> aClass, List<T> dataList) {

        List<Object> thRow = new ArrayList<>();  //表头数据
        List<List<Object>> thOrderList = new ArrayList<>();       //存放数据和顺序
        for (Field declaredField : aClass.getDeclaredFields()) {  //循环遍历对象的属性列表
            if (declaredField.isAnnotationPresent(ExportExcel.class)) {  //找到被注解的属性

                List<Object> orderValues = new ArrayList<>();

                int order = declaredField.getAnnotation(ExportExcel.class).order();  //获取属性的order
                String value = declaredField.getAnnotation(ExportExcel.class).value();//取出属性注解的value值

                orderValues.add(order);
                orderValues.add(value);

                thOrderList.add(orderValues);

            }

            thOrderList.sort(Comparator.comparingInt(a -> (Integer) a.get(0)));  //排序

        }
        for (List<Object> objects : thOrderList) {
            thRow.add(objects.get(1));
        }

        List<List<Object>> lists = new ArrayList<>(); //表格数据
        lists.add(thRow);  //将表头数据加入

        for (T t : dataList) {  //循环遍历对象列表
            Field[] declaredFields = t.getClass().getDeclaredFields();  //反射得到对象的属性列表
            List<List<Object>> orderList = new ArrayList<>();       //存放数据和顺序
            for (Field declaredField : declaredFields) {    //循环遍历对象的属性
                if (declaredField.isAnnotationPresent(ExportExcel.class)) {
                    int order = declaredField.getAnnotation(ExportExcel.class).order();  //获取属性的order

                    String name = declaredField.getName();  //获取属性的name
                    String getValueMethodName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1);  // 获取属性的get方法
                    Method method = null;
                    try {
                        method = t.getClass().getMethod(getValueMethodName);
                        Object invoke = method.invoke(t);
                        if (invoke == null) {
                            invoke = "";
                        }

                        List<Object> list = new ArrayList<>();
                        list.add(order);
                        list.add(invoke);

                        orderList.add(list);

                    } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
                        throw new RuntimeException(e);
                    }

                }

            }

            orderList.sort(Comparator.comparingInt(a -> (Integer) a.get(0))); //排序

            ArrayList<Object> rowList = new ArrayList<>();
            for (List<Object> orderData : orderList) {
                rowList.add(orderData.get(1));
            }
            lists.add(rowList);

        }
        return exportExcelList(fileName, lists);
    }

    /**
     * 通过list数据集合导出
     *
     * @param fileName 文件名
     * @param dataList 数据列表(list)
     * @return 导出是否成功
     */
    public Boolean exportExcelList(String fileName, List<List<Object>> dataList) {
        HSSFSheet sheet = getSheet(fileName, wb);
        int thSize = dataList.get(0).size() - 1; //表头数据列表长度

        //标题内容  col列 row行
        CellStyle titleStyle = setCellStyle("Arial", 16, true, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);//设置title单元格样式
        HSSFRow titleRow = sheet.createRow(0);
        HSSFCell titleCell = titleRow.createCell(0);
        titleCell.setCellValue(fileName);
        /*
          合并单元格
             第一个参数:第一个单元格的行数(从0开始)
             第二个参数:第二个单元格的行数(从0开始)
             第三个参数:第一个单元格的列数(从0开始)
             第四个参数:第二个单元格的列数(从0开始)
         */
        CellRangeAddress range = new CellRangeAddress(0, 0, 0, thSize);
        sheet.addMergedRegion(range);
        titleCell.setCellStyle(titleStyle);

        //设置列的宽度
        int size = dataList.get(0).size();
        int[] colSize = new int[size];

        for (List<Object> data : dataList) {
            for (int i = 0; i < data.size(); i++) {
                int length = data.get(i).toString().length();
                if (colSize[i] < length) {
                    colSize[i] = length;   //获取每一列中最长的数据
                }
            }
        }
        for (int i = 0; i < colSize.length; i++) {
            sheet.setColumnWidth(i, 2000 + colSize[i] * 200);   ///设置列的宽度
        }

        //表头行数
        int rowId = 1;

        //数据
        CellStyle style = setCellStyle("Arial", 12, false, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
        CellStyle numStyle = setCellStyle("Arial", 12, false, HorizontalAlignment.LEFT, VerticalAlignment.CENTER);
        for (List<Object> strings : dataList) {
            HSSFRow row = sheet.createRow(rowId);

            for (int i = 0; i < strings.size(); i++) {
                HSSFCell cell = row.createCell(i);
                //表头的样式
                if (rowId == 1) {
                    CellStyle thStyle = setCellStyle("Arial", 12, false, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
                    thStyle.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());
                    thStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
                    cell.setCellStyle(thStyle);
                }
                //数据的样式
                if (rowId != 1) {
                    if (strings.get(i) instanceof Double
                            || strings.get(i) instanceof Float
                            || strings.get(i) instanceof Long
                            || strings.get(i) instanceof Integer) {
                        cell.setCellStyle(numStyle);
                    } else {
                        cell.setCellStyle(style);
                    }
                }

                //数据类型处理
                if (strings.get(i) instanceof Double) {
                    cell.setCellValue((double) strings.get(i));
                } else if (strings.get(i) instanceof Float) {
                    cell.setCellValue((double) (Float) strings.get(i));
                } else if (strings.get(i) instanceof Long) {
                    cell.setCellValue((double) (Long) strings.get(i));
                } else if (strings.get(i) instanceof Integer) {
                    cell.setCellValue((double) (Integer) strings.get(i));
                } else if (strings.get(i) instanceof Date) {
                    DataFormat format = wb.createDataFormat();
                    style.setDataFormat(format.getFormat("yyyy-MM-dd"));
                    cell.setCellValue((Date) strings.get(i));
                } else if (strings.get(i) instanceof String) {
                    cell.setCellValue((String) strings.get(i));
                } else {
                    try {
                        cell.setCellValue((String) Class.forName(this.getClass()
                                        .getName()
                                        .replaceAll(this.getClass()
                                                .getSimpleName(), "fieldtype." + strings.get(i)
                                                .getClass()
                                                .getSimpleName() + "Type"))
                                .getMethod("setValue", Object.class)
                                .invoke((Object) null, strings.get(i)));
                    } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException |
                             ClassNotFoundException e) {
                        throw new RuntimeException(e);
                    }
                }

            }


            rowId++;
        }

        //输出Excel
        return outputFile(fileName);
    }

    /**
     * 设置单元格字体样式
     *
     * @param fontType        字体类型
     * @param fontSize        字体大小
     * @param bold            字体是否加粗
     * @param textAlign_l_a_r 字体对齐方式(左右)
     * @param textAlign_t_a_b 字体对齐方式(上下)
     * @return CellStyle
     */
    public CellStyle setCellStyle(String fontType, int fontSize, boolean bold, HorizontalAlignment textAlign_l_a_r, VerticalAlignment textAlign_t_a_b) {
        HSSFCellStyle cellStyle = wb.createCellStyle();
        if (textAlign_l_a_r != null) {
            cellStyle.setAlignment(textAlign_l_a_r);//设置对齐方式
        }
        if (textAlign_t_a_b != null) {
            cellStyle.setVerticalAlignment(textAlign_t_a_b); //设置对齐方式
        }

        HSSFFont font = wb.createFont();
        font.setFontName(fontType);
        font.setFontHeightInPoints((short) fontSize);
        font.setBold(bold);
        cellStyle.setFont(font);// 设置字体
        return cellStyle;
    }

    /**
     * 文件输出流
     *
     * @param fileName 文件名
     * @return 返回是否成功
     */
    private Boolean outputFile(String fileName) {
        FileOutputStream output = null;

        try {
            output = new FileOutputStream("D://" + fileName + ".xls");
            wb.write(output);

            output.flush();
            output.close();

            return true;

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}

后面还会对这个类进行持续的修改优化!!!!,希望可以给各位有一定的帮助!!欢迎讨论分享

;