Java Excel (Apache POI + annotation)

思路: 自定义注解, 导出/读取 excel 根据注解自动解析字段

  • 注解
package com.excel;

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

@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelClassAnnotation {

    String sheetName();

}

package com.excel;

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

@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelFieldAnnotation {

    int columnIndex();

    String headerName() default "";
    
}


  • 注解与excel mapping
package com.excel;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;

public class CellTemplate implements Comparable {

    private final static SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:ss:mm");

    private Field field;
    private String annotation_headerName;
    private int annotation_columnIndex;

    public static CellTemplate getInstance(Field field) {
        CellTemplate mappingCell = new CellTemplate();
        Annotation[] annotations = field.getAnnotations();
        if (annotations == null || annotations.length == 0) {
            return null;
        }
        for (Annotation annotation : annotations) {
            if (annotation instanceof ExcelFieldAnnotation) {
                ExcelFieldAnnotation res = (ExcelFieldAnnotation) annotation;
                mappingCell.field = field;
                mappingCell.annotation_columnIndex = res.columnIndex();
                mappingCell.annotation_headerName = res.headerName();
                if (mappingCell.annotation_headerName == null || mappingCell.annotation_headerName.trim().length() == 0) {
                    mappingCell.annotation_headerName = field.getName();
                }
                return mappingCell;
            }
        }

        return null;
    }

    public void createCell(Row row, Object obj) throws IllegalArgumentException, IllegalAccessException {
        Cell cell = row.createCell(annotation_columnIndex);
        boolean isAccessible = field.isAccessible();
        field.setAccessible(true);

        Class fieldClass = field.getType();

        if (fieldClass == Integer.class || fieldClass == int.class) {
            int value = field.getInt(obj);
            cell.setCellValue(value);
            cell.setCellType(CellType.NUMERIC);
        } else if (fieldClass == Short.class || fieldClass == short.class) {
            short value = field.getShort(obj);
            cell.setCellValue(value);
            cell.setCellType(CellType.NUMERIC);
        } else if (fieldClass == Long.class || fieldClass == long.class) {
            long value = field.getShort(obj);
            cell.setCellValue(value);
            cell.setCellType(CellType.NUMERIC);
        } else if (fieldClass == String.class) {
            String value = field.get(obj).toString();
            cell.setCellValue(value);
            cell.setCellType(CellType.STRING);
        } else if (fieldClass == Double.class || fieldClass == double.class) {
            double value = field.getDouble(obj);
            cell.setCellValue(value);
            cell.setCellType(CellType.NUMERIC);
        } else if (fieldClass == Float.class || fieldClass == float.class) {
            float value = field.getFloat(obj);
            cell.setCellValue(value);
            cell.setCellType(CellType.NUMERIC);
        } else if (fieldClass == Byte.class || fieldClass == byte.class) {
            byte value = field.getByte(obj);
            cell.setCellValue(value);
            cell.setCellType(CellType.NUMERIC);
        } else if (fieldClass == Character.class || fieldClass == char.class) {
            char value = field.getChar(obj);
            cell.setCellValue(value);
            cell.setCellType(CellType.STRING);
        } else if (fieldClass == Boolean.class) {
            boolean value = field.getBoolean(obj);
            cell.setCellValue(value);
            cell.setCellType(CellType.BOOLEAN);
        } else if (fieldClass == Date.class) {
            String value = DATE_FORMAT.format((Date) field.get(obj));
            cell.setCellValue(value);
            cell.setCellType(CellType.STRING);
        } else {
            throw new RuntimeException(fieldClass + " is not supported.");
        }

        field.setAccessible(isAccessible);
    }

    public void createHeaderCell(Row row) {
        Cell cell = row.createCell(annotation_columnIndex);
        cell.setCellValue(annotation_headerName);
        cell.setCellType(CellType.STRING);
    }

    public void invokeObjectProperty(Cell cell, Object obj) throws IllegalArgumentException, IllegalAccessException, ParseException {
        boolean isAccessible = field.isAccessible();
        field.setAccessible(true);

        Class fieldClass = field.getType();

        if (fieldClass == Integer.class || fieldClass == int.class) {
            int value = (int) cell.getNumericCellValue();
            field.set(obj, value);
        } else if (fieldClass == Short.class || fieldClass == short.class) {
            short value = (short) cell.getNumericCellValue();
            field.set(obj, value);
        } else if (fieldClass == Long.class || fieldClass == long.class) {
            long value = (long) cell.getNumericCellValue();
            field.set(obj, value);
        } else if (fieldClass == String.class) {
            String value = cell.getStringCellValue();
            field.set(obj, value);
        } else if (fieldClass == Double.class || fieldClass == double.class) {
            double value = cell.getNumericCellValue();
            field.set(obj, value);
        } else if (fieldClass == Float.class || fieldClass == float.class) {
            float value = (float) cell.getNumericCellValue();
            field.set(obj, value);
        } else if (fieldClass == Byte.class || fieldClass == byte.class) {
            byte value = (byte) cell.getNumericCellValue();
            field.set(obj, value);
        } else if (fieldClass == Character.class || fieldClass == char.class) {
            char value = (char) cell.getNumericCellValue();
            field.set(obj, value);
        } else if (fieldClass == Boolean.class) {
            Boolean value = (Boolean) cell.getBooleanCellValue();
            field.set(obj, value);
        } else if (fieldClass == Date.class) {
            Date value = DATE_FORMAT.parse(cell.getStringCellValue());
            field.set(obj, value);
        } else {
            throw new RuntimeException(fieldClass + " is not supported.");
        }

        field.setAccessible(isAccessible);
    }

    public int compareTo(CellTemplate obj) {
        if (this.annotation_columnIndex == obj.annotation_columnIndex) {
            return 0;
        }
        return this.annotation_columnIndex > obj.annotation_columnIndex ? 1 : -1;
    }

}


  • 工厂, 根据后缀名调用不同的api
package com.excel;

import java.io.IOException;

public class ExcelUtilsFactory {

    static final String EXCEL_XLS = ".xls";
    static final String EXCEL_XLSX = ".xlsx";

    public static ExcelUtilsBase getInstance(String fileFullName) throws IOException {
        ExcelVersionEnum version = getExcelPostfix(fileFullName);
        switch (version) {
        case XLS:
            return new ExcelUtilsXls(fileFullName);
        case XLSX:
            return new ExcelUtilsXlsx(fileFullName);
        default:
            throw new IllegalArgumentException(fileFullName);
        }
    }

    private static ExcelVersionEnum getExcelPostfix(String excelFileName) {
        if (excelFileName == null) {
            throw new IllegalArgumentException(excelFileName);
        }

        if (excelFileName.endsWith(EXCEL_XLS)) {
            return ExcelVersionEnum.XLS;
        } else if (excelFileName.endsWith(EXCEL_XLSX)) {
            return ExcelVersionEnum.XLSX;
        }
        throw new IllegalArgumentException(excelFileName);
    }

}

package com.excel;
public enum ExcelVersionEnum {

    NONE, XLS, XLSX;
}

  • 核心类
package com.excel;

import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;

public abstract class ExcelUtilsBase {

    protected String fileFullName;

    public ExcelUtilsBase(String fileFullName) {
        this.fileFullName = fileFullName;
    }

    /**
     * add a sheet to the excel located on fileFullName; 
* If the file exist, will add a new sheet to it; if not will create a new * excel. * * @param srcContent * the excel content * @param cls * the type of the content pojo * @throws IOException */ public void create(List srcContent, Class cls) throws IOException { FileOutputStream outputStream = null; Workbook workbook = null; try { String sheetName = getExportSheetName(cls); List templateList = getExportableFields(cls); workbook = createOrGetWorkBook(true); fillWorkBook(workbook, sheetName, templateList, srcContent); outputStream = new FileOutputStream(fileFullName); workbook.write(outputStream); } catch (Exception ex) { ex.printStackTrace(); } finally { close(workbook, outputStream); } } public List read(Class cls) throws IOException { List content = new ArrayList(); FileInputStream inputStream = null; Workbook workbook = null; try { workbook = createOrGetWorkBook(false); Sheet sheet = readSheet(cls, workbook); content = readContent(sheet, cls); } catch (Exception ex) { ex.printStackTrace(); } finally { close(workbook, inputStream); } return content; } protected abstract Workbook createBlankNewWorkbook(); protected abstract Workbook getWorkbook() throws FileNotFoundException, IOException; protected abstract void fillWorkBook(Workbook workbook, String sheetName, List templateList, List srcContent) throws IllegalArgumentException, IllegalAccessException; private Workbook createOrGetWorkBook(boolean createNewIfNotFound) throws FileNotFoundException, IOException { if (fileExist()) { return getWorkbook(); } else { if (createNewIfNotFound) { return createBlankNewWorkbook(); } else { throw new FileNotFoundException(fileFullName); } } } protected boolean fileExist() { File file = new File(fileFullName); return file.exists(); } private Sheet getSheetBySheetName(Workbook workbook, String sheetName) { Iterator iterator = workbook.sheetIterator(); while (iterator.hasNext()) { Sheet sheet = iterator.next(); if (sheet.getSheetName().equals(sheetName)) { return sheet; } } throw new RuntimeException("Can't find sheet " + sheetName); } private Sheet readSheet(Class cls, Workbook workbook) { String sheetName = getExportSheetName(cls); Sheet sheet = getSheetBySheetName(workbook, sheetName); return sheet; } private List readContent(Sheet sheet, Class cls) throws InstantiationException, IllegalAccessException, IllegalArgumentException, ParseException { List result = new ArrayList(); List templateList = getExportableFields(cls); Iterator rows = sheet.rowIterator(); skipExcelHeader(rows); while (rows.hasNext()) { Row row = rows.next(); T item = readRow(cls, templateList, row); result.add(item); } return result; } private void skipExcelHeader(Iterator rows) { rows.next(); } private T readRow(Class cls, List templateList, Row row) throws InstantiationException, IllegalAccessException, IllegalArgumentException, ParseException { T item = cls.newInstance(); Iterator cells = row.cellIterator(); int columnIndex = 0; while (cells.hasNext()) { Cell cell = cells.next(); templateList.get(columnIndex).invokeObjectProperty(cell, item); columnIndex++; } return item; } private String getExportSheetName(Class cls) { Annotation[] annotations = cls.getAnnotations(); for (Annotation annotation : annotations) { if (annotation instanceof ExcelClassAnnotation) { return ((ExcelClassAnnotation) annotation).sheetName(); } } throw new IllegalArgumentException(cls + "is not exportable."); } private List getExportableFields(Class cls) { List templateList = new ArrayList(); Field[] declaredFields = cls.getDeclaredFields(); for (Field field : declaredFields) { CellTemplate template = CellTemplate.getInstance(field); if (template != null) { templateList.add(template); } } Collections.sort(templateList); return templateList; } protected void close(Closeable... itemsToClose) throws IOException { if (itemsToClose != null) { for (Closeable closeable : itemsToClose) { if (closeable != null) { closeable.close(); } } } } }
package com.excel;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;

import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Workbook;

public class ExcelUtilsXls extends ExcelUtilsBase {

    public ExcelUtilsXls(String fileFullName) {
        super(fileFullName);
    }

    @Override
    protected Workbook createBlankNewWorkbook() {
        return new HSSFWorkbook();
    }

    @Override
    protected Workbook getWorkbook() throws FileNotFoundException, IOException {
        try (FileInputStream inputStream = new FileInputStream(fileFullName)) {
            return new HSSFWorkbook(inputStream);
        }
    }

    @Override
    public  void fillWorkBook(Workbook workbook, String sheetName, List templateList, List srcContent) throws IllegalArgumentException, IllegalAccessException {
        HSSFSheet sheet = ((HSSFWorkbook) workbook).createSheet(sheetName);
        createHeaderRow(templateList, sheet);
        createBodyRows(templateList, srcContent, sheet);
    }

    private void createHeaderRow(List templateList, HSSFSheet sheet) {
        HSSFRow headerRow = sheet.createRow(0);
        for (CellTemplate template : templateList) {
            template.createHeaderCell(headerRow);
        }
    }

    private  void createBodyRows(List templateList, List srcContent, HSSFSheet sheet) throws IllegalAccessException {
        int rownum = 1;
        for (T item : srcContent) {
            HSSFRow row = sheet.createRow(rownum++);
            for (CellTemplate template : templateList) {
                template.createCell(row, item);
            }
        }
    }

}


package com.excel;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;

import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class ExcelUtilsXlsx extends ExcelUtilsBase {

    public ExcelUtilsXlsx(String fileFullName) {
        super(fileFullName);
    }

    @Override
    protected Workbook createBlankNewWorkbook() {
        return new XSSFWorkbook();
    }

    @Override
    protected Workbook getWorkbook() throws FileNotFoundException, IOException {
        try (FileInputStream inputStream = new FileInputStream(fileFullName)) {
            return new XSSFWorkbook(inputStream);
        }
    }

    @Override
    public  void fillWorkBook(Workbook workbook, String sheetName, List templateList, List srcContent) throws IllegalArgumentException, IllegalAccessException {
        XSSFSheet sheet = ((XSSFWorkbook) workbook).createSheet(sheetName);
        createHeaderRow(templateList, sheet);
        createBodyRows(templateList, srcContent, sheet);
    }

    private void createHeaderRow(List templateList, XSSFSheet sheet) {
        XSSFRow headerRow = sheet.createRow(0);
        for (CellTemplate template : templateList) {
            template.createHeaderCell(headerRow);
        }
    }

    private  void createBodyRows(List templateList, List srcContent, XSSFSheet sheet) throws IllegalAccessException {
        int rownum = 1;
        for (T item : srcContent) {
            XSSFRow row = sheet.createRow(rownum++);
            for (CellTemplate template : templateList) {
                template.createCell(row, item);
            }
        }
    }

}


  • test
package pojo;


import java.util.Date;

import com.excel.ExcelClassAnnotation;
import com.excel.ExcelFieldAnnotation;

@ExcelClassAnnotation(sheetName = "staff")
public class Record {

    @ExcelFieldAnnotation(columnIndex = 1, headerName = "id")
    private int id;

    @ExcelFieldAnnotation(columnIndex = 3, headerName = "name")
    private String name;

    @ExcelFieldAnnotation(columnIndex = 0, headerName = "age")
    private int age;

    @ExcelFieldAnnotation(columnIndex = 2)
    private double salary;
    
    @ExcelFieldAnnotation(columnIndex = 4)
    private Date aaa;
    
    public Record(){}
    
    public Record(int id, String name, int age, double salary,Date date) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.salary = salary;
        this.aaa=date;
    }

    @Override
    public String toString() {
        return String.format("id:%s\tage:%s\tsalary:%s\tname:%s\tdate:%s", id, age, salary,name,aaa.toLocaleString());
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

}




import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.excel.ExcelUtilsFactory;

import pojo.Record;

public class Main {

    public static void main(String[] args) throws IOException, IllegalArgumentException, IllegalAccessException, InstantiationException {
        test7();
        test8();
        test9();

        // test10();
    }

    private static void test10() throws IOException {
        List records = new ArrayList();
        records.add(new Record(1, "a", 12, 11.1d,new Date()));
        records.add(new Record(2, "b", 13, 12.1d,new Date()));
        records.add(new Record(3, "c", 14, 13.1d,new Date()));

        ExcelUtilsFactory.getInstance("c:\\work\\b.xls").create(records, Record.class);
        ExcelUtilsFactory.getInstance("c:\\work\\b.xlsx").create(records, Record.class);
    }

    private static void test9() throws IOException {
        System.out.println(ExcelUtilsFactory.getInstance("c:\\work\\b.xlsx").read(Record.class));
        System.out.println(ExcelUtilsFactory.getInstance("c:\\work\\b.xls").read(Record.class));
    }

    static void test7() throws IOException, IllegalArgumentException, IllegalAccessException {
        List records = new ArrayList();
        records.add(new Record(1, "a", 12, 11.1d,new Date()));
        records.add(new Record(2, "b", 13, 12.1d,new Date()));
        records.add(new Record(3, "c", 14, 13.1d,new Date()));

        ExcelUtilsFactory.getInstance("c:\\work\\b.xls").create(records, Record.class);
    }

    static void test8() throws IOException, IllegalArgumentException, IllegalAccessException {
        List records = new ArrayList();
        records.add(new Record(1, "a", 12, 11.1d,new Date()));
        records.add(new Record(2, "b", 13, 12.1d,new Date()));
        records.add(new Record(3, "c", 14, 13.1d,new Date()));
        ExcelUtilsFactory.getInstance("c:\\work\\b.xlsx").create(records, Record.class);
    }

}


你可能感兴趣的:(Java Excel (Apache POI + annotation))