POI创建复杂表头excel文件通用方法

本文介绍了一个使用Apache POI库,结合自定义注解创建复杂Excel表头的方法。通过注解从Model类和数据域获取表头信息,支持单行和多行表头,以及动态生成表头。示例包括Annotation类、Model类、通用工具类和导出Excel的实现。
摘要由CSDN通过智能技术生成

# POI创建复杂表头excel文件通用方法

---

## 主要实现的功能:

- 泛型方法,不依赖对象类型
- 表头信息使用反射从model类及数据域注释获取
- 适应单行表头和多行表头的生成并赋值

### 下面分别从Annotation类、model类、通用工具类和导出excel文件下载方法四部分代码做以讲解(注意代码中包含部分自定义常量,对应常量类并未贴出)

1. Annotation类

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

/**
 * @author huxiaolong
 * @date 2018/8/14
 */
@Documented
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelAnnotation {
    /*列注释属性*/
    // 表头cell名称
    String headerName() default "";

    // 表头cell索引
    int index() default 0;

    // 表头cell所在row索引
    int level() default 0;

    // 表头cell的上级cell索引
    int parentIndex() default -1;

    /*类注释属性*/
    // sheet名称
    String sheetName() default "";

    // sheet页中日期类值显示所使用的格式
    String datePattern() default "yyyy-MM-dd";

    // 是否添加序号列
    boolean counted() default false;
}
~~~

> 对于列注释index(),表头cell索引设定所遵循的原则是:索引从*0*开始,依据表头在页面中的展布位置,从左往右,从上往下,从父cell到子cell升序排列,即就是靠左的cell索引小于靠右cell的索引,父cell的索引小于其子cell的索引,靠左的子cell的索引小于靠右的父cell的索引。具体见下表所示:
![img_1](/assets/image.png)

2. model类

~~~java
import com.longruan.hnny.scheduling.annotation.ExcelAnnotation;
import java.io.Serializable;
import java.util.Date;

@ExcelAnnotation(sheetName = "煤业公司采煤工作面抽采达标进尺情况", datePattern = "yyyy-MM-dd", counted = true)
public class ExtractionStandardFootage implements Serializable {
    private Integer id;

    @ExcelAnnotation(headerName = "矿井名称",
            index = 0, level = 0, parentIndex = -1)
    private String mineName;

    @ExcelAnnotation(headerName = "综采工作面",
            index = 1, level = 0, parentIndex = -1)
    private String workFaceName;

    @ExcelAnnotation(headerName = "回风巷(m)",
            index = 2, level = 0, parentIndex = -1)
    private String returnAirWay;

    @ExcelAnnotation(headerName = "防突评价允许进尺",
            index = 3, level = 1, parentIndex = 2)
    private Integer permissionFootageReturn;

    @ExcelAnnotation(headerName = "当日进尺",
            index = 4, level = 1, parentIndex = 2)
    private Integer currentFootageReturn;

    @ExcelAnnotation(headerName = "本循环累计进尺",
            index = 5, level = 1, parentIndex = 2)
    private Integer totalFootageReturn;

    @ExcelAnnotation(headerName = "剩余允许进尺",
            index = 6, level = 1, parentIndex = 2)
    private Integer leftPermissionFootageReturn;

    @ExcelAnnotation(headerName = "进风巷(m)",
            index = 7, level = 0, parentIndex = -1)
    private String intakeAiyWay;

    @ExcelAnnotation(headerName = "防突评价允许进尺",
            index = 8, level = 1, parentIndex = 7)
    private Integer permissionFootageIntake;

    @ExcelAnnotation(headerName = "当日进尺",
            index = 9, level = 1, parentIndex = 7)
    private Integer currentFootageIntake;

    @ExcelAnnotation(headerName = "本循环累计进尺",
            index = 10, level = 1, parentIndex = 7)
    private Integer totalFootageIntake;

    @ExcelAnnotation(headerName = "剩余允许进尺",
            index = 11, level = 1, parentIndex = 7)
    private Integer leftPermissionFootageIntake;

    @ExcelAnnotation(headerName = "备注",
            index = 12, level = 0, parentIndex = -1)
    private String remark;

    private Date createTime;

    private Date updateTime;

    private Integer sysdeptId;

    private static final long serialVersionUID = 1L;

    // 后续构造器及setter和getter省略
}
~~~

> 数据库中建表时,字段个数与上述model中字段个数相同,非传值字段(部分添加注释的属性),在数据库中可为null。

3. ExcelUtil类

~~~java
import com.longruan.hnny.scheduling.annotation.ExcelAnnotation;
import com.longruan.hnny.scheduling.common.Const;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.util.HSSFRegionUtil;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 导出excel文件工具类
 *
 * @author huxiaolong
 * @date 2018/8/22
 */
public class ExcelUtil {
    private static Logger logger = LoggerFactory.getLogger(ExcelUtil.class);

    /**
    * 接口方法
    * @param tableName 表名,添加在表头列之上
    * @param dataSet 从数据库中获取的对象集合
    * @param <E>
    * @return 包含完整数据和指定样式的HSSFWorkbook对象
    */
    public static <E> HSSFWorkbook exportExcel(String tableName, List<E> dataSet) {
        HSSFWorkbook hssfWorkbook = null;
        if (dataSet.size() > 0) {
            // 行索引,首行索引为0
            int rowIndex = 0;
            // 获取sheet信息
            Map<String, Object> sheetInfoMap = ExcelUtil.getSheetInfo(dataSet.get(0));
            String sheetName = (String) sheetInfoMap.get("sheetName");
            String datePattern = (String) sheetInfoMap.get("datePattern");
            boolean counted = (boolean) sheetInfoMap.get("counted");
            // 组装表头信息,已经依据cell的index进行过排序操作
            List<HeaderNode> headerNodeList = ExcelUtil.assembleHeaderNode(dataSet.get(0));
            if (!headerNodeList.isEmpty()) {
                // 如果有序号列,则进行下面的操作,添加序号列节点到HeaderNodeList首位
                if (counted) {
                    ExcelUtil.increasePreNotExtensibleHeaderNodeSum(headerNodeList);
                    HeaderNode headerNodeForCountColumn = new HeaderNode();
                    headerNodeForCountColumn.setHeaderName(Const.COUNT);
                    headerNodeForCountColumn.setIndex(-1);
                    headerNodeForCountColumn.setLevel(0);
                    headerNodeForCountColumn.setExtensible(false);
                    headerNodeForCountColumn.setPreNotExtensibleHeaderNodeSum(0);
                    headerNodeForCountColumn.setSubNotExtensibleHeaderNodeSum(0);
                    headerNodeList.add(0, headerNodeForCountColumn);
                }
                // 获取不可扩展cell(即就是子cell)的名称序列,因assembleHeaderNode方法的排序操作,此序列中cell名称同样为顺序存储
                List<String> notExtensibleHeaderNameList = ExcelUtil.getNotExtensibleHeaderNameList(headerNodeList);
                // 获得表头区域列数
                int columnSum = notExtensibleHeaderNameList.size();
                hssfWorkbook = new HSSFWorkbook();
                HSSFSheet hssfSheet = hssfWorkbook.createSheet(sh

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值