Apache POI 是 Apache 基金會開源專案,提供 Java API 操作 Microsoft Office 格式檔案。核心元件:
官方快速指南:https://poi.apache.org/spreadsheet/quick-guide.html
利用 Java 反射機制,支援任意符合 JavaBean 風格的類別,自動將集合資料導出為 Excel。支援基本型別、String、Date、byte[](圖片)。
public class Student {
private long id;
private String name;
private int age;
private boolean sex; // true=男, false=女
private Date birthday;
// getter/setter 略
}
public class Book {
private int id;
private String name, author, isbn, publisher;
private float price;
private byte[] coverImage; // JPEG 圖片資料
// getter/setter 略
}
ExportExcel<T>public class ExportExcel{ // 多載方法,預設標題與日期格式 public void exportExcel(Collection dataset, OutputStream out) { exportExcel("測試POI導出EXCEL文檔", null, dataset, out, "yyyy-MM-dd"); } public void exportExcel(String[] headers, Collection dataset, OutputStream out) { exportExcel("測試POI導出EXCEL文檔", headers, dataset, out, "yyyy-MM-dd"); } public void exportExcel(String[] headers, Collection dataset, OutputStream out, String pattern) { exportExcel("測試POI導出EXCEL文檔", headers, dataset, out, pattern); } /** 通用導出方法 */ @SuppressWarnings("unchecked") public void exportExcel(String title, String[] headers, Collection dataset, OutputStream out, String pattern) { HSSFWorkbook workbook = new HSSFWorkbook(); HSSFSheet sheet = workbook.createSheet(title); sheet.setDefaultColumnWidth((short) 15); // 標題樣式 HSSFCellStyle headerStyle = workbook.createCellStyle(); headerStyle.setFillForegroundColor(HSSFColor.SKY_BLUE.index); headerStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND); headerStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN); headerStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN); headerStyle.setBorderRight(HSSFCellStyle.BORDER_THIN); headerStyle.setBorderTop(HSSFCellStyle.BORDER_THIN); headerStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); HSSFFont headerFont = workbook.createFont(); headerFont.setColor(HSSFColor.VIOLET.index); headerFont.setFontHeightInPoints((short) 12); headerFont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); headerStyle.setFont(headerFont); // 資料樣式 HSSFCellStyle dataStyle = workbook.createCellStyle(); dataStyle.setFillForegroundColor(HSSFColor.LIGHT_YELLOW.index); dataStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND); dataStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN); dataStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN); dataStyle.setBorderRight(HSSFCellStyle.BORDER_THIN); dataStyle.setBorderTop(HSSFCellStyle.BORDER_THIN); dataStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); dataStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); HSSFFont dataFont = workbook.createFont(); dataFont.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL); dataStyle.setFont(dataFont); // 繪圖管理器(用於插入圖片/註解) HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); HSSFComment comment = patriarch.createComment( new HSSFClientAnchor(0, 0, 0, 0, (short) 4, 2, (short) 6, 5)); comment.setString(new HSSFRichTextString("可以在POI中添加註解!")); comment.setAuthor("leno"); // 寫入標題列 HSSFRow headerRow = sheet.createRow(0); for (short i = 0; i < headers.length; ++i) { HSSFCell cell = headerRow.createCell(i); cell.setCellStyle(headerStyle); cell.setCellValue(new HSSFRichTextString(headers[i])); } // 遍歷資料集,利用反射寫入資料列 Iterator it = dataset.iterator(); int rowIdx = 0; while (it.hasNext()) { ++rowIdx; HSSFRow row = sheet.createRow(rowIdx); T obj = it.next(); Field[] fields = obj.getClass().getDeclaredFields(); for (short i = 0; i < fields.length; ++i) { HSSFCell cell = row.createCell(i); cell.setCellStyle(dataStyle); Field field = fields[i]; String getter = "get" + field.getName().substring(0,1).toUpperCase() + field.getName().substring(1); try { Method method = obj.getClass().getMethod(getter); Object value = method.invoke(obj); String textValue = null; if (value instanceof Boolean) { textValue = (Boolean)value ? "男" : "女"; } else if (value instanceof Date) { textValue = new SimpleDateFormat(pattern).format((Date)value); } else if (value instanceof byte[]) { // 插入圖片 row.setHeightInPoints(60); sheet.setColumnWidth(i, (short)(35.7 * 80)); byte[] bs = (byte[])value; HSSFClientAnchor anchor = new HSSFClientAnchor(0,0,1023,255,(short)6,rowIdx,(short)6,rowIdx); anchor.setAnchorType(2); patriarch.createPicture(anchor, workbook.addPicture(bs, HSSFWorkbook.PICTURE_TYPE_JPEG)); } else { textValue = value.toString(); } if (textValue != null) { // 純數字轉 double,其餘藍字顯示 if (textValue.matches("^\\d+(\\.\\d+)?$")) { cell.setCellValue(Double.parseDouble(textValue)); } else { HSSFRichTextString rich = new HSSFRichTextString(textValue); HSSFFont f = workbook.createFont(); f.setColor(HSSFColor.BLUE.index); rich.applyFont(f); cell.setCellValue(rich); } } } catch (Exception e) { e.printStackTrace(); } } } try { workbook.write(out); } catch (IOException e) { e.printStackTrace(); } } // 測試 main 方法略 }
ExportExcelex = new ExportExcel<>(); String[] headers = {"學號","姓名","年齡","性別","出生日期"}; List data = Arrays.asList( new Student(10000001, "張三", 20, true, new Date()), new Student(20000002, "李四", 24, false, new Date()) ); ex.exportExcel(headers, data, new FileOutputStream("students.xls"));