Esta postagem aborda como executar operações de mala direta em documentos do MS Word usando Java. No final deste artigo, você aprenderá como criar modelos de mala direta e executar a mala direta programaticamente.

Sobre mala direta

Mail Merge é uma maneira conveniente de gerar cartas, envelopes, faturas, relatórios e outros tipos de documentos dinamicamente. Usando mala direta, você cria um arquivo de modelo contendo os campos de mesclagem e preenche esses campos usando os dados em uma fonte de dados. Vamos supor que você tenha que enviar uma carta para 20 pessoas diferentes e você só precisa mudar o nome e o endereço dos destinatários em cada cópia. Nesse caso, você pode criar um modelo de mala direta para a carta e gerar 20 cartas preenchendo os campos de nome e endereço dinamicamente.

Java Mail Merge API - Download grátis

Aspose.Words for Java é uma API de processamento de texto bem conhecida que permite criar vários tipos de documentos a partir do zero. A API fornece recursos integrados de mala direta que permitem gerar documentos dinamicamente usando modelos e fontes de dados. Aspose.Words para Java pode ser baixado como JAR ou instalado dentro dos aplicativos baseados em 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>

Fontes de dados para mala direta

Os dados na mala direta podem ser obtidos de qualquer fonte de dados, como JSON, XML, planilha ou um banco de dados.

Criar modelo para mala direta no MS Word

O modelo usado na mala direta pode ser um documento simples do Word (ou seja, DOCX) e não precisa estar em um formato de modelo. O documento de modelo contém os campos de mesclagem que são preenchidos com dados quando a mala direta é executada. A seguir estão as etapas de como preparar um modelo de mala direta usando o MS Word.

  • Crie um novo documento no MS Word.
  • Coloque o cursor onde deseja adicionar um campo de mesclagem.
  • No menu Inserir selecione a opção Campo.
  • Na lista Nomes de campo, selecione MergeField.
  • Insira um nome para o campo de mesclagem em Nome do campo e pressione OK.
  • Salve o documento como DOCX.

A seguir está a captura de tela do documento modelo de amostra.

modelo de palavra de mala direta

Criar modelo de mala direta usando Java

Você também pode gerar o modelo de mala direta programaticamente. A seguir estão os passos para isso.

O exemplo de código a seguir mostra como criar um modelo de mala direta usando Java.

// Criar construtor de documentos
DocumentBuilder builder = new DocumentBuilder();

// Insira um campo de entrada de texto, o nome exclusivo deste campo é "Olá", os outros parâmetros definem
// que tipo de FormField é, o formato do texto, o resultado do campo e o comprimento máximo do texto (0 = sem limite)
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);

// Inserir uma quebra de parágrafo no documento
builder.insertParagraph();

// Inserir corpo do e-mail
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();

// Inserir final de e-mail
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");

// Salvar documento
builder.getDocument().save("document.docx");

Executar mala direta no documento do Word usando Java

Quando o modelo estiver pronto, você poderá preencher os campos de mesclagem com dados. A seguir estão as etapas de execução de mala direta em um modelo do Word.

O exemplo de código a seguir mostra como realizar mala direta em documentos do Word usando Java.

// Inclua o código do nosso modelo
Document doc = new Document();

// Passe o documento para o criador de documentos
DocumentBuilder builder = new DocumentBuilder(doc);

// Criar campos de mesclagem
builder.insertField(" MERGEFIELD CustomerName ");
builder.insertParagraph();
builder.insertField(" MERGEFIELD Item ");
builder.insertParagraph();
builder.insertField(" MERGEFIELD Quantity ");

// Salve o modelo
builder.getDocument().save("MailMerge.TestTemplate.docx");

// Preencha os campos do documento com os dados do usuário
doc.getMailMerge().execute(new String[] { "CustomerName", "Item", "Quantity" },
		new Object[] { "John Doe", "Hawaiian", "2" });

// Salve o documento 
builder.getDocument().save("MailMerge.Simple.docx");

Modelo

mala direta simples em java

Resultado

mala direta simples

Executar mala direta usando fonte de dados XML

No exemplo anterior, realizamos a Mala Direta usando os objetos Java. No entanto, na maioria dos casos, uma fonte de dados é usada para preencher os campos de mesclagem. Para demonstração, vamos verificar como usar uma fonte de dados XML na mala direta. A seguir estão os passos para isso.

  • Carregue a fonte de dados XML usando a classe DataSet.
  • Carregue o modelo de mala direta usando a classe Document.
  • Use a função execute para preencher os campos de mesclagem usando a tabela de dados desejada na fonte de dados.
  • Salve o documento do Word gerado usando o método Document.save(String).

Veja a seguir a fonte de dados XML que está sendo usada neste exemplo.

<?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> 

O exemplo de código a seguir mostra como preencher o modelo de mala direta usando a tabela de dados do cliente na fonte de dados XML fornecida.

// Crie o Dataset e leia o XML
DataSet customersDs = new DataSet();
customersDs.readXml("Customers.xml");

// Abra um documento modelo
Document doc = new Document("TestFile XML.docx");

// Execute a mala direta para preencher o modelo com dados de XML usando DataTable.
// Observe que essa classe também funciona com uma única região repetível (e qualquer região aninhada).
// Para mesclar várias regiões ao mesmo tempo de uma única fonte de dados XML, use a classe XmlMailMergeDataSet.
// por exemplo, doc.getMailMerge().executeWithRegions(new XmlMailMergeDataSet(xmlData));
doc.getMailMerge().execute(customersDs.getTables().get("Customer"));

// Salve o documento de saída
doc.save("generated-document.docx");

Modelo

mala direta com XML

Resultado

xml de mala direta

Mala direta com regiões em Java

Em certos casos, pode ser necessário repetir uma determinada região no documento. Por exemplo, você deseja exibir os pedidos feitos por cada cliente em uma tabela separada. Nesses casos, você pode aproveitar as regiões de mala direta. Para criar uma região, você pode especificar o início e o fim da região. Como resultado, a região será repetida para cada instância dos dados durante a execução da mala direta.

A captura de tela a seguir mostra um modelo no qual a região consiste em uma tabela. Começa com «TableStart:Customers» e termina em «TableEnd:Customers».

modelo de região de mala direta

O exemplo de código a seguir mostra como criar um modelo com regiões e preenchê-lo com os dados.

// Criar documento
Document doc = new Document();
DocumentBuilder builder = new DocumentBuilder(doc);

// O ponto inicial da mala direta com as regiões do conjunto de dados.
builder.insertField(" MERGEFIELD TableStart:Customers");
// Os dados das linhas da coluna "CustomerName" da tabela "Customers" irão
// neste MERGEFIELD.
builder.write("Orders for ");
builder.insertField(" MERGEFIELD CustomerName");
builder.write(":");

// Criar cabeçalhos de coluna
builder.startTable();
builder.insertCell();
builder.write("Item");
builder.insertCell();
builder.write("Quantity");
builder.endRow();

// Temos uma segunda tabela de dados chamada "Pedidos", que tem um número muitos-para-um
// relacionamento com "Clientes"
// selecionando linhas com o mesmo valor 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();

// O ponto final da mala direta com regiões.
builder.insertField(" MERGEFIELD TableEnd:Customers");

// Passe nosso conjunto de dados para realizar mala direta com regiões.
DataSet customersAndOrders = CreateDataSet();
doc.getMailMerge().executeWithRegions(customersAndOrders);

// Salve o resultado
doc.save("MailMerge.ExecuteWithRegions.docx");

Resultado

região de mala direta

Criar regiões de mala direta aninhadas usando Java

Outro cenário popular na mala direta é quando você tem regiões aninhadas. Por exemplo, quando você precisa listar os pedidos e os itens em cada pedido, você pode usar as regiões aninhadas. A imagem a seguir torna a imagem mais clara sobre as regiões aninhadas.

Na imagem acima, temos a tabela Pedidos e a tabela Itens onde cada registro em Itens está vinculado a um registro em Pedidos. Portanto, existe uma relação um-para-muitos entre essas duas tabelas. Nesses casos, o Aspose.Words executa a Mala Direta cuidando dos relacionamentos definidos no DataSet. Por exemplo, se tivermos uma fonte de dados XML, o Aspose.Words usará as informações do esquema ou a estrutura do XML para descobrir os relacionamentos. Assim, você não terá que lidar com isso manualmente e o método Document.getMailMerge().executeWithRegions(DataSet) funcionará para você (como no exemplo anterior).

Aplicar formatação personalizada em campos de mesclagem

A fim de lhe dar mais controle sobre a mala direta, Aspose.Words para Java permite que você personalize os campos de mesclagem durante a execução da mala direta. O método setFieldMergingCallback(IFieldMergingCallback) aceita uma classe que implementa os métodos fieldMerging(FieldMergingArgs) e imageFieldMerging(ImageFieldMergingArgs) para controle personalizado sobre o processo de mala direta. O evento fieldMerging(FieldMergingArgs) ocorre quando um campo de mesclagem é encontrado durante a execução da mala direta.

A seguir está o exemplo de código completo de como personalizar a operação de mala direta e aplicar formatação às células.

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");

        // Adicione um manipulador para o evento MergeField.
        doc.getMailMerge().setFieldMergingCallback(new HandleMergeFieldAlternatingRows());

        // Execute mala direta com regiões.
        DataTable dataTable = getSuppliersDataTable();
        doc.getMailMerge().executeWithRegions(dataTable);

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

    /**
     * Retorna verdadeiro se o valor for ímpar; false se o valor for par.
     */
    public static boolean isOdd(int value) throws Exception {
        return (value % 2 != 0);
    }

    /**
     * Crie DataTable e preencha-o com dados. Na vida real este DataTable
     * devem ser preenchidos a partir de um banco de dados.
     */
    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");
    }

    /**
     * Um método auxiliar que cria um ResultSet desconectado Java vazio com
     * as colunas especificadas.
     */
    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;
    }

    /**
     * Um método auxiliar que adiciona uma nova linha com os valores especificados a um
     * ResultSet desconectado.
     */
    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();

        // Essa "dança" é necessária para adicionar linhas ao final do conjunto de resultados corretamente.
        // Se eu fizer outra coisa, as linhas serão adicionadas na frente ou no resultado
        // set lança uma exceção sobre uma linha excluída durante a mala direta.
        resultSet.moveToCurrentRow();
        resultSet.last();
    }
}

class HandleMergeFieldAlternatingRows implements IFieldMergingCallback {
    /**
     * Chamado para cada campo de mesclagem encontrado no documento. Nós podemos tanto
     * retornar alguns dados para o mecanismo de mala direta ou fazer outra coisa com o
     * documento. Neste caso, modificamos a formatação da célula.
     */
    public void fieldMerging(FieldMergingArgs e) throws Exception {
        if (mBuilder == null)
            mBuilder = new DocumentBuilder(e.getDocument());

        // Desta forma, pegamos o início de uma nova linha.
        if (e.getFieldName().equals("CompanyName")) {
            // Selecione a cor dependendo se o número da linha é par ou ímpar.
            Color rowColor;
            if (ApplyCustomFormattingDuringMailMerge.isOdd(mRowIdx))
                rowColor = new Color(213, 227, 235);
            else
                rowColor = new Color(242, 242, 242);

            // Não há como definir as propriedades da célula para a linha inteira no momento,
            // então temos que iterar sobre todas as células na linha.
            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 {
        // Fazer nada.
    }

    private DocumentBuilder mBuilder;
    private int mRowIdx;
}

Conclusão

Mail Merge fornece uma ampla gama de recursos para gerar documentos do MS Word dinamicamente. Você pode gerar relatórios simples e complexos com base nos dados em bancos de dados ou outras fontes de dados. Neste artigo, você viu como implementar os recursos de mala direta programaticamente usando Java. Você pode aprender mais sobre a API Java Mail Merge usando a documentação.

Veja também