I have a document template where some fields are static and others are dynamic. I need to replace some data (name, last name, salary) and generate the new file. What library do you recommend to do this? Is POI appropriate? I am working with Spring, Java EE6 and Oracle.
问题:
回答1:
You can give Apache POI a try but the HWPF and XWPF part of POI which are required to manipulate word files are really complicated to use - you need to have at least a good understanding how a word file is structured!
Solution using iText and PDF
I did something similar with PDF (this might be an option for you)
1) You can use LibreOffice to create fields in the document (like in Acrobat Pro)
- Create an .odt file and style it
- or convert your template to it using MS Word or LibreOffice Writer
- Then go to View -> Toolsbars -> Form Design and set "Design Mode on/off"
- Now you can add fields to your file (double clicking on it will open properties of the fields)
- When you are finished: "File -> Export as PDF"
2) Now you can use iText to fill in the created fields
The following is just example code:
public byte[] getDocumentAsByteArray(Object dataBean, String pdfTemplateName) throws KkmsException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PdfStamper stamp = null;
InputStream templateInputStream = null;
Locale local = new Locale(language);
try {
templateInputStream = // get the file input stream of the pdf
PdfReader reader = new PdfReader(templateInputStream);
// Create a stamper that will copy the document to a new file
stamp = new PdfStamper(reader, outputStream);
AcroFields form = stamp.getAcroFields();
// form fields are normal text in the end
stamp.setFormFlattening(true);
Map<String, AcroFields.Item> map = (Map<String, AcroFields.Item>)form.getFields();
if (map != null) {
if (map.size() == 0) {
logger.debug("There are no fields in this PDF layout");
}
for (Entry<String, AcroFields.Item> e : map.entrySet()) {
logger.debug("PDF fieldname = " + e.getKey());
// at the moment we only handle text fields
if (AcroFields.FIELD_TYPE_TEXT == form.getFieldType(e.getKey())) {
fillForm(dataBean, form, e.getKey(), local);
} else {
logger.warn("Field type is not supported: "+form.getFieldType(e.getKey()));
}
}
}
stamp.close();
} catch (Exception e) {
logger.warn("Failed to create PDF document", e);
throw new KkmsException("Failed to create PDF document: "+e.getMessage());
} finally {
if (templateInputStream != null) {
try {
templateInputStream.close();
} catch (IOException e) {
throw new KkmsException("Failed to close InputStream of PDF document", e);
}
}
}
return outputStream.toByteArray();
}
In the end you get a PDF -> hope this helps you at least a little bit!
Another quick and dirty solution
Could be to use the power of odt or docx -> convert your doc to docx or odt -> its just a zip file -> so unzip it -> you will see a content.xml file in the root of the zip -> there is all the document content in there Now you could add some magic tags (e.g. $$$) here which can later be replaced by your program
<text:p text:style-name="P3">SAP Customer Number:</text:p>
<text:p text:style-name="P3">SAP Customer Number: $$$sapCustomerNumber$$$</text:p>
Now create a program which unzips the odt/docx file -> replaces the tags -> zips the file again
回答2:
These slides, from a presentation I gave at OSDC 2012, outline some major approaches.
These days I'd likely add "generate what you want as XHTML, then export that to docx". Since we introduced docx4j-ImportXHTML with support for converting CSS @class values to Word styles, we've seen this approach more and more.