freemarker生成world转PDF转SWF,加载到浏览器.解决最终浏览器加载的是xml代码的问题.
首先说一下需求:动态生成world,客户可在浏览器预览freemarker动态生成的world文档.
失败的解决方法:
1. world转xml, 编辑xml,用${}替换动态改变的值。
2. freemarker动态替换${}占位符的值, 更改后缀名为doc。
3. 系统安装openoffice工具,启动openoffice服务,jodconverter 调用命令将doc转成pdf.
4. 系统安装swftools工具, 调用命令,将pdf转成swf.(很多插件支持直接加载pdf到浏览器,但是对于老版本的IE,兼容性并不好,但是swf文件基本所有浏览器都支持,所以为了老版本ie兼容性,就做了一步转swf)
5. 前台js插件flashPaper,直接加载服务器上的swf文件.
最终效果, doc和pdf文档直接双击可以打开,显示的也正常。但是flashPaper加载到浏览器则显示的是一堆xml格式代码,这个代码就是freemarker生成的doc右键文本打开后的xml代码. 经过翻阅资料,flashPaper包括很多插件不支持直接加载xml形式的doc文档(可能是我没找到正确方法,如果您有, 请给留个言,谢谢),如果非要加载,那么显示到浏览器上的就会是一推xml代码。主要原因可能是freemarker产生的doc实际上只是个xml文档,右键可打开文本查看,但是直接在桌面新建的doc,docx文档右键则打不开(实际上这样建立的doc docx是一个压缩文件)
新的解决方法:
1. 新建docx文档(07版本的), 编辑docx,需要用freemarker替换的数据用${x}代替,保存 注意: 替换变量${x}时最好一次性写完,要不可能xml文档混乱
2. 右键以压缩文件形式打开,在world/下找到document.xml文件,是freemarker需要输出的结果xml文件.格式化xml查看${}占位是否有问题,有问题
不要直接改,重新编辑world,重复1步骤开始。
3. 第2步没问题,将docx文件和导出来的xml文件复制到ftl/test下,xml重命名为docx的名字.(我建立的是javaweb项目,ftl/test是在类路径下,以方便
根据类路径可读取到这个包)
4. FreemarkerUtil.printFile 根据第三步的xml生成替换后新的xml,临时保存
5. XmlToDocxDocument.printDocx 根据第三步docx模板文件,用新的xml替换调/world下document文件,重新生成一个新的docx。
6. 系统安装openoffice工具,启动openoffice服务,jodconverter 调用命令将docx转成pdf.
4. 系统安装swftools工具, 调用命令,将pdf转成swf.(很多插件支持直接加载pdf到浏览器,但是对于老版本的IE,兼容性并不好,但是swf文件基本所
有浏览器都支持,所以为了老版本ie兼容性,就做了一步转swf)
5. 前台js插件flashPaper,直接加载服务器上的swf文件.
经测试效果良好,IE7 到 11,火狐 谷歌多种内核浏览器均可正常显示.
大致方法就是doc中包含一个xml文档,xml文档包含了所有要显示的内容,我们用freemarker替换这个xml,之后再添加压缩文件,替换回去。这样最终保持了
world的完整性,新建文档需要docx 07版的。
代码: 完整项目有附件. 点击打开链接
需要安装的软件,资源很多 随处可下
1. Apache_OpenOffice_4.1.4_Win_x86_install_zh-CN.exe
2. swftools-0.9.0.exe
jar 包
1.
/**
* @date 2017年11月21日 下午11:10:14
* @return void 返回类型
* @throws Exception
* @throws
* @Description:
* 下载文档(freemarker模板)
*/
@RequestMapping(value="/downLoadDocx")
@ResponseBody
public void downLoadDocument(HttpServletResponse response, String fileName) throws Exception{
/**
* 1. freemarker填充xml文件
* 2. xml替换docx模板中的document
* 3. 下载
*/
Map root = new HashMap();
root.put("userName", "丽丽");
root.put("sex", "2女");
root.put("content", "这是freemarker模板引擎生成的world测试内容.");
String preFileName = fileName;//前台传过来的文件名 test.docx
String ftlPath = "test";//ftl下的文件夹名称
String filePath = PathUtil.getDocumentPathByClassPath();//webcontent/document目录
String timeFileName = FileUtil.getFilePrefixName(fileName)+(new Date().getTime())+".xml";
FreemarkerUtil.printFile(FileUtil.getFilePrefixName(fileName)+".xml",
root,
timeFileName,
filePath,
ftlPath);
XmlToDocxDocument.printDocx(response,
filePath+timeFileName,
PathUtil.getClassResources()+"/ftl/"+ftlPath+"/"+preFileName,
ConfigUtil.getSwfUploadDir() + "/"+preFileName,
preFileName);
//删除临时freemarker生成的xml文件
FileUtil.delFile(filePath+timeFileName);
}
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import javax.servlet.http.HttpServletResponse;
/**
* 将freemarker替换的xml转成docx压缩文件的document.xml
* @author yangwl 2017年11月23日21:56:19
*
*/
public class XmlToDocxDocument {
/**
* @date 2017年11月23日 下午9:57:30
* documentFile freemarker替换之后的xml
* docxTemplate docx的模板
* toFilePath 导出目标文件路径
* @return void 返回类型
* @throws
* @Description:
*/
public static void printDocx(HttpServletResponse response, File documentFile, String docxTemplate, String toFilePath) throws ZipException, IOException {
try {
File docxFile = new File(docxTemplate);
ZipFile zipFile = new ZipFile(docxFile);
Enumeration extends ZipEntry> zipEntrys = zipFile.entries();
ZipOutputStream zipout = new ZipOutputStream(response.getOutputStream());
int len = -1;
byte[] buffer = new byte[1024];
while (zipEntrys.hasMoreElements()) {
ZipEntry next = zipEntrys.nextElement();
InputStream is = zipFile.getInputStream(next);
// 把输入流的文件传到输出流中 如果是word/document.xml由我们输入
zipout.putNextEntry(new ZipEntry(next.toString()));
if ("word/document.xml".equals(next.toString())) {
InputStream in = new FileInputStream(documentFile);
while ((len = in.read(buffer)) != -1) {
zipout.write(buffer, 0, len);
}
in.close();
} else {
while ((len = is.read(buffer)) != -1) {
zipout.write(buffer, 0, len);
}
is.close();
}
}
zipout.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void printDocx(HttpServletResponse response, String documentFile, String docxTemplate, String toFilePath, String outFileName) throws ZipException, IOException {
response.reset();
response.setHeader("Content-Disposition", "attachment; filename=\"" + new String(outFileName.getBytes("gb2312"), "ISO8859-1")+ "\"");
response.setContentType("application/octet-stream;charset=UTF-8");
printDocx(response, new File(documentFile), docxTemplate, toFilePath);
response.flushBuffer();
}
}
/**
* 文档预览
* world/excel/ppt 等 -> PDF -> SWF
* swf兼容个版本浏览器
* 2017年11月16日14:31:16
* @param os
* @param filePath
* @throws IOException
*/
@RequestMapping(value="/showDocx", method=RequestMethod.GET)
public void showOfficeFile(OutputStream os,String filePath) throws IOException {
if (!StringUtil.isEmpty(filePath)){
filePath = ConfigUtil.getSwfUploadDir() + "/" + filePath;
String swfFilePath = filePath.substring(0, filePath.lastIndexOf(".")) + ".swf";
File f = new File(swfFilePath);
boolean hasFile = true;
if (!f.exists()) {
LOGGER.info("未生成过swf文件,即将生成的SWF文件,路径为: " + swfFilePath);
hasFile = OfficeToSwf.toSwf(filePath);
}
LOGGER.info("SWF文件已生成,路径为: " + swfFilePath);
if ( hasFile ){
InputStream inputStream = null;
inputStream = new BufferedInputStream(new FileInputStream(f));
FileCopyUtils.copy(inputStream,os);
os.flush();
os.close();
inputStream.close();
}
}
}
public static int office2PDF(String sourceFile, String destFile){
try {
log.debug("文件转换为PDF,[参数]SOURCEFile: " + sourceFile + "destFile: "
+ destFile);
File inputFile = new File(sourceFile);
if (!inputFile.exists()) {
return -1;// 找不到源文件, 则返回-1
}
// 如果目标路径不存在, 则新建该路径
File outputFile = new File(destFile);
if (outputFile.exists()){
return 0;
}
if (!outputFile.getParentFile().exists()) {
outputFile.getParentFile().mkdirs();
}
// 连接服务
OpenOfficeConnection connection = OpenOfficeServer.getConnection();
connection.connect();
// convert
DocumentConverter converter = new OpenOfficeDocumentConverter(connection);
if (isTxt(inputFile)) {
File odtFile = isWindows(inputFile);
converter.convert(odtFile, outputFile);
} else {
DocumentFormatRegistry factory = new BasicDocumentFormatRegistry();
DocumentFormat inputDocumentFormat = factory.getFormatByFileExtension(getExtensionName(inputFile.getAbsolutePath()));
DocumentFormat outputDocumentFormat = factory.getFormatByFileExtension(getExtensionName(outputFile.getAbsolutePath()));
converter.convert(inputFile, inputDocumentFormat, outputFile, outputDocumentFormat);
}
connection.disconnect();
return 0;
} catch (ConnectException e) {
log.error("openoffice 连接失败!",e);
} catch (IOException e) {
log.error("文件格式转换失败",e);
} catch (InterruptedException e) {
log.error("文件转换失败",e);
return 1;
}
return 1;
}
pdf-swf
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.nuctech.common.util.CommandHelper;
import com.nuctech.common.util.ConfigUtil;
/**
* pdf转swf类
*/
public class PdfToSwf {
private static final Logger log = LoggerFactory.getLogger(PdfToSwf.class);
/**
* pdf转swf.
*
* @param pdfPath pdf路径
* @param swfPath swf路径
* @return result
*/
public static boolean pdfToSwf(String pdfPath, String swfPath) {
String command = "";
Properties properies = ConfigUtil.getProperies();
if (System.getProperty("os.name").contains("Windows")) {
command = properies.getProperty("windows.swftools.bin") + " -t " + pdfPath + " -o " + swfPath
+ " -f -s flashversion=9 ";
} else {
command = properies.getProperty("linux.swftools.bin") + " -t " + pdfPath + " -o " + swfPath
+ " -f -s flashversion=9 ";
}
log.debug("即将执行命令:" + command);
return CommandHelper.runCommand(command) == 0;
}
}
注意: 启动openoffice方法 在 OpenOfficeServer的main方法里. application.server.properties 配置了两个软件的安装地址.