import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
public class PDFTableGenerator {
    // Generates document from Table object
    public void generatePDF(Table table) throws IOException {
        PDDocument doc = null;
        try {
            doc = new PDDocument();
            drawTable(doc, table);
            doc.save("D:\\file\\sample.pdf");
        } finally {
            if (doc != null) {
                doc.close();
            }
        }
    }
    // Configures basic setup for the table and draws it page by page
    public void drawTable(PDDocument doc, Table table) throws IOException {
        // Calculate pagination
        Integer rowsPerPage = new Double(Math.floor(table.getHeight() / table.getRowHeight())).intValue() - 1; // subtract
        Integer numberOfPages = new Double(Math.ceil(table.getNumberOfRows().floatValue() / rowsPerPage)).intValue();
        // Generate each page, get the content and draw it
        for (int pageCount = 0; pageCount < numberOfPages; pageCount++) {
            PDPage page = generatePage(doc, table);
            PDPageContentStream contentStream = generateContentStream(doc, page, table);
            if (pageCount == 0) {
                //寫標題
                contentStream.beginText();
                // 文字位置
                contentStream.setFont(PDType0Font.load(doc, new File("C:\\Windows\\Fonts\\simfang.TTF")), 18);
                contentStream.newLineAtOffset(table.getWidth() / 2 + 20, table.getHeight() + table.getMargin() + 40);
                // 插入文本
                contentStream.showText(table.getTitle());
                contentStream.endText();
                //導出時間
                contentStream.beginText();
                contentStream.setFont(PDType0Font.load(doc, new File("C:\\Windows\\Fonts\\simfang.TTF")), 8);
                contentStream.newLineAtOffset(table.getWidth() - 20, table.getHeight() + table.getMargin() + 10);
                // 插入文本
                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
                contentStream.showText("批單導出日期:"+format.format(new Date()));
                contentStream.endText();
                contentStream.setFont(PDType0Font.load(doc, new File("C:\\Windows\\Fonts\\simfang.TTF")), 10);
                String[][] currentPageContent = getContentForCurrentPage(table, rowsPerPage, pageCount);
                drawCurrentPage(table, currentPageContent, contentStream);
            } else {
                String[][] currentPageContent = getContentForCurrentPage(table, rowsPerPage, pageCount);
                drawCurrentPage(table, currentPageContent, contentStream);
            }
        }
    }
    // Draws current page table grid and border lines and content
    private void drawCurrentPage(Table table, String[][] currentPageContent, PDPageContentStream contentStream)
            throws IOException {
        float tableTopY = table.isLandscape() ? table.getPageSize().getWidth() - table.getMargin() : table.getPageSize().getHeight() - table.getMargin();
        // Draws grid and borders
        drawTableGrid(table, currentPageContent, contentStream, tableTopY);
        // Position cursor to start drawing content
        float nextTextX = table.getMargin() + table.getCellMargin();
        // Calculate center alignment for text in cell considering font height
        float nextTextY = tableTopY - (table.getRowHeight() / 2)
                - ((table.getTextFont().getFontDescriptor().getFontBoundingBox().getHeight() / 1000 * table.getFontSize()) / 4);
        // Write column headers
        writeContentLine(table.getColumnsNamesAsArray(), contentStream, nextTextX, nextTextY, table);
        nextTextY -= table.getRowHeight();
        nextTextX = table.getMargin() + table.getCellMargin();
        // Write content
        for (int i = 0; i < currentPageContent.length; i++) {
            writeContentLine(currentPageContent[i], contentStream, nextTextX, nextTextY, table);
            nextTextY -= table.getRowHeight();
            nextTextX = table.getMargin() + table.getCellMargin();
        }
        contentStream.close();
    }
    // Writes the content for one line
    private void writeContentLine(String[] lineContent, PDPageContentStream contentStream, float nextTextX, float nextTextY,
                                  Table table) throws IOException {
        Integer numberOfColumns = table.getNumberOfColumns();
        for (int i = 0; i < table.getNumberOfColumns(); i++) {
            String text = lineContent[i];
            contentStream.beginText();
            contentStream.moveTextPositionByAmount(nextTextX, nextTextY);
            contentStream.drawString(text != null ? text : "");
            contentStream.endText();
            nextTextX += table.getColumns().get(i).getWidth();
        }
    }
    private void drawTableGrid(Table table, String[][] currentPageContent, PDPageContentStream contentStream, float tableTopY)
            throws IOException {
        // Draw row lines
        float nextY = tableTopY;
        for (int i = 0; i <= currentPageContent.length + 1; i++) {
            contentStream.drawLine(table.getMargin(), nextY, table.getMargin() + table.getWidth(), nextY);
            nextY -= table.getRowHeight();
        }
        // Draw column lines
        final float tableYLength = table.getRowHeight() + (table.getRowHeight() * currentPageContent.length);
        final float tableBottomY = tableTopY - tableYLength;
        float nextX = table.getMargin();
        for (int i = 0; i < table.getNumberOfColumns(); i++) {
            contentStream.drawLine(nextX, tableTopY, nextX, tableBottomY);
            nextX += table.getColumns().get(i).getWidth();
        }
        contentStream.drawLine(nextX, tableTopY, nextX, tableBottomY);
    }
    private String[][] getContentForCurrentPage(Table table, Integer rowsPerPage, int pageCount) {
        int startRange = pageCount * rowsPerPage;
        int endRange = (pageCount * rowsPerPage) + rowsPerPage;
        if (endRange > table.getNumberOfRows()) {
            endRange = table.getNumberOfRows();
        }
        return Arrays.copyOfRange(table.getContent(), startRange, endRange);
    }
    private PDPage generatePage(PDDocument doc, Table table) {
        PDPage page = new PDPage();
        page.setMediaBox(table.getPageSize());
        page.setRotation(table.isLandscape() ? 90 : 0);
        doc.addPage(page);
        return page;
    }
    private PDPageContentStream generateContentStream(PDDocument doc, PDPage page, Table table) throws IOException {
        PDPageContentStream contentStream = new PDPageContentStream(doc, page, false, false);
        // User transformation matrix to change the reference when drawing.
        // This is necessary for the landscape position to draw correctly
        if (table.isLandscape()) {
            contentStream.concatenate2CTM(0, 1, -1, 0, table.getPageSize().getWidth(), 0);
        }
        contentStream.setFont(PDType0Font.load(doc, new File("C:\\Windows\\Fonts\\simfang.TTF")), 10);
        return contentStream;
    }
} 
          
         
         import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class PDFSample {
    // Page configuration
    private static final PDRectangle PAGE_SIZE = PDRectangle.A4;
    private static final float MARGIN = 90;
    private static final boolean IS_LANDSCAPE = true;
    // Font configuration
    private static final PDFont TEXT_FONT = PDType1Font.HELVETICA;
    private static final float FONT_SIZE = 10;
    // Table configuration
    private static final float ROW_HEIGHT = 15;
    private static final float CELL_MARGIN = 2;
    public static void main(String[] args) throws IOException {
        new PDFTableGenerator().generatePDF(createContent());
    }
    private static Table createContent() {
        String title="支付憑證號:"+"00000000000000";
        // Total size of columns must not be greater than table width.
        List<Column> columns = new ArrayList<Column>();
        columns.add(new Column("李四",80));
        columns.add(new Column("LastName", 90));
        columns.add(new Column("Email", 80));
        columns.add(new Column("ZipCode", 83));
        columns.add(new Column("MailOptIn", 80));
        columns.add(new Column("Code", 80));
        columns.add(new Column("Branch", 89));
        String[][] content = {
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
                { "張三", "LastName", "fakemail@mock.com", "12345", "yes", "XH4234FSD", "4334" },
    };
        float tableHeight = IS_LANDSCAPE ? PAGE_SIZE.getWidth() - (2 * MARGIN) : PAGE_SIZE.getHeight() - (2 * MARGIN);
        Table table = new TableBuilder()
                .setTitle(title)
            .setCellMargin(CELL_MARGIN)
            .setColumns(columns)
            .setContent(content)
            .setHeight(tableHeight)
            .setNumberOfRows(content.length)
            .setRowHeight(ROW_HEIGHT)
            .setMargin(MARGIN)
            .setPageSize(PAGE_SIZE)
            .setLandscape(IS_LANDSCAPE)
            .setTextFont(TEXT_FONT)
            .setFontSize(FONT_SIZE)
            .build();
        return table;
    }
}