我需要打开一个文件.doc/.dot/.docx/.dotx
(我并不挑剔,我只想让它工作),将其解析为占位符(或类似的东西),放入我自己的数据,然后返回生成的.doc/.docx/.dotx/.pdf
文件。
最重要的是,我需要免费的工具来实现这一目标。
我一直在寻找适合自己需求的东西,但找不到任何东西。Docmosis,Javadocx,Aspose等工具是商业化的。据我了解,Apache
POI尚无法成功实现这一目标(他们目前还没有任何正式的开发人员在框架的Word部分上工作)。
看起来唯一可以解决问题的是OpenOffice UNO API。但这对于从未使用过此API的人(例如我)来说是一个很大的字节。
因此,如果我要跳入这一步,我需要确保自己走在正确的道路上。
有人可以给我一些建议吗?
我知道距发布此问题已经很长时间了,我说我会在完成后发布解决方案。就是这样
希望有一天能对某人有所帮助。这是一个完整的工作类,您所要做的就是将其放入您的应用程序,并将TEMPLATE_DIRECTORY_ROOT目录和.docx模板放入您的根目录中。
用法很简单。您将占位符(键)放入.docx文件中,然后传递文件名和包含该文件对应键值对的Map。
请享用!
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URI;
import java.util.Deque;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletResponse;
public class DocxManipulator {
private static final String MAIN_DOCUMENT_PATH = "word/document.xml";
private static final String TEMPLATE_DIRECTORY_ROOT = "TEMPLATES_DIRECTORY/";
/* PUBLIC METHODS */
/**
* Generates .docx document from given template and the substitution data
*
* @param templateName
* Template data
* @param substitutionData
* Hash map with the set of key-value pairs that represent
* substitution data
* @return
*/
public static Boolean generateAndSendDocx(String templateName, Map<String,String> substitutionData) {
String templateLocation = TEMPLATE_DIRECTORY_ROOT + templateName;
String userTempDir = UUID.randomUUID().toString();
userTempDir = TEMPLATE_DIRECTORY_ROOT + userTempDir + "/";
try {
// Unzip .docx file
unzip(new File(templateLocation), new File(userTempDir));
// Change data
changeData(new File(userTempDir + MAIN_DOCUMENT_PATH), substitutionData);
// Rezip .docx file
zip(new File(userTempDir), new File(userTempDir + templateName));
// Send HTTP response
sendDOCXResponse(new File(userTempDir + templateName), templateName);
// Clean temp data
deleteTempData(new File(userTempDir));
}
catch (IOException ioe) {
System.out.println(ioe.getMessage());
return false;
}
return true;
}
/* PRIVATE METHODS */
/**
* Unzipps specified ZIP file to specified directory
*
* @param zipfile
* Source ZIP file
* @param directory
* Destination directory
* @throws IOException
*/
private static void unzip(File zipfile, File directory) throws IOException {
ZipFile zfile = new ZipFile(zipfile);
Enumeration<? extends ZipEntry> entries = zfile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
File file = new File(directory, entry.getName());
if (entry.isDirectory()) {
file.mkdirs();
}
else {
file.getParentFile().mkdirs();
InputStream in = zfile.getInputStream(entry);
try {
copy(in, file);
}
finally {
in.close();
}
}
}
}
/**
* Substitutes keys found in target file with corresponding data
*
* @param targetFile
* Target file
* @param substitutionData
* Map of key-value pairs of data
* @throws IOException
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
private static void changeData(File targetFile, Map<String,String> substitutionData) throws IOException{
BufferedReader br = null;
String docxTemplate = "";
try {
br = new BufferedReader(new InputStreamReader(new FileInputStream(targetFile), "UTF-8"));
String temp;
while( (temp = br.readLine()) != null)
docxTemplate = docxTemplate + temp;
br.close();
targetFile.delete();
}
catch (IOException e) {
br.close();
throw e;
}
Iterator substitutionDataIterator = substitutionData.entrySet().iterator();
while(substitutionDataIterator.hasNext()){
Map.Entry<String,String> pair = (Map.Entry<String,String>)substitutionDataIterator.next();
if(docxTemplate.contains(pair.getKey())){
if(pair.getValue() != null)
docxTemplate = docxTemplate.replace(pair.getKey(), pair.getValue());
else
docxTemplate = docxTemplate.replace(pair.getKey(), "NEDOSTAJE");
}
}
FileOutputStream fos = null;
try{
fos = new FileOutputStream(targetFile);
fos.write(docxTemplate.getBytes("UTF-8"));
fos.close();
}
catch (IOException e) {
fos.close();
throw e;
}
}
/**
* Zipps specified directory and all its subdirectories
*
* @param directory
* Specified directory
* @param zipfile
* Output ZIP file name
* @throws IOException
*/
private static void zip(File directory, File zipfile) throws IOException {
URI base = directory.toURI();
Deque<File> queue = new LinkedList<File>();
queue.push(directory);
OutputStream out = new FileOutputStream(zipfile);
Closeable res = out;
try {
ZipOutputStream zout = new ZipOutputStream(out);
res = zout;
while (!queue.isEmpty()) {
directory = queue.pop();
for (File kid : directory.listFiles()) {
String name = base.relativize(kid.toURI()).getPath();
if (kid.isDirectory()) {
queue.push(kid);
name = name.endsWith("/") ? name : name + "/";
zout.putNextEntry(new ZipEntry(name));
}
else {
if(kid.getName().contains(".docx"))
continue;
zout.putNextEntry(new ZipEntry(name));
copy(kid, zout);
zout.closeEntry();
}
}
}
}
finally {
res.close();
}
}
/**
* Sends HTTP Response containing .docx file to Client
*
* @param generatedFile
* Path to generated .docx file
* @param fileName
* File name of generated file that is being presented to user
* @throws IOException
*/
private static void sendDOCXResponse(File generatedFile, String fileName) throws IOException {
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
HttpServletResponse response = (HttpServletResponse) externalContext
.getResponse();
BufferedInputStream input = null;
BufferedOutputStream output = null;
response.reset();
response.setHeader("Content-Type", "application/msword");
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
response.setHeader("Content-Length",String.valueOf(generatedFile.length()));
input = new BufferedInputStream(new FileInputStream(generatedFile), 10240);
output = new BufferedOutputStream(response.getOutputStream(), 10240);
byte[] buffer = new byte[10240];
for (int length; (length = input.read(buffer)) > 0;) {
output.write(buffer, 0, length);
}
output.flush();
input.close();
output.close();
// Inform JSF not to proceed with rest of life cycle
facesContext.responseComplete();
}
/**
* Deletes directory and all its subdirectories
*
* @param file
* Specified directory
* @throws IOException
*/
public static void deleteTempData(File file) throws IOException {
if (file.isDirectory()) {
// directory is empty, then delete it
if (file.list().length == 0)
file.delete();
else {
// list all the directory contents
String files[] = file.list();
for (String temp : files) {
// construct the file structure
File fileDelete = new File(file, temp);
// recursive delete
deleteTempData(fileDelete);
}
// check the directory again, if empty then delete it
if (file.list().length == 0)
file.delete();
}
} else {
// if file, then delete it
file.delete();
}
}
private static void copy(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
while (true) {
int readCount = in.read(buffer);
if (readCount < 0) {
break;
}
out.write(buffer, 0, readCount);
}
}
private static void copy(File file, OutputStream out) throws IOException {
InputStream in = new FileInputStream(file);
try {
copy(in, out);
} finally {
in.close();
}
}
private static void copy(InputStream in, File file) throws IOException {
OutputStream out = new FileOutputStream(file);
try {
copy(in, out);
} finally {
out.close();
}
}
}
我在VBA Excel中开发了一个小程序。这是一个好的开始,但我调整了一些预设--一个网站推荐这将是从MS Word提取文本。我将正在处理的所有代码剥离为以下代码: 它打开任务管理器中引用的Word文档,但不是从界面中引用的。
问题内容: 我想从Java程序中打开excel文档。实际上,我想在程序中单击按钮时打开excel文档。我努力了 其中workbook.xls位于项目文件夹的根目录中,但不起作用。异常表示无法打开程序workbook.xls。我怎样才能做到这一点 问题答案: 我想您要使用默认程序(例如Excel)打开Excel文件吗?如果是这样,您可以使用-class:
问题内容: 我的Java应用程序中有一个按钮,当单击该按钮时,该按钮应导致Word打开特定文件。该文件位于文件系统中的某个位置,例如用户的文档目录中。 如何在Java中实现类似的功能? 问题答案: 这是简单的演示应用程序,您可以针对按钮单击事件对其进行修改: } 这将使用默认单词应用程序打开单词文件。台式机的更多详细信息
问题内容: 如何在浏览器中打开和查看文件扩展名?该文件位于我的服务器上。 问题答案: 有两种选择:第一种是仅链接到它,第二种是使用iframe并将其指向文档。但是,要使此功能起作用,大多数浏览器都要求服务器发送带有文档的标头。如果您无法配置Web服务器来执行此操作,则可以将文档包装在php中: 然后链接到该脚本而不是您的Word文档。 但是,这不能保证能正常工作。content-dispositi
本文向大家介绍Java在线打开word文档并强制留痕的方法,包括了Java在线打开word文档并强制留痕的方法的使用技巧和注意事项,需要的朋友参考一下 前言: 在OA系统中,时不时的都会伴随着文档流转过程。 比如有的系统中会有领导审批的流程,那么在A领导审批完成后,他的审批痕迹能不能强制保留下来,以供下一步处理文档的专员清晰地参考呢? 我们知道,在本地office打开的文档中,如果点击 审阅---
问题内容: 我有一个Windows实用程序,用于打开Word文档,从其中提取数据并使用该数据生成另一个Word文档。 现在我的问题是,该Windows exe可直接在命令提示符下正常运行,但是如果我通过jenkins调用此exe,即构建步骤“执行Windows批处理命令”,则会出现错误,无法打开Word文档,因此存在实用性错误。 我也尝试过其他选项,例如从pom文件和批处理文件调用exe。每当它给