Hướng Dẫn Toàn Diện Về Apache POI: Thao Tác Và Xuất File Excel Phức Tạp Trong Java

1. Kiến Trúc và Các Thành Phần Cốt Lõi của Apache POI

Apache POI là một thư viện mã nguồn mở mạnh mẽ do Apache Software Foundation phát triển, cung cấp API cho phép các ứng dụng Java đọc, ghi và thao tác với các định dạng tệp tin Microsoft Office. Đối với hệ sinh thái .NET, thư viện tương đương là NPOI.

Các Module Chính

  • HSSF (Horrible SpreadSheet Format): Xử lý định dạng Excel cũ (.xls - Excel 97-2003).
  • XSSF (XML SpreadSheet Format): Xử lý định dạng Excel mới (.xlsx - Excel 2007+ dựa trên OOXML).
  • HWPF / XWPF: Thao tác với tài liệu Word (.doc và .docx).
  • HSLF / XSLF: Thao tác với PowerPoint.
  • HDGF / HSMF: Xử lý Visio và Outlook.

Các Interface và Class Thường Dùng

Để viết mã linh hoạt và dễ dàng chuyển đổi giữa .xls và .xlsx, bạn nên sử dụng các interface chung thay vì các class cụ thể của HSSF hay XSSF:

Interface / ClassChức Năng
WorkbookĐại diện cho toàn bộ tài liệu Excel.
SheetĐại diện cho một trang tính (Worksheet).
RowĐại diện cho một hàng dữ liệu.
CellĐại diện cho một ô dữ liệu.
CellStyleQuản lý định dạng (màu sắc, viền, font chữ).
CreationHelperFactory tạo ra các đối tượng phức tạp như công thức, hyperlink.

2. Các Thao Tác Cơ Bản Với Excel

Khởi Tạo Workbook và Sheet

Dưới đây là cách tạo một file Excel mới, thêm trang tính và ghi dữ liệu ra ổ đĩa. Mã nguồn được tối ưu hóa bằng try-with-resources để tự động đóng luồng.

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileOutputStream;
import java.io.IOException;

public class ExcelCreator {
    public static void main(String[] args) {
        String targetPath = "output/financial_report.xlsx";
        
        // Sử dụng XSSFWorkbook cho định dạng .xlsx
        try (Workbook workbook = new XSSFWorkbook();
             FileOutputStream fileOut = new FileOutputStream(targetPath)) {
             
            Sheet reportSheet = workbook.createSheet("DoanhThu_Q1");
            Sheet summarySheet = workbook.createSheet("TongHop");
            
            workbook.write(fileOut);
            System.out.println("Tạo file Excel thành công!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Ghi Dữ Liệu Vào Ô (Cell)

Các kiểu dữ liệu như chuỗi, số, boolean và ngày tháng đều có thể được gán trực tiếp vào ô.

Sheet dataSheet = workbook.createSheet("DuLieu");
Row headerRow = dataSheet.createRow(0);

// Tạo và gán giá trị chuỗi
Cell nameCell = headerRow.createCell(0);
nameCell.setCellValue("HoTen");

// Tạo và gán giá trị boolean, số thực
headerRow.createCell(1).setCellValue("IsActive");
headerRow.createCell(2).setCellValue(98.75);

Thiết Lập Metadata (Thuộc Tính Tài Liệu)

Thêm thông tin tác giả, tiêu đề giúp quản lý tệp tin chuyên nghiệp hơn:

import org.apache.poi.ooxml.POIXMLProperties;

POIXMLProperties props = ((XSSFWorkbook) workbook).getProperties();
props.getCoreProperties().setCreator("HeThongERP");
props.getCoreProperties().setTitle("BaoCaoTaiChinh");
props.getExtendedProperties().getUnderlyingProperties().setCompany("TechCorp VietNam");

Tạo Chú Thích (Comment)

Drawing drawing = dataSheet.createDrawingPatriarch();
CreationHelper factory = workbook.getCreationHelper();

// Định vị trí comment (col1, row1, col2, row2)
ClientAnchor anchor = factory.createClientAnchor();
anchor.setCol1(2); anchor.setRow1(1);
anchor.setCol2(5); anchor.setRow2(4);

Comment cellComment = drawing.createCellComment(anchor);
cellComment.setString(factory.createRichTextString("Doanh thu chưa bao gồm VAT"));
cellComment.setAuthor("KeToanTruong");

Cell targetCell = dataSheet.createRow(1).createCell(2);
targetCell.setCellValue(5000000);
targetCell.setCellComment(cellComment);

3. Định Dạng và Thao Tác Nâng Cao Với Ô

Lưu ý quan trọng cho Kỹ sư: Luôn tạo CellStyle ở cấp độ Workbook và tái sử dụng chúng. Việc tạo style mới cho từng ô sẽ dẫn đến lỗi tràn bộ nhớ (OutOfMemory) đối với file lớn.

Định Dạng Dữ Liệu (Format)

CellStyle currencyStyle = workbook.createCellStyle();
CreationHelper createHelper = workbook.getCreationHelper();
// Định dạng tiền tệ Việt Nam
currencyStyle.setDataFormat(createHelper.createDataFormat().getFormat("#,##0 VND"));

Row moneyRow = dataSheet.createRow(2);
Cell priceCell = moneyRow.createCell(0);
priceCell.setCellValue(15000000);
priceCell.setCellStyle(currencyStyle);

Gộp Ô (Merge Cells)

Sử dụng CellRangeAddress để gộp các ô liền kề. Tham số lần lượt là: (firstRow, lastRow, firstCol, lastCol).

import org.apache.poi.ss.util.CellRangeAddress;

Row titleRow = dataSheet.createRow(3);
titleRow.createCell(0).setCellValue("BAO CAO TONG HOP");
// Gộp từ cột 0 đến cột 3 của hàng 3
dataSheet.addMergedRegion(new CellRangeAddress(3, 3, 0, 3));

Căn Chỉnh, Viền và Font Chữ

CellStyle headerStyle = workbook.createCellStyle();

// Căn giữa
headerStyle.setAlignment(HorizontalAlignment.CENTER);
headerStyle.setVerticalAlignment(VerticalAlignment.CENTER);

// Thiết lập viền
headerStyle.setBorderTop(BorderStyle.THIN);
headerStyle.setBorderBottom(BorderStyle.MEDIUM);
headerStyle.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());

// Cấu hình Font
Font headerFont = workbook.createFont();
headerFont.setFontName("Arial");
headerFont.setBold(true);
headerFont.setFontHeightInPoints((short) 12);
headerFont.setColor(IndexedColors.WHITE.getIndex());
headerStyle.setFont(headerFont);

// Nền màu
headerStyle.setFillForegroundColor(IndexedColors.DARK_BLUE.getIndex());
headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);

// Áp dụng style
titleRow.getCell(0).setCellStyle(headerStyle);

Điều Chỉnh Kích Thước

Chiều rộng cột trong POI được tính bằng 1/256 độ rộng ký tự. Chiều cao hàng tính bằng points.

dataSheet.setColumnWidth(0, 30 * 256); // Rộng 30 ký tự
titleRow.setHeightInPoints(25); // Cao 25 points

4. Tích Hợp Công Thức (Formulas)

POI hỗ trợ ghi trực tiếp các chuỗi công thức Excel tiêu chuẩn vào ô.

Các Công Thức Thông Dụng

Row formulaRow = dataSheet.createRow(5);
formulaRow.createCell(0).setCellValue(150);
formulaRow.createCell(1).setCellValue(200);

Cell sumCell = formulaRow.createCell(2);
sumCell.setCellFormula("SUM(A6:B6)"); // Tính tổng

Cell ifCell = formulaRow.createCell(3);
ifCell.setCellFormula("IF(C6>300, \"Dat\", \"Khong Dat\")"); // Logic IF

Cell lookupCell = formulaRow.createCell(4);
lookupCell.setCellFormula("VLOOKUP(A6, $A$1:$C$4, 3, FALSE)");

Đánh Giá Công Thức (Formula Evaluation)

Để lấy kết quả tính toán của công thức ngay trong Java mà không cần mở bằng Excel:

FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
CellValue evaluatedValue = evaluator.evaluate(sumCell);
System.out.println("Ket qua cua SUM: " + evaluatedValue.getNumberValue());

5. Đồ Họa và Hình Ảnh

Vẽ Các Hình Khối Cơ Bản

Sử dụng ClientAnchor để neo vị trí hình vẽ dựa trên tọa độ ô.

Drawing drawingPatriarch = dataSheet.createDrawingPatriarch();
ClientAnchor shapeAnchor = new XSSFClientAnchor(0, 0, 0, 0, 2, 10, 5, 15);

SimpleShape rectangle = drawingPatriarch.createSimpleShape(shapeAnchor);
rectangle.setShapeType(ShapeTypes.RECTANGLE);
rectangle.setLineStyleColor(255, 0, 0); // Viền đỏ
rectangle.setFillColor(200, 200, 200);  // Nền xám
rectangle.setLineWidth(2.5);

Chèn Ảnh Vào Excel

import java.io.InputStream;
import org.apache.poi.util.IOUtils;

try (InputStream is = ExcelCreator.class.getResourceAsStream("/logo.png")) {
    byte[] bytes = IOUtils.toByteArray(is);
    int pictureIdx = workbook.addPicture(bytes, Workbook.PICTURE_TYPE_PNG);
    
    ClientAnchor imgAnchor = new XSSFClientAnchor();
    imgAnchor.setCol1(1); imgAnchor.setRow1(1);
    imgAnchor.setCol2(3); imgAnchor.setRow2(6);
    
    Picture picture = drawingPatriarch.createPicture(imgAnchor, pictureIdx);
    // picture.resize(); // Tự động điều chỉnh kích thước ảnh
}

6. Quản Lý Sheet và Cấu Trúc Bảng

Đổi Tên và Chọn Sheet Mặc Định

workbook.setSheetName(0, "BaoCao_Chinh");
workbook.setActiveSheet(0); // Đặt làm sheet mặc định khi mở file

Cố Định Hàng/Cột (Freeze Panes)

Giúp tiêu đề luôn hiển thị khi cuộn trang. Tham số: (colSplit, rowSplit).

// Cố định hàng đầu tiên (Tiêu đề cột)
dataSheet.createFreezePane(0, 1);

Ẩn/Hiện Lưới và Grouping

dataSheet.setDisplayGridlines(false); // Tắt đường kẻ ô
// Nhóm các hàng từ 5 đến 10 lại (có nút +/- để thu gọn)
dataSheet.groupRow(4, 9); 

7. Tính Năng Bảo Mật và Tương Tác

Khóa Sheet Bằng Mật Khẩu

CellStyle unlockedStyle = workbook.createCellStyle();
unlockedStyle.setLocked(false);

Cell editableCell = dataSheet.createRow(20).createCell(0);
editableCell.setCellValue("Co the chinh sua");
editableCell.setCellStyle(unlockedStyle);

// Khóa toàn bộ sheet, ngoại trừ các ô được set unlockedStyle
dataSheet.protectSheet("MatKhauBiMat123");

Data Validation (Tạo Dropdown List)

Giới hạn dữ liệu đầu vào bằng danh sách thả xuống.

DataValidationHelper validationHelper = dataSheet.getDataValidationHelper();
DataValidationConstraint constraint = validationHelper.createExplicitListConstraint(
    new String[]{"Ha Noi", "Ho Chi Minh", "Da Nang"}
);
CellRangeAddressList addressList = new CellRangeAddressList(1, 100, 0, 0); // Cột A, hàng 2 đến 101
DataValidation validation = validationHelper.createValidation(constraint, addressList);
validation.createErrorBox("Loi Du Lieu", "Vui long chon thanh pho hop le!");
dataSheet.addValidationData(validation);

Chèn Hyperlink

CreationHelper linkHelper = workbook.getCreationHelper();
Hyperlink link = linkHelper.createHyperlink(HyperlinkType.URL);
link.setAddress("https://github.com/apache/poi");

Cell linkCell = dataSheet.createRow(22).createCell(0);
linkCell.setCellValue("Truy cap POI Repository");
linkCell.setHyperlink(link);

8. Thao Tác Cơ Bản Với Word (Apache XWPF)

Mặc dù POI nổi tiếng với Excel, module XWPF cũng cung cấp khả năng xử lý file .docx.

Tạo Tài Liệu Word Mới

import org.apache.poi.xwpf.usermodel.*;
import java.io.FileOutputStream;

try (XWPFDocument document = new XWPFDocument();
     FileOutputStream out = new FileOutputStream("contract.docx")) {

    // Tạo đoạn văn
    XWPFParagraph paragraph = document.createParagraph();
    paragraph.setAlignment(ParagraphAlignment.CENTER);
    
    XWPFRun run = paragraph.createRun();
    run.setText("HOP DONG LAO DONG");
    run.setBold(true);
    run.setFontSize(16);
    run.setColor("0000FF");

    // Tạo bảng biểu
    XWPFTable table = document.createTable(3, 3);
    table.getRow(0).getCell(0).setText("STT");
    table.getRow(0).getCell(1).setText("Noi Dung");
    table.getRow(0).getCell(2).setText("Gia Tri");

    document.write(out);
}

Trích Xuất Văn Bản Từ Word

import java.io.FileInputStream;

try (FileInputStream fis = new FileInputStream("contract.docx");
     XWPFDocument doc = new XWPFDocument(fis)) {
     
    // Đọc tất cả các đoạn văn
    for (XWPFParagraph p : doc.getParagraphs()) {
        System.out.println(p.getText());
    }
    
    // Đọc dữ liệu từ bảng
    for (XWPFTable tbl : doc.getTables()) {
        for (XWPFTableRow row : tbl.getRows()) {
            for (XWPFTableCell cell : row.getTableCells()) {
                System.out.print(cell.getText() + "\t");
            }
            System.out.println();
        }
    }
}

Thẻ: Apache POI Java Excel XSSFWorkbook HSSFWorkbook

Đăng vào ngày 1 tháng 11 lúc 04:41