美文网首页简更想法无戒学堂:365天极限挑战日更营
一种基于POI操作复杂样式Excel的思路及其实现

一种基于POI操作复杂样式Excel的思路及其实现

作者: 日更专用小马甲 | 来源:发表于2019-03-24 18:06 被阅读34次

基于 上一篇 提到的想法,今天抽时间实现出来了。

先贴截图。

运行结果

个人觉得填充底色,合并单元格,各种设置格式之流的操作用纯代码来实现还是蛮耗费精力的。但是,如果是基于下面这样已经调好格式的模板,只需要往里填充数据的话,工作量要小很多。

模板

模板通过2个sheet拼接完成。代码填充好第一个sheet的数据之后,再把第二个sheet的内容拷贝到第一个sheet的最后。

数据是通过POJO和自定义注解配合完成的。目前注解主要用于获得单元格所对应的行,后期还会添加其他属性。时间关系,POJO的属性暂时也只支持了String一种类型。

注解定义如下:

/**
 * @author nathan
 * @date 2019/3/24
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelProperties {
    int index();
}

一个示例POJO如下:

/**
 * @author nathan
 * @date 2019/3/24
 */
@Getter
@Setter
public class FooDTO {

    @ExcelProperties(index = 0)
    private String empty1;

    @ExcelProperties(index = 1)
    private String busiName;

    @ExcelProperties(index = 2)
    private String busiType;

    @ExcelProperties(index = 3)
    private String empty2;

    @ExcelProperties(index = 4)
    private String value1;

    @ExcelProperties(index = 5)
    private String value2;

    @ExcelProperties(index = 6)
    private String empty3;
}

一个可以运行的Demo:

/**
 * @author nathan
 * @date 2019/3/24
 */
public class RptUtil {

    public static void main(String[] args) {
        // 从第1行,第4列开始,用户指定
        int startRow = 0;
        int startCol = 4;
        List<FooDTO> foos = getFooList();

        int sheet2StartRow = 1;
        int sheet2StartCol = 2;

        File template = new File("/tmp/template.xlsx");
        File output = new File("/tmp/test.xlsx");

        // 从template文件读取2个sheet
        // sheet1从第0行,第4列开始插入数据
        // sheet2从第1行,第2列开始读取
        write(template, output, foos, startRow, startCol, true, sheet2StartRow, sheet2StartCol);
    }

    private static List<FooDTO> getFooList() {
        FooDTO foo1 = new FooDTO();
        foo1.setBusiName("测试名称1");
        foo1.setBusiType("测试类型1");
        foo1.setValue1("50.12");
        foo1.setValue2("12.86");
        return Lists.newArrayList(foo1);
    }

    public static <T> void write(File template, File output, List<T> data, int startRow, int startCol, boolean copySheet2, int sheet2StartRow, int sheet2StartCol) {
        FileInputStream in = null;
        FileOutputStream out = null;

        try {
            in = new FileInputStream(template);

            XSSFWorkbook source = new XSSFWorkbook(in);

            // 获得sheet1的内容
            XSSFSheet sheet1 = source.getSheetAt(0);
            // 插入主体数据1
            insertData(data, sheet1, startRow, startCol);

            if (copySheet2) {
                copyFromSheet2(source, sheet1, startCol + data.size() - sheet2StartCol, sheet2StartRow, sheet2StartCol);
            }

            // 写入到output
            out = new FileOutputStream(output);
            source.write(out);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(in);
            close(out);
        }
    }

    /**
     * 关闭资源
     *
     * @param closeable
     */
    private static void close(Closeable closeable) {
        if(closeable != null) {
            try {
                closeable.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 插入数据(List形式)
     *
     * @param data
     * @param sheet
     * @param startRow
     * @param startCol
     * @param <T>
     * @throws Exception
     */
    private static <T> void insertData(List<T> data, XSSFSheet sheet, int startRow, int startCol) throws Exception {
        for (T t : data) {
            insertOne(t, sheet, startRow, startCol);
            startCol++;
        }
    }

    /**
     * 插入数据(单条)
     *
     * @param data
     * @param sheet
     * @param startRow
     * @param startCol
     * @param <T>
     * @throws Exception
     */
    private static <T> void insertOne(T data, XSSFSheet sheet, int startRow, int startCol) throws Exception {

        XSSFCell cell;
        XSSFRow row;

        for (Field field : data.getClass().getDeclaredFields()) {

            int index = -1;
            String value = "";

            if (field.isAnnotationPresent(ExcelProperties.class)) {

                ExcelProperties props = field.getAnnotation(ExcelProperties.class);
                field.setAccessible(true);

                if (field.getGenericType().toString().equals("class java.lang.String")) {

                    String name = field.getName();
                    name = name.substring(0, 1).toUpperCase() + name.substring(1);

                    Method m = data.getClass().getMethod("get" + name);
                    String val = (String) m.invoke(data);

                    index = props.index();
                    value = val;
                }
            }

            if (index != -1) {
                row = sheet.getRow(startRow + index);
                // 找到最后一个cell
                Cell lastCell = row.getCell(row.getLastCellNum() - 1);
                // 创建一个cell
                cell = row.createCell(startCol);
                // 拷贝样式
                cell.setCellStyle(lastCell.getCellStyle());
                // 设置值
                cell.setCellValue(value);
            }
        }
    }

    /**
     * 把sheet2的内容拷贝到sheet1
     *
     * @param source
     * @param sheet
     * @param startCol
     * @param sheet2StartRow
     * @param sheet2StartCol
     */
    private static void copyFromSheet2(XSSFWorkbook source, XSSFSheet sheet, int startCol, int sheet2StartRow, int sheet2StartCol) {
        // 从sheet2获得剩余部分内容,并插入到sheet1
        XSSFCell cell;
        XSSFRow row;

        // 插入sheet2的内容
        XSSFSheet sheet2 = source.getSheetAt(1);
        Iterator<Row> iterator = sheet2.iterator();

        // 跳过若干行
        while (sheet2StartRow > 1) {
            iterator.next();
            sheet2StartRow--;
        }

        int count = 0;
        while (iterator.hasNext()) {
            XSSFRow current = (XSSFRow) iterator.next();
            row = sheet.getRow(count);

            for (int j = sheet2StartCol; j < current.getLastCellNum(); j++) {
                cell = row.createCell(startCol + j);
                cell.copyCellFrom(current.getCell(j), new CellCopyPolicy());
            }
            count++;
        }
        // 删除sheet2
        source.removeSheetAt(1);
    }
}

maven依赖:

<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>3.17</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.17</version>
</dependency>

相关文章

网友评论

    本文标题:一种基于POI操作复杂样式Excel的思路及其实现

    本文链接:https://www.haomeiwen.com/subject/dukuvqtx.html