Spring通过poi简单封装excel导出的工具类

前言

  首先,当准备看这个博客的时候,就默认大家已经会使用spring进行javaweb开发以及使用poi导出excel。相信大家在进行excel导出的时候都会发现,代码冗余较多,如果每导出一个excel文件就写一段代码的话,代码重复量巨大,出了问题也难以定位问题的所在。那么自己封装一个导出excel的工具类就显得十分有意义了。
  那么我们可以通过什么方式来构建这个工具类呢?
  相信大家在使用spring开发项目的时候都使用过hibernate、mybatis来查询处理数据库中的数据,而这类框架的名称叫做ORM(Object Relational Mapping)框架,即对象关系映射框架。ORM的思想是将数据库中的每一个关系(即表)映射到一个实体类上,用类代表表、对象代表一条条记录、类的属性代表表中的字段。
  大家也都知道,数据库通常分为关系型数据库和非关系型数据库,而关系型数据库中数据的存储展示方式与excel表格十分相似,那我们为什么不能模仿ORM来进行excel导出辅助工具类的设计呢?

分析

excel组成

  在生成excel之前我们首先要知道一个excel文件的结构以及一个excel文件通常是什么样的。

文件组成

  首先我们来看一个简单的例子,这是关于学生信息统计的excel表格。
在这里插入图片描述

  在图中我们可以发现一个excel文件结构是:一个excel文件(A对应的xxx.xls)包含多个sheet(C对应的部分),而一个sheet包含多个单元格(cell)(B对应的部分)。

sheet的通常使用格式

  通常我们将一个sheet分成四个模块:标题、表头、数据和标尾。
在这里插入图片描述
  但是我们知道,一个excel表格中,只有表头和数据部分是必须出现的,少了任何一个便不能成为一个完整的数据呈现载体。而标题和标尾不能强求,说不定别人一个文件想要,另一个就不想要了,所以表头和数据部分是必须的,而标题和标尾应该可以供用户选择,留出扩展实现的接口。

工具类的设计与实现

  我们使用自底向上的思路,从cell开始,直到excel文件。

数据单元

  我们知道,在spring-data-jpa中是使用@Entity来标明这个类这是一个实体,需要映射到某张表;而用@Column标明这个属性需要映射到表中的一个字段。那我们是不是也可以通过注解的方式来标注实体的映射信息呢?
  我们可以分别用两个注解,一个类注解来表明这个实体类对应一个sheet,一个属性注解来表明这个属性对应一个表头。(由于时间原因这里只实现了后者
  话不多说,直接贴一下代码:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelColumn {
    /**
     * 该字段出现在 excel 表格的顺序
     *
     * @return
     */
    int order();

    /**
     * 该字段在表头的名称
     *
     * @return
     */
    String description();

    /**
     * 标题字体大小
     *
     * @return
     */
    short titleFontSize() default (short) 10;

    /**
     * 标题字体粗细
     *
     * @return
     */
    short titleFontWeight() default HSSFFont.BOLDWEIGHT_NORMAL;

    /**
     * 标题字体颜色
     *
     * @return
     */
    short titleFontColor() default Font.COLOR_NORMAL;

    /**
     * 正文字体大小
     *
     * @return
     */
    short contentFontSize() default (short) 10;

    /**
     * 正文字体粗细
     *
     * @return
     */
    short contentFontWeight() default HSSFFont.BOLDWEIGHT_NORMAL;

    /**
     * 正文字体颜色
     *
     * @return
     */
    short contentFontColor() default Font.COLOR_NORMAL;

    /**
     * 是否对这一列上锁
     *
     * @return
     */
    boolean columnLocked() default true;
}

  这里除了字体格式、颜色、大小以及是否对该列上锁等基本信息,需要注意的两个属性是order和description,这两个属性不能为空,也是格式构造必不可少的两个部分:
  order:order是这个属性对应的权重,越小,该属性对应的列就越靠前,就像最开始学生信息表,order:学号 < 姓名 < 性别 < 住址。
  description:description是该属性对应的列的表头,如最开始学生信息表的学号、姓名、性别和住址。
  使用方式如下:

class Student{
        @ExcelColumn(order = 1, description = "学号")
        private String id;
        @ExcelColumn(order = 2, description = "姓名")
        private String name;
        @ExcelColumn(order = 4, description = "住址")
        private String address;
        @ExcelColumn(order = 3, description = "性别")
        private String sex;

		// 构造方法和getter、setter方法省略
    }

sheet

  现在单元格的载体已经设计好,可以设计单元格的载体sheet了,其实大家也都熟悉sheet,所以这里直接放上代码:

public class Sheet {
    private String sheetName; // sheet的名称
    private List<String> orderedTitles; // 排好序的每一列的表头
    private List<?> data; // 具体的数据
    private Class targetClass; // 承载数据的类,如:Student
    private List<Field> orderedFields; // 排好序的属性
    private List<HSSFCellStyle> titleStyle; // 表头的格式
    private List<HSSFCellStyle> contentStyle; // 正文数据的格式
    private HSSFWorkbook hssfWorkbook; // 所属的excel文件
    private ExcelProcessor excelProcessor = new StandardExcelProcessor(); // 处理器(这里默认是标准处理器)
    private boolean customMode = false; // 是否为自定义模式

    // 构造方法和getter、setter方法省略
}

  这里将要利用反射机制对属性进行排序,具体代码如下:

private void initExcelAssistBean() {
        Field[] fields = targetClass.getDeclaredFields();
        orderedFields = new ArrayList<>();
        for (Field temp : fields) {
            if (temp.getAnnotation(ExcelColumn.class) != null) {
                orderedFields.add(temp);
            }
        }
        orderedFields.sort(Comparator.comparingInt(field -> field.getAnnotation(ExcelColumn.class).order()));
        orderedTitles = new ArrayList<>();
        for (Field temp : orderedFields) {
            orderedTitles.add(temp.getAnnotation(ExcelColumn.class).description());
        }
        //如果开启自定义模式
        if (customMode) {
            titleStyle = new ArrayList<>();
            contentStyle = new ArrayList<>();
            HSSFCellStyle currentCellStyle;
            Font font;
            for (Field temp : orderedFields) {
                currentCellStyle = hssfWorkbook.createCellStyle();
                font = hssfWorkbook.createFont();
                font.setFontHeightInPoints(temp.getAnnotation(ExcelColumn.class).titleFontSize());
                font.setBoldweight(temp.getAnnotation(ExcelColumn.class).titleFontWeight());
                font.setColor(temp.getAnnotation(ExcelColumn.class).titleFontColor());
                currentCellStyle.setLocked(false);  // 表头均不能修改
                currentCellStyle.setFont(font);
                titleStyle.add(currentCellStyle);
                currentCellStyle = hssfWorkbook.createCellStyle();
                font = hssfWorkbook.createFont();
                font.setFontHeightInPoints(temp.getAnnotation(ExcelColumn.class).contentFontSize());
                font.setBoldweight(temp.getAnnotation(ExcelColumn.class).contentFontWeight());
                font.setColor(temp.getAnnotation(ExcelColumn.class).contentFontColor());
                currentCellStyle.setLocked(temp.getAnnotation(ExcelColumn.class).columnLocked());
                currentCellStyle.setFont(font);
                contentStyle.add(currentCellStyle);
            }
        }
    }

  该类的每个构造方法都会调用这个初始化方法,而这个方法主要是对属性进行排序(通过order),以及设置表头和正文各种格式样式。

excel文件载体

  虽说可以专门抽象出一个类来描述一个excel文件,可转念一想,一个excel文件其实包含的属性比较少,所以就和工厂类抽象成同一个就好了,下面是代码:

public class ExcelWorkBookCreator {
    private String excelFileName; // 文件名称
    private List<Sheet> sheets; // 文件包含的sheets
    private HSSFWorkbook hssfWorkbook; // 文件载体
    private final String EXCEL_SHEET_PASSWORD = "123321"; // 文件密码

    // 构造方法和getter、setter方法省略
}

通用工具类

  在这个类中可以获取ExcelWorkBookCreator,以及一些简单的通用操作:

public class ExcelUtil {
    /**
     * 获取 excel 文件创造器
     *
     * @param excelFileName -> excel 文件的名字
     * @return
     */
    public static ExcelWorkBookCreator getExcelWorkBookCreator(String excelFileName) {
        return new ExcelWorkBookCreator(excelFileName);
    }
}

处理器

  大家是否还记着之前说的:通常我们将一个sheet分成四个模块:标题、表头、数据和标尾。而标题和标尾不是必须不可的,而在上面我们也没有给这两个模块留有相应的余地。不光如此,一个封装工具无论怎样设计都难做到满足所有需求,所以我们必须留给自己足够的余地。这个时候就很需要处理器了。这里我们模仿spring中ioc容器的PostProcessor,在绘制表头和正文之前(自定义标题)和之后(自定义标尾以及处理一些特殊数据)让用户进行自定义的处理。

public interface ExcelProcessor {
    /**
     * 在正式注入数据之前的自定义操作,可以自己设计标题等
     *
     * @param sheet -> 当前 sheet 信息
     * @param currentSheet -> 当前 sheet
     * @return 想要正式注入表头及数据的行数
     */
    Integer customOperationBeforeInvokeData(Sheet sheet, HSSFSheet currentSheet);

    /**
     * 在注入完数据后的自定义操作,如:在表格最后落上日期、对某些数据进行修改等
     * 可以通过 currentSheet..getLastRowNum() 获取最后一行的行标,从 0 开始
     *
     * @param sheet -> 当前 sheet 信息
     * @param currentSheet -> 当前 sheet
     */
    void customOperationAfterInvokeData(Sheet sheet, HSSFSheet currentSheet, int firstRowNum);
}

  通过实现这个接口,我们便可以进行一些扩展的操作。

功能分配汇总

ExcelWorkBookCreator(层级:文件):保存所有sheet,可以导出文件。
Sheet(层次:sheet):保存sheet信息,可以注入数据。
ExcelUtil:进行一些通用操作。
ExcelProcessor:在文件构造前后进行自定义处理。

需要的依赖

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

总结

  由于从想到要创建这个工具类到实现只用了一两天的时间,所以有许多设计其实并不是特别合理。而且这个工具类也没有使用过,所以可能会出现很多bug。但这里其实我只是提供一种思路,实现还是自己来的好,毕竟用自己实现的才安心。另外这些代码仅供学习,如果在实际环境中使用出现问题,请自负责任。

代码

  **这里是所有内容的代码,仅供学习!真实环境中使用出现问题,这里不负责!**如果嫌麻烦,可以去空间下载。

ExcelColumn

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelColumn {
    /**
     * 该字段出现在 excel 表格的顺序
     *
     * @return
     */
    int order();

    /**
     * 该字段在表头的名称
     *
     * @return
     */
    String description();

    /**
     * 标题字体大小
     *
     * @return
     */
    short titleFontSize() default (short) 10;

    /**
     * 标题字体粗细
     *
     * @return
     */
    short titleFontWeight() default HSSFFont.BOLDWEIGHT_NORMAL;

    /**
     * 标题字体颜色
     *
     * @return
     */
    short titleFontColor() default Font.COLOR_NORMAL;

    /**
     * 正文字体大小
     *
     * @return
     */
    short contentFontSize() default (short) 10;

    /**
     * 正文字体粗细
     *
     * @return
     */
    short contentFontWeight() default HSSFFont.BOLDWEIGHT_NORMAL;

    /**
     * 正文字体颜色
     *
     * @return
     */
    short contentFontColor() default Font.COLOR_NORMAL;

    /**
     * 是否对这一列上锁
     *
     * @return
     */
    boolean columnLocked() default true;
}

Sheet

public class Sheet {
    private String sheetName;
    private List<String> orderedTitles;
    private List<?> data;
    private Class targetClass;
    private List<Field> orderedFields;
    private List<HSSFCellStyle> titleStyle;
    private List<HSSFCellStyle> contentStyle;
    private HSSFWorkbook hssfWorkbook;
    private ExcelProcessor excelProcessor = new StandardExcelProcessor();
    private boolean customMode = false;

    public Sheet() {
    }

    public Sheet(HSSFWorkbook hssfWorkbook, String sheetName, List<?> data, Class targetClass) {
        this.hssfWorkbook = hssfWorkbook;
        this.sheetName = sheetName;
        this.data = data;
        this.targetClass = targetClass;
        initExcelAssistBean();
    }

    public Sheet(HSSFWorkbook hssfWorkbook, String sheetName, List<?> data, Class targetClass, ExcelProcessor excelProcessor) {
        this.hssfWorkbook = hssfWorkbook;
        this.sheetName = sheetName;
        this.data = data;
        this.targetClass = targetClass;
        this.excelProcessor = excelProcessor;
        initExcelAssistBean();
    }

    public Sheet(HSSFWorkbook hssfWorkbook, String sheetName, List<?> data, Class targetClass, boolean customMode) {
        this.hssfWorkbook = hssfWorkbook;
        this.sheetName = sheetName;
        this.data = data;
        this.targetClass = targetClass;
        this.customMode = customMode;
        initExcelAssistBean();
    }

    public Sheet(HSSFWorkbook hssfWorkbook, String sheetName, List<?> data, Class targetClass, ExcelProcessor excelProcessor, boolean customMode) {
        this.hssfWorkbook = hssfWorkbook;
        this.sheetName = sheetName;
        this.data = data;
        this.targetClass = targetClass;
        this.excelProcessor = excelProcessor;
        this.customMode = customMode;
        initExcelAssistBean();
    }

    private void initExcelAssistBean() {
        Field[] fields = targetClass.getDeclaredFields();
        orderedFields = new ArrayList<>();
        for (Field temp : fields) {
            if (temp.getAnnotation(ExcelColumn.class) != null) {
                orderedFields.add(temp);
            }
        }
        orderedFields.sort(Comparator.comparingInt(field -> field.getAnnotation(ExcelColumn.class).order()));
        orderedTitles = new ArrayList<>();
        for (Field temp : orderedFields) {
            orderedTitles.add(temp.getAnnotation(ExcelColumn.class).description());
        }
        //如果开启自定义模式
        if (customMode) {
            titleStyle = new ArrayList<>();
            contentStyle = new ArrayList<>();
            HSSFCellStyle currentCellStyle;
            Font font;
            for (Field temp : orderedFields) {
                currentCellStyle = hssfWorkbook.createCellStyle();
                font = hssfWorkbook.createFont();
                font.setFontHeightInPoints(temp.getAnnotation(ExcelColumn.class).titleFontSize());
                font.setBoldweight(temp.getAnnotation(ExcelColumn.class).titleFontWeight());
                font.setColor(temp.getAnnotation(ExcelColumn.class).titleFontColor());
                currentCellStyle.setLocked(false);  // 表头均不能修改
                currentCellStyle.setFont(font);
                titleStyle.add(currentCellStyle);
                currentCellStyle = hssfWorkbook.createCellStyle();
                font = hssfWorkbook.createFont();
                font.setFontHeightInPoints(temp.getAnnotation(ExcelColumn.class).contentFontSize());
                font.setBoldweight(temp.getAnnotation(ExcelColumn.class).contentFontWeight());
                font.setColor(temp.getAnnotation(ExcelColumn.class).contentFontColor());
                currentCellStyle.setLocked(temp.getAnnotation(ExcelColumn.class).columnLocked());
                currentCellStyle.setFont(font);
                contentStyle.add(currentCellStyle);
            }
        }
    }

    public void titleCellStyleInvoke(HSSFRow row) {
        HSSFCell titleCell;
        for (int titleIndex = 0; titleIndex < orderedTitles.size(); titleIndex++) {
            titleCell = row.createCell(titleIndex);
            titleCell.setCellStyle(titleStyle.get(titleIndex));
            titleCell.setCellValue(orderedTitles.get(titleIndex));
        }
    }

    public void contentCellStyleInvoke(HSSFSheet hssfSheet, int firstRowNum) throws Exception {
        HSSFRow currentRow;
        for (int rowIndex = firstRowNum + 1; rowIndex < data.size(); rowIndex++) {
            currentRow = hssfSheet.createRow(rowIndex);
            HSSFCell currentCell;
            Object obj = data.get(rowIndex);
            for (int cellIndex = 0; cellIndex < orderedFields.size(); cellIndex++) {
                currentCell = currentRow.createCell(cellIndex);
                currentCell.setCellStyle(contentStyle.get(cellIndex));
                if (!orderedFields.get(cellIndex).isAccessible()) {
                    orderedFields.get(cellIndex).setAccessible(true);
                    if (orderedFields.get(cellIndex).get(obj) != null) {
                        currentCell.setCellValue(orderedFields.get(cellIndex).get(obj).toString());
                    }
                    orderedFields.get(cellIndex).setAccessible(false);
                } else {
                    if (orderedFields.get(cellIndex).get(obj) != null) {
                        currentCell.setCellValue(orderedFields.get(cellIndex).get(obj).toString());
                    }
                }
            }
        }
    }

    public String getSheetName() {
        return sheetName;
    }

    public void setSheetName(String sheetName) {
        this.sheetName = sheetName;
    }

    public List<String> getOrderedTitles() {
        return orderedTitles;
    }

    public void setOrderedTitles(List<String> orderedTitles) {
        this.orderedTitles = orderedTitles;
    }

    public List<?> getData() {
        return data;
    }

    public void setData(List<?> data) {
        this.data = data;
    }

    public Class getTargetClass() {
        return targetClass;
    }

    public void setTargetClass(Class targetClass) {
        this.targetClass = targetClass;
    }

    public List<Field> getOrderedFields() {
        return orderedFields;
    }

    public void setOrderedFields(List<Field> orderedFields) {
        this.orderedFields = orderedFields;
    }

    public ExcelProcessor getExcelProcessor() {
        return excelProcessor;
    }

    public void setExcelProcessor(ExcelProcessor excelProcessor) {
        this.excelProcessor = excelProcessor;
    }

    public boolean isCustomMode() {
        return customMode;
    }

    public void setCustomMode(boolean customMode) {
        this.customMode = customMode;
    }

    public List<HSSFCellStyle> getTitleStyle() {
        return titleStyle;
    }

    public void setTitleStyle(List<HSSFCellStyle> titleStyle) {
        this.titleStyle = titleStyle;
    }

    public List<HSSFCellStyle> getContentStyle() {
        return contentStyle;
    }

    public void setContentStyle(List<HSSFCellStyle> contentStyle) {
        this.contentStyle = contentStyle;
    }

    public HSSFWorkbook getHssfWorkbook() {
        return hssfWorkbook;
    }

    public void setHssfWorkbook(HSSFWorkbook hssfWorkbook) {
        this.hssfWorkbook = hssfWorkbook;
    }
}

ExcelProcessor

public interface ExcelProcessor {
    /**
     * 在正式注入数据之前的自定义操作,可以自己设计标题等
     *
     * @param sheet -> 当前 sheet 信息
     * @param currentSheet -> 当前 sheet
     * @return 想要正式注入表头及数据的行数
     */
    Integer customOperationBeforeInvokeData(Sheet sheet, HSSFSheet currentSheet);

    /**
     * 在注入完数据后的自定义操作,如:在表格最后落上日期、对某些数据进行修改等
     * 可以通过 currentSheet..getLastRowNum() 获取最后一行的行标,从 0 开始
     *
     * @param sheet -> 当前 sheet 信息
     * @param currentSheet -> 当前 sheet
     */
    void customOperationAfterInvokeData(Sheet sheet, HSSFSheet currentSheet, int firstRowNum);
}

StandardExcelProcessor

public class StandardExcelProcessor implements ExcelProcessor {
    @Override
    public Integer customOperationBeforeInvokeData(Sheet sheet, HSSFSheet currentSheet) {
        return 0;
    }

    @Override
    public void customOperationAfterInvokeData(Sheet sheet, HSSFSheet currentSheet, int firstRowNum) {
        ExcelUtil.RowWidthAutoFix(sheet, currentSheet, firstRowNum);
    }
}

ExcelUtil

public class ExcelUtil {

    /**
     * 获取 excel 文件创造器
     *
     * @param excelFileName -> excel 文件的名字
     * @return
     */
    public static ExcelWorkBookCreator getExcelWorkBookCreator(String excelFileName) {
        return new ExcelWorkBookCreator(excelFileName);
    }

    /**
     * 列宽自适应,可以在 ExcelProcessor 的实现类的后置处理中使用
     *
     * @param sheet
     * @param currentSheet
     * @param firstRowNum
     */
    public static void RowWidthAutoFix(Sheet sheet, HSSFSheet currentSheet, int firstRowNum) {
        int columnNum = sheet.getOrderedTitles().size();
        int columnLength = currentSheet.getLastRowNum() + 1;
        System.out.println(columnLength);
        int[] columnWidth = new int[columnNum];
        for (int index = 0; index < columnNum; index++) {
            columnWidth[index] = 0;
        }
        HSSFRow currentRow;
        for (int currentRowNum = firstRowNum; currentRowNum < columnLength; currentRowNum++) {
            currentRow = currentSheet.getRow(currentRowNum);
            HSSFCell currentCell;
            if (currentRow != null) {
                for (int currentColumnNum = 0; currentColumnNum < columnNum; currentColumnNum++) {
                    currentCell = currentRow.getCell(currentColumnNum);
                    if (currentCell != null && currentCell.getStringCellValue().getBytes().length > columnWidth[currentColumnNum]) {
                        columnWidth[currentColumnNum] = currentCell.getStringCellValue().getBytes().length;
                    }
                }
            }
        }
        for (int index = 0; index < columnNum; index++) {
            currentSheet.setColumnWidth(index, columnWidth[index] * 300);
        }
    }
}

ExcelWorkBookCreator

public class ExcelWorkBookCreator {
    private String excelFileName;
    private List<Sheet> sheets;
    private HSSFWorkbook hssfWorkbook;
    private final String EXCEL_SHEET_PASSWORD = "123321";

    public ExcelWorkBookCreator(String excelFileName) {
        this.excelFileName = excelFileName;
        hssfWorkbook = new HSSFWorkbook();
        sheets = new ArrayList<>();
    }

    public void addOneSheet(String sheetName, List<?> data, Class targetClass) {
        sheets.add(new Sheet(hssfWorkbook, sheetName, data, targetClass));
    }

    public void addOneSheet(String sheetName, List<?> data, Class targetClass, boolean customMode) {
        sheets.add(new Sheet(hssfWorkbook, sheetName, data, targetClass, customMode));
    }

    public void addOneSheet(String sheetName, List<?> data, Class targetClass, ExcelProcessor excelProcessor) {
        sheets.add(new Sheet(hssfWorkbook, sheetName, data, targetClass, excelProcessor));
    }

    public void addOneSheet(String sheetName, List<?> data, Class targetClass, ExcelProcessor excelProcessor, boolean customMode) {
        sheets.add(new Sheet(hssfWorkbook, sheetName, data, targetClass, excelProcessor, customMode));
    }


    /**
     * 导出 excel
     *
     * @param response
     * @return
     * @throws Exception
     */
    public void excelExport(HttpServletResponse response) throws Exception {
        //设置文件名
        response.setContentType("multipart/form-data");
        response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode((excelFileName + ".xls"), "UTF-8"));
        OutputStream os = response.getOutputStream();
        //开始注入数据
        for (int sheetIndex = 0; sheetIndex < sheets.size(); sheetIndex++) {
            Sheet currentSheetMsg = sheets.get(sheetIndex);
            HSSFSheet currentSheet = hssfWorkbook.createSheet(currentSheetMsg.getSheetName());
            currentSheet.protectSheet(EXCEL_SHEET_PASSWORD);
            ExcelProcessor excelProcessor = currentSheetMsg.getExcelProcessor();
            int firstRowNum = excelProcessor.customOperationBeforeInvokeData(currentSheetMsg, currentSheet);
            if (currentSheetMsg.isCustomMode()) {
                invokeDataUnderCustomModel(currentSheetMsg, currentSheet, firstRowNum);
            } else {
                invokeData(currentSheetMsg, currentSheet, firstRowNum);
            }
            excelProcessor.customOperationAfterInvokeData(currentSheetMsg, currentSheet, firstRowNum);
        }
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        hssfWorkbook.write(outputStream);
        outputStream.flush();
        hssfWorkbook.close();
        outputStream.close();
        InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());

        int b = 0;
        byte[] buffer = new byte[512];
        while (b != -1) {
            b = inputStream.read(buffer);
            if (b != -1) {
                os.write(buffer, 0, b);
            }
        }

        if (os != null) {
            os.close();
            os.flush();
        }
    }

    /**
     * 不开启自定义文本模式下注入正文
     *
     * @param currentSheet
     * @param hssfSheet
     * @param firstRowNum
     * @throws Exception
     */
    private void invokeData(Sheet currentSheet, HSSFSheet hssfSheet, int firstRowNum) throws Exception {
        //设置表头
        HSSFRow firstRow = hssfSheet.createRow(firstRowNum);
        HSSFCellStyle cellStyle = hssfWorkbook.createCellStyle();
        Font titleFont = hssfWorkbook.createFont();
        //加粗标题字体
        titleFont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        cellStyle.setFont(titleFont);
        cellStyle.setLocked(true);
        HSSFCell titleCell;
        for (int titleIndex = 0; titleIndex < currentSheet.getOrderedTitles().size(); titleIndex++) {
            titleCell = firstRow.createCell(titleIndex);
            titleCell.setCellValue(currentSheet.getOrderedTitles().get(titleIndex));
            titleCell.setCellStyle(cellStyle);
        }
        //注入数据
        List<?> currentData = currentSheet.getData();
        List<Field> fields = currentSheet.getOrderedFields();
        cellStyle = hssfWorkbook.createCellStyle();
        cellStyle.setLocked(true);
        HSSFRow currentRow;
        for (int rowIndex = 0; rowIndex < currentData.size(); rowIndex++) {
            currentRow = hssfSheet.createRow(rowIndex + firstRowNum + 1);
            HSSFCell currentCell;
            Object obj = currentData.get(rowIndex);
            for (int cellIndex = 0; cellIndex < fields.size(); cellIndex++) {
                currentCell = currentRow.createCell(cellIndex);
                currentCell.setCellStyle(cellStyle);
                if (!fields.get(cellIndex).isAccessible()) {
                    fields.get(cellIndex).setAccessible(true);
                    if (fields.get(cellIndex).get(obj) != null) {
                        currentCell.setCellValue(fields.get(cellIndex).get(obj).toString());
                    }
                    fields.get(cellIndex).setAccessible(false);
                } else {
                    if (fields.get(cellIndex).get(obj) != null) {
                        currentCell.setCellValue(fields.get(cellIndex).get(obj).toString());
                    }
                }
            }
        }
    }

    /**
     * 开启自定义文本模式下注入正文
     *
     * @param currentSheet
     * @param hssfSheet
     * @param firstRowNum
     * @throws Exception
     */
    private void invokeDataUnderCustomModel(Sheet currentSheet, HSSFSheet hssfSheet, int firstRowNum) throws Exception {
        //设置表头
        HSSFRow firstRow = hssfSheet.createRow(firstRowNum);
        currentSheet.titleCellStyleInvoke(firstRow);
        //注入数据
        currentSheet.contentCellStyleInvoke(hssfSheet, firstRowNum);
    }

    public String getExcelFileName() {
        return excelFileName;
    }

    public void setExcelFileName(String excelFileName) {
        this.excelFileName = excelFileName;
    }

    public List<Sheet> getSheets() {
        return sheets;
    }

    public void setSheets(List<Sheet> sheets) {
        this.sheets = sheets;
    }
}

测试

@Controller
@RequestMapping("/test")
public class TestController {

    @ResponseBody
    @RequestMapping(value = "/getExcel", method = RequestMethod.GET)
    public String getExcel(HttpServletResponse response){
        try {
            List<Student> students = new ArrayList<>();
            this.injectData(students);
            ExcelWorkBookCreator creator = ExcelUtil.getExcelWorkBookCreator("学生信息汇总");
            creator.addOneSheet("学生信息", students, Student.class);
            creator.excelExport(response);
            return "success";
        } catch (Exception e) {
            e.printStackTrace();
            return "error";
        }
    }

    private void injectData(List<Student> students){
        students.add(new Student("1", "张三", "xx1小区", "男"));
        students.add(new Student("2", "李四", "xx2小区", "男"));
        students.add(new Student("3", "王五", "xx3小区", "女"));
        students.add(new Student("4", "小明", "xx4小区", "男"));
        students.add(new Student("5", "小红", "xx5小区", "女"));
    }

    class Student{
        @ExcelColumn(order = 1, description = "学号")
        private String id;
        @ExcelColumn(order = 2, description = "姓名")
        private String name;
        @ExcelColumn(order = 4, description = "住址")
        private String address;
        @ExcelColumn(order = 3, description = "性别")
        private String sex;

        public Student() {
        }

        public Student(String id, String name, String address, String sex) {
            this.id = id;
            this.name = name;
            this.address = address;
            this.sex = sex;
        }

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getAddress() {
            return address;
        }

        public void setAddress(String address) {
            this.address = address;
        }

        public String getSex() {
            return sex;
        }

        public void setSex(String sex) {
            this.sex = sex;
        }
    }
}

在这里插入图片描述

码云

poi简单封装excel导出的工具类

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Java POI是一个用于操作Microsoft Office格式文件的Java API,包括Excel、Word和PowerPoint等文件。使用Java POI可以轻松地读取、写入和操作Excel文件。 导出Excel工具类是基于Java POI开发的一种工具,可以将Java程序中的数据导出Excel文件中。该工具类通常包括以下功能: 1. 创建Excel文件和工作表 2. 设置Excel文件和工作表的属性,如标题、列宽、行高等 3. 写入数据到Excel文件中,包括文本、数字、日期、图片等 4. 格式化Excel文件中的数据,如设置单元格的字体、颜色、边框等 5. 导出Excel文件到本地磁盘或网络路径中 使用导出Excel工具类可以方便地将Java程序中的数据导出Excel文件中,便于数据的查看和分析。 ### 回答2: Java POI是由Apache基金会开发的一个开源的Java API,它可以帮助Java开发人员轻松地读写Microsoft Office格式的文件,其中包括Excel、Word和PowerPoint。其中Excel是最常用的一个,而Java POI提供了一种方便的方法导出Excel,使开发人员的工作变得更加高效。 Java POI导出Excel工具类的实现原理是利用POI库提供的API来操作Excel文件。首先,需要创建一个Workbook对象,它代表了整个Excel文件,然后再创建Sheet对象,它代表了Excel文件中的一个工作簿。接着,需要往Sheet对象中添加行和列,以及单元格值,并设置单元格的样式,最后将数据写入到Excel文件,并进行文件保存。 在实际开发中,通常会创建一个工具类来处理Excel文件的导入和导出,以提高代码的复用性和可维护性。导出Excel工具类通常包含以下几个方法: 1. 创建Workbook对象:使用POI库创建Workbook对象,设置Excel文件的格式和样式等属性。 2. 创建Sheet对象:使用POI库创建Sheet对象,设置Sheet的名称、列头信息和单元格样式等属性。 3. 添加数据行:将数据逐行添加到Sheet对象中,并设置单元格样式,以保证输出的Excel文件具有良好的可读性。 4. 写入数据:将Sheet对象中的数据写入到Excel文件中,可以选择将文件保存到本地磁盘或者将文件发送给客户端。 总的来说,Java POI导出Excel工具类可以方便地实现Excel文件的生成,提高了开发效率和程序的可靠性,是Java开发人员不可或缺的工具之一。 ### 回答3: Java POI是一种用来读写Microsoft Office格式文件的Java API,其中包括Excel,Word和PowerPoint文档。导出Excel文件是Java开发过程中常见的需求,Java POI提供了丰富的API,使得开发者们可以方便快捷地实现导出Excel文件的功能。下面将介绍java poi导出excel工具类的实现步骤。 1. 引入POI库 使用Maven或Gradle工具,可以轻松地在项目中引入POI库。引入完毕后,即可在代码中使用POI API。 2. 创建工具类Java工程中创建一个名为 ExcelUtil 的类,该类负责导出Excel文件。 3. 编写导出Excel的方法 在 ExcelUtil 类中,编写导出 Excel 文件的方法。 该方法主要包括创建工作簿,创建工作表,设置表头,将数据写入表格,设置单元格样式和导出文件等步骤。接下来,分别介绍每个步骤的实现方法。 (1)创建工作簿 在导出 Excel 文件时,首先需要创建一个工作簿。可以通过 HSSFWorkbook 或 XSSFWorkbook 类来创建工作簿。使用 XSSFWorkbook 类可以创建 .xlsx 格式的 Excel 文件,而使用 HSSFWorkbook 类可以创建 .xls 格式的 Excel 文件。 (2)创建工作表 除了创建工作簿之外,还需要在工作簿中创建工作表。可以使用 createSheet() 方法创建工作表。 (3)设置表头 表头是 Excel 文件中的第一行,通常包含各个列的名称。可以使用 createRow() 方法创建表头行,并使用 createCell() 方法在行中创建单元格。 (4)将数据写入表格 接下来,需要将数据写入工作表中。可以通过循环遍历来逐行写入数据。典型的情况是,读取一个链表,然后将链表中的元素逐一写入 Excel 文件。 (5) 设置单元格样式 可以创建一个单元格样式类,设置单元格的底色、字体颜色、字体大小、对齐方式、边框等属性。 (6)导出文件 将创建好的工作簿写入输出流中,即可将 Excel 文件导出到文件系统或应用程序的输出流中。 4. 调用导出方法 最后,在需要导出 Excel 文件的地方,向 ExcelUtil 类传递数据并调用导出方法即可实现导出文件的功能。 以上就是介绍 java poi导出excel工具类的实现方式。使用 Java POI API,可以快速方便地将数据导出Excel 文件中。开发者们可以根据实际需求进行二次开发,实现更多的功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值