用java替换word文档模板中的变量

时间:2014-03-24 16:49:44

标签: java apache-poi velocity

我想加载模板word文档以添加内容并另存为新文档。我正在研究.doc文件。

经过长时间的研究,我只找到了docx的解决方案:

http://www.smartjava.org/content/create-complex-word-docx-documents-programatically-docx4j

http://www.sambhashanam.com/mail-merge-in-java-for-microsoft-word-document-part-i/

所以我想用这个格式替换任何变量:$VAR。 我可以用velocity或Apache-poi来做,它的最佳解决方案是什么。 任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:27)

是的,您可以使用Apache-POI来完成。您的变量名称必须是唯一的。请参阅以下代码

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.usermodel.CharacterRun;
import org.apache.poi.hwpf.usermodel.Paragraph;
import org.apache.poi.hwpf.usermodel.Range;
import org.apache.poi.hwpf.usermodel.Section;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;

public class HWPFTest {
    public static void main(String[] args){
        String filePath = "F:\\Sample.doc";
        POIFSFileSystem fs = null;        
        try {            
            fs = new POIFSFileSystem(new FileInputStream(filePath));            
            HWPFDocument doc = new HWPFDocument(fs);
            doc = replaceText(doc, "$VAR", "MyValue1");
            saveWord(filePath, doc);
        }
        catch(FileNotFoundException e){
            e.printStackTrace();
        }
        catch(IOException e){
            e.printStackTrace();
        }
    }

    private static HWPFDocument replaceText(HWPFDocument doc, String findText, String replaceText){
        Range r1 = doc.getRange(); 

        for (int i = 0; i < r1.numSections(); ++i ) { 
            Section s = r1.getSection(i); 
            for (int x = 0; x < s.numParagraphs(); x++) { 
                Paragraph p = s.getParagraph(x); 
                for (int z = 0; z < p.numCharacterRuns(); z++) { 
                    CharacterRun run = p.getCharacterRun(z); 
                    String text = run.text();
                    if(text.contains(findText)) {
                        run.replaceText(findText, replaceText);
                    } 
                }
            }
        } 
        return doc;
    }

    private static void saveWord(String filePath, HWPFDocument doc) throws FileNotFoundException, IOException{
        FileOutputStream out = null;
        try{
            out = new FileOutputStream(filePath);
            doc.write(out);
        }
        finally{
            out.close();
        }
    }
}

答案 1 :(得分:2)

最近,我不得不使用 .docx 文档解决相同的问题。尝试上述方法会导致以下错误(如post中所述):

org.apache.poi.poifs.filesystem.OfficeXmlFileException:提供的数据似乎在Office 2007+ XML中。您正在调用与OLE2 Office文档有关的POI部分。您需要调用POI的其他部分来处理此数据(例如XSSF而不是HSSF)

最后,我不得不按如下方式更改代码(在我的情况下,.docx文件位于资源文件夹中):

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.apache.poi.xwpf.usermodel.XWPFDocument;

public class XWPFTest {

    public static void main(String[] args) throws URISyntaxException, IOException {
        String resourcePath = "template.docx";
        Path templatePath = Paths.get(XWPFTest.class.getClassLoader().getResource(resourcePath).toURI());
        XWPFDocument doc =  new XWPFDocument(Files.newInputStream(templatePath));
        doc = replaceTextFor(doc, "UNIQUE_VAR", "MyValue1");
        saveWord("C:\\document.docx", doc);
    }

    private static XWPFDocument replaceTextFor(XWPFDocument doc, String findText, String replaceText){
        doc.getParagraphs().forEach(p ->{
            p.getRuns().forEach(run -> {
                String text = run.text();
                if(text.contains(findText)) {
                    run.setText(text.replace(findText, replaceText), 0);
                } 
            });
        });

        return doc;
    }

    private static void saveWord(String filePath, XWPFDocument doc) throws FileNotFoundException, IOException{
        FileOutputStream out = null;
        try{
            out = new FileOutputStream(filePath);
            doc.write(out);
        }
        catch(Exception e) {
            e.printStackTrace();
        }
        finally{
            out.close();
        }
    }

}

P.S。我必须删除$,因为在.docx中管理的是单独运行,因此我不得不选择唯一的var名称的方法。 我需要以下Apache POI依赖项:

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.17</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.17</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-scratchpad</artifactId>
    <version>3.17</version>
</dependency>

答案 2 :(得分:-5)

维克兰特,

上面给出了代码片段,为了工作,我们需要上面提到的jar。与该Jar一起使用/下载poi-3.5-FINAL.jar。

希望这会回答你的问题。