Bài đăng này trình bày cách thực hiện các thao tác Trộn thư trong tài liệu MS Word bằng Java. Đến cuối bài viết này, bạn sẽ tìm hiểu cách tạo các mẫu Trộn Thư và thực hiện Trộn Thư theo lập trình.

Giới thiệu về Trộn thư

Mail Merge là một cách thuận tiện để tạo thư, phong bì, hóa đơn, báo cáo và các loại tài liệu khác một cách linh hoạt. Sử dụng Trộn Thư, bạn tạo một tệp mẫu có chứa các trường phối và sau đó điền vào các trường đó bằng cách sử dụng dữ liệu trong nguồn dữ liệu. Giả sử bạn phải gửi một lá thư cho 20 người khác nhau và bạn chỉ cần thay đổi tên và địa chỉ của người nhận trên mỗi bản sao. Trong trường hợp này, bạn có thể tạo một mẫu Trộn thư cho thư và sau đó tạo 20 chữ cái bằng cách điền động các trường tên và địa chỉ.

API trộn thư Java - Tải xuống miễn phí

Aspose.Words for Java là API xử lý văn bản nổi tiếng cho phép bạn tạo nhiều loại tài liệu khác nhau từ đầu. API cung cấp các tính năng Phối thư tích hợp sẵn cho phép bạn tạo động các tài liệu bằng cách sử dụng các mẫu và nguồn dữ liệu. Có thể tải xuống Aspose.Words for Java dưới dạng JAR hoặc cài đặt trong các ứng dụng dựa trên Maven.

<repository>
    <id>AsposeJavaAPI</id>
    <name>Aspose Java API</name>
    <url>https://repository.aspose.com/repo/</url>
</repository>
<dependency>
    <groupId>com.aspose</groupId>
    <artifactId>aspose-words</artifactId>
    <version>20.11</version>
    <classifier>jdk17</classifier>
</dependency>

Nguồn dữ liệu để trộn thư

Dữ liệu trong Trộn thư có thể được tìm nạp từ bất kỳ nguồn dữ liệu nào, chẳng hạn như JSON, XML, bảng tính hoặc cơ sở dữ liệu.

Tạo mẫu trộn thư trong MS Word

Mẫu đang được sử dụng trong Trộn thư có thể là một tài liệu Word đơn giản (tức là DOCX) và nó không cần phải ở định dạng mẫu. Tài liệu mẫu chứa các trường hợp nhất được phổ biến dữ liệu khi Hợp nhất Thư được thực thi. Sau đây là các bước chuẩn bị mẫu Trộn thư bằng MS Word.

  • Tạo một tài liệu mới trong MS Word.
  • Đặt con trỏ ở nơi bạn muốn thêm trường hợp nhất.
  • Từ menu Chèn, chọn tùy chọn Trường.
  • Từ danh sách Tên trường, chọn Hợp nhất Trường.
  • Nhập tên cho trường hợp nhất trong Tên trường và nhấn OK.
  • Lưu tài liệu dưới dạng DOCX.

Sau đây là ảnh chụp màn hình của tài liệu mẫu mẫu.

mẫu từ trộn thư

Tạo mẫu trộn thư bằng Java

Bạn cũng có thể tạo mẫu Trộn Thư theo chương trình. Sau đây là các bước cho nó.

Mẫu mã sau đây cho biết cách tạo mẫu Trộn thư bằng Java.

// Tạo trình tạo tài liệu
DocumentBuilder builder = new DocumentBuilder();

// Chèn một trường nhập văn bản, tên duy nhất của trường này là "Xin chào", các tham số khác xác định
// đó là loại FormField nào, định dạng của văn bản, kết quả trường và độ dài văn bản tối đa (0 = không giới hạn)
builder.insertTextInput("TextInput", TextFormFieldType.REGULAR, "", "Hello", 0);
builder.insertField("MERGEFIELD CustomerFirstName \\* MERGEFORMAT");

builder.insertTextInput("TextInput1", TextFormFieldType.REGULAR, "", " ", 0);
builder.insertField("MERGEFIELD CustomerLastName \\* MERGEFORMAT");

builder.insertTextInput("TextInput1", TextFormFieldType.REGULAR, "", " , ", 0);

// Chèn ngắt đoạn vào tài liệu
builder.insertParagraph();

// Chèn nội dung thư
builder.insertTextInput("TextInput", TextFormFieldType.REGULAR, "", "Thanks for purchasing our ", 0);
builder.insertField("MERGEFIELD ProductName \\* MERGEFORMAT");

builder.insertTextInput("TextInput", TextFormFieldType.REGULAR, "", ", please download your Invoice at ",
	0);
builder.insertField("MERGEFIELD InvoiceURL \\* MERGEFORMAT");

builder.insertTextInput("TextInput", TextFormFieldType.REGULAR, "",
	". If you have any questions please call ", 0);
builder.insertField("MERGEFIELD Supportphone \\* MERGEFORMAT");

builder.insertTextInput("TextInput", TextFormFieldType.REGULAR, "", ", or email us at ", 0);
builder.insertField("MERGEFIELD SupportEmail \\* MERGEFORMAT");

builder.insertTextInput("TextInput", TextFormFieldType.REGULAR, "", ".", 0);

builder.insertParagraph();

// Chèn kết thúc thư
builder.insertTextInput("TextInput", TextFormFieldType.REGULAR, "", "Best regards,", 0);
builder.insertBreak(BreakType.LINE_BREAK);
builder.insertField("MERGEFIELD EmployeeFullname \\* MERGEFORMAT");

builder.insertTextInput("TextInput1", TextFormFieldType.REGULAR, "", " ", 0);
builder.insertField("MERGEFIELD EmployeeDepartment \\* MERGEFORMAT");

// Lưu tài liệu
builder.getDocument().save("document.docx");

Thực hiện trộn thư trong tài liệu Word bằng Java

Khi mẫu đã sẵn sàng, bạn có thể điền dữ liệu vào các trường hợp nhất. Sau đây là các bước thực hiện Trộn thư trên mẫu Word.

Mẫu mã sau đây cho biết cách thực hiện trộn thư trong tài liệu Word bằng Java.

// Bao gồm mã cho mẫu của chúng tôi
Document doc = new Document();

// Truyền tài liệu cho trình tạo tài liệu
DocumentBuilder builder = new DocumentBuilder(doc);

// Tạo trường hợp nhất
builder.insertField(" MERGEFIELD CustomerName ");
builder.insertParagraph();
builder.insertField(" MERGEFIELD Item ");
builder.insertParagraph();
builder.insertField(" MERGEFIELD Quantity ");

// Lưu mẫu
builder.getDocument().save("MailMerge.TestTemplate.docx");

// Điền vào các trường trong tài liệu với dữ liệu người dùng
doc.getMailMerge().execute(new String[] { "CustomerName", "Item", "Quantity" },
		new Object[] { "John Doe", "Hawaiian", "2" });

// Lưu tài liệu 
builder.getDocument().save("MailMerge.Simple.docx");

Mẫu

trộn thư đơn giản trong java

đầu ra

trộn thư đơn giản

Thực hiện trộn thư bằng cách sử dụng nguồn dữ liệu XML

Trong ví dụ trước, chúng ta đã thực hiện trộn thư bằng các đối tượng Java. Tuy nhiên, trong hầu hết các trường hợp, một nguồn dữ liệu được sử dụng để điền vào các trường hợp nhất. Để trình diễn, hãy xem cách sử dụng nguồn dữ liệu XML trong Trộn Thư. Sau đây là các bước cho nó.

  • Tải nguồn dữ liệu XML bằng lớp DataSet.
  • Tải mẫu Trộn thư bằng lớp Document.
  • Sử dụng hàm thực thi để điền vào các trường hợp nhất bằng cách sử dụng bảng dữ liệu mong muốn trong nguồn dữ liệu.
  • Lưu tài liệu Word đã tạo bằng phương pháp Document.save(String).

Sau đây là nguồn dữ liệu XML đang được sử dụng trong ví dụ này.

<?xml version="1.0" encoding="utf-8"?>
<customers>
	 <customer Name="John Ben Jan" ID="1" Domain="History" City="Boston"/>
 	<customer Name="Lisa Lane" ID="2" Domain="Chemistry" City="LA"/>
	 <customer Name="Dagomir Zits" ID="3" Domain="Heraldry" City="Milwaukee"/>
 	<customer Name="Sara Careira Santy" ID="4" Domain="IT" City="Miami"/>
</customers> 

Mẫu mã sau đây cho biết cách điền mẫu Trộn thư bằng cách sử dụng bảng dữ liệu Khách hàng trong nguồn dữ liệu XML được cung cấp.

// Tạo Bộ dữ liệu và đọc XML
DataSet customersDs = new DataSet();
customersDs.readXml("Customers.xml");

// Mở tài liệu mẫu
Document doc = new Document("TestFile XML.docx");

// Thực hiện trộn thư để điền vào mẫu bằng dữ liệu từ XML bằng DataTable.
// Lưu ý rằng lớp này cũng hoạt động với một vùng lặp lại duy nhất (và bất kỳ vùng lồng nhau nào).
// Để hợp nhất nhiều vùng cùng lúc từ một nguồn dữ liệu XML duy nhất, hãy sử dụng lớp XmlMailMergeDataSet.
// ví dụ doc.getMailMerge().executeWithRegions(new XmlMailMergeDataSet(xmlData));
doc.getMailMerge().execute(customersDs.getTables().get("Customer"));

// Lưu tài liệu đầu ra
doc.save("generated-document.docx");

Mẫu

trộn thư với XML

đầu ra

trộn thư xml

Hợp nhất thư với các vùng trong Java

Trong một số trường hợp nhất định, bạn có thể cần lặp lại một vùng cụ thể trong tài liệu. Ví dụ: bạn muốn hiển thị các đơn đặt hàng của từng khách hàng trong một bảng riêng biệt. Trong những trường hợp như vậy, bạn có thể tận dụng các vùng trộn thư. Để tạo một vùng, bạn có thể chỉ định điểm đầu và điểm cuối của vùng. Do đó, vùng sẽ được lặp lại cho từng phiên bản dữ liệu trong quá trình thực hiện Trộn thư.

Ảnh chụp màn hình sau đây hiển thị một mẫu trong đó vùng bao gồm một bảng. Nó bắt đầu với «TableStart:Customers» và kết thúc tại «TableEnd:Customers».

mẫu khu vực trộn thư

Mẫu mã sau đây cho biết cách tạo mẫu có vùng và điền dữ liệu vào đó.

// Tạo tài liệu
Document doc = new Document();
DocumentBuilder builder = new DocumentBuilder(doc);

// Điểm bắt đầu hợp nhất thư với các vùng của tập dữ liệu.
builder.insertField(" MERGEFIELD TableStart:Customers");
// Dữ liệu từ các hàng của cột "CustomerName" của bảng "Customers" sẽ chuyển
// trong MERGEFIELD này.
builder.write("Orders for ");
builder.insertField(" MERGEFIELD CustomerName");
builder.write(":");

// Tạo tiêu đề cột
builder.startTable();
builder.insertCell();
builder.write("Item");
builder.insertCell();
builder.write("Quantity");
builder.endRow();

// Chúng tôi có một bảng dữ liệu thứ hai được gọi là "Đơn hàng", có nhiều đối một
// mối quan hệ với "Khách hàng"
// chọn các hàng có cùng giá trị CustomerID.
builder.insertCell();
builder.insertField(" MERGEFIELD TableStart:Orders");
builder.insertField(" MERGEFIELD ItemName");
builder.insertCell();
builder.insertField(" MERGEFIELD Quantity");
builder.insertField(" MERGEFIELD TableEnd:Orders");
builder.endTable();

// Điểm cuối của quá trình trộn thư theo vùng.
builder.insertField(" MERGEFIELD TableEnd:Customers");

// Vượt qua tập dữ liệu của chúng tôi để thực hiện hợp nhất thư với các vùng.
DataSet customersAndOrders = CreateDataSet();
doc.getMailMerge().executeWithRegions(customersAndOrders);

// Lưu kết quả
doc.save("MailMerge.ExecuteWithRegions.docx");

đầu ra

khu vực trộn thư

Tạo các vùng trộn thư lồng nhau bằng Java

Một tình huống phổ biến khác trong Trộn thư là khi bạn có các vùng lồng nhau. Ví dụ: khi bạn phải liệt kê các đơn hàng và các mặt hàng trong mỗi đơn hàng thì bạn có thể sử dụng các vùng lồng nhau. Hình ảnh sau đây làm cho hình ảnh rõ ràng hơn về các vùng lồng nhau.

Trong hình trên, chúng ta có bảng Đơn hàng và bảng Mục trong đó mỗi bản ghi trong Mục được liên kết với một bản ghi trong Đơn hàng. Do đó, tồn tại mối quan hệ một-nhiều giữa hai bảng này. Trong những trường hợp như vậy, Aspose.Words thực thi Trộn thư để đảm bảo các mối quan hệ được xác định trong Tập dữ liệu. Chẳng hạn, nếu chúng ta có nguồn dữ liệu XML thì Aspose.Words sẽ sử dụng thông tin lược đồ hoặc cấu trúc của XML để tìm ra các mối quan hệ. Do đó, bạn sẽ không phải tự mình xử lý thủ công và phương thức Document.getMailMerge().executeWithRegions(DataSet) sẽ giúp bạn (như ví dụ trước).

Áp dụng định dạng tùy chỉnh trên các trường hợp nhất

Để cung cấp cho bạn nhiều quyền kiểm soát hơn đối với Trộn Thư, Aspose.Words for Java cho phép bạn tùy chỉnh các trường phối trong khi thực hiện Trộn Thư. Phương thức setFieldMergingCallback(IFieldMergingCallback) chấp nhận một lớp triển khai các phương thức fieldMerging(FieldMergingArgs)imageFieldMerging(ImageFieldMergingArgs) để kiểm soát tùy chỉnh quy trình Trộn thư. Sự kiện fieldMerging(FieldMergingArgs) xảy ra khi gặp trường hợp nhất trong quá trình thực thi Trộn thư.

Sau đây là mẫu mã hoàn chỉnh về cách tùy chỉnh thao tác Phối Thư và áp dụng định dạng cho các ô.

public class ApplyCustomFormattingDuringMailMerge {

    private static final String dataDir = Utils.getSharedDataDir(ApplyCustomFormattingDuringMailMerge.class) + "MailMerge/";

    public static void main(String[] args) throws Exception {
        Document doc = new Document(dataDir + "MailMerge.AlternatingRows.doc");

        // Thêm trình xử lý cho sự kiện MergeField.
        doc.getMailMerge().setFieldMergingCallback(new HandleMergeFieldAlternatingRows());

        // Thực hiện trộn thư với các vùng.
        DataTable dataTable = getSuppliersDataTable();
        doc.getMailMerge().executeWithRegions(dataTable);

        doc.save(dataDir + "MailMerge.AlternatingRows Out.doc");
    }

    /**
     * Trả về true nếu giá trị là số lẻ; sai nếu giá trị là số chẵn.
     */
    public static boolean isOdd(int value) throws Exception {
        return (value % 2 != 0);
    }

    /**
     * Tạo DataTable và điền dữ liệu vào. Trong cuộc sống thực, DataTable này
     * nên được điền từ cơ sở dữ liệu.
     */
    private static DataTable getSuppliersDataTable() throws Exception {
        java.sql.ResultSet resultSet = createCachedRowSet(new String[]{"CompanyName", "ContactName"});

       for (int i = 0; i < 10; i++)
            addRow(resultSet, new String[]{"Company " + Integer.toString(i), "Contact " + Integer.toString(i)});

        return new DataTable(resultSet, "Suppliers");
    }

    /**
     * Một phương thức trợ giúp tạo ra một Kết quả ngắt kết nối Java trống với
     * các cột được chỉ định.
     */
    private static ResultSet createCachedRowSet(String[] columnNames) throws Exception {
        RowSetMetaDataImpl metaData = new RowSetMetaDataImpl();
        metaData.setColumnCount(columnNames.length);
       for (int i = 0; i < columnNames.length; i++) {
            metaData.setColumnName(i + 1, columnNames[i]);
            metaData.setColumnType(i + 1, java.sql.Types.VARCHAR);
        }

        CachedRowSet rowSet = RowSetProvider.newFactory().createCachedRowSet();
        ;
        rowSet.setMetaData(metaData);

        return rowSet;
    }

    /**
     * Một phương thức trợ giúp thêm một hàng mới với các giá trị được chỉ định vào một
     * Bộ kết quả bị ngắt kết nối.
     */
    private static void addRow(ResultSet resultSet, String[] values) throws Exception {
        resultSet.moveToInsertRow();

       for (int i = 0; i < values.length; i++)
            resultSet.updateString(i + 1, values[i]);

        resultSet.insertRow();

        // "Điệu nhảy" này là cần thiết để thêm các hàng vào cuối tập kết quả đúng cách.
        // Nếu tôi làm điều gì đó khác thì các hàng sẽ được thêm vào phía trước hoặc kết quả
        // set đưa ra một ngoại lệ về một hàng đã bị xóa trong quá trình trộn thư.
        resultSet.moveToCurrentRow();
        resultSet.last();
    }
}

class HandleMergeFieldAlternatingRows implements IFieldMergingCallback {
    /**
     * Được gọi cho mọi trường hợp nhất gặp phải trong tài liệu. chúng ta có thể
     * trả lại một số dữ liệu cho công cụ trộn thư hoặc làm điều gì đó khác với
     * tài liệu. Trong trường hợp này, chúng tôi sửa đổi định dạng ô.
     */
    public void fieldMerging(FieldMergingArgs e) throws Exception {
        if (mBuilder == null)
            mBuilder = new DocumentBuilder(e.getDocument());

        // Bằng cách này, chúng tôi bắt đầu một hàng mới.
        if (e.getFieldName().equals("CompanyName")) {
            // Chọn màu tùy thuộc vào số hàng là chẵn hay lẻ.
            Color rowColor;
            if (ApplyCustomFormattingDuringMailMerge.isOdd(mRowIdx))
                rowColor = new Color(213, 227, 235);
            else
                rowColor = new Color(242, 242, 242);

            // Hiện tại không có cách nào để đặt thuộc tính ô cho toàn bộ hàng,
            // vì vậy chúng ta phải lặp lại tất cả các ô trong hàng.
           for (int colIdx = 0; colIdx < 4; colIdx++) {
                mBuilder.moveToCell(0, mRowIdx, colIdx, 0);
                mBuilder.getCellFormat().getShading().setBackgroundPatternColor(rowColor);
            }

            mRowIdx++;
        }
    }

    public void imageFieldMerging(ImageFieldMergingArgs args) throws Exception {
        // Không làm gì cả.
    }

    private DocumentBuilder mBuilder;
    private int mRowIdx;
}

Sự kết luận

Trộn thư cung cấp cho bạn nhiều tính năng để tạo các tài liệu MS Word một cách linh hoạt. Bạn có thể tạo các báo cáo đơn giản cũng như phức tạp dựa trên dữ liệu trong cơ sở dữ liệu hoặc các nguồn dữ liệu khác. Trong bài viết này, bạn đã biết cách triển khai các tính năng Trộn thư theo chương trình bằng cách sử dụng Java. Bạn có thể tìm hiểu thêm về Java Mail Merge API bằng cách sử dụng tài liệu.

Xem thêm