日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

如何使用freeMarker生成doc、docx文档

發(fā)布時(shí)間:2023/12/31 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何使用freeMarker生成doc、docx文档 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

如何使用freeMarker生成doc、docx、pdf文件

freeMarker是什么
doc和docx有什么區(qū)別
如何生成doc文檔(帶圖片)
如何生成docx文檔,以及將其生成pdf文檔

  • freeMarker是什么

    http://freemarker.foofun.cn/

  • doc和docx有什么區(qū)別
    格式不同
    DOCX是WORD2007及以上版的格式,是一種基于XML的壓縮格式。
    DOC是WORD2003及以下版的格式。
    體積不同,docx遠(yuǎn)大于doc
    doc是單個(gè)文件,而docx其實(shí)是由一個(gè)zip壓縮文件更改后綴而來

  • 如何生成doc文檔
    由1可以明白freemarker可以輸出文本信息, 而我們的doc其實(shí)就是一個(gè)文本,所以可以直接使用freemarker可以doc文件,將doc文件,另存為xml文件,修改成動(dòng)態(tài)數(shù)據(jù)模板,如果帶有圖片,可直接由圖片轉(zhuǎn)成base64格式,再按照普通屬性進(jìn)行替換(此處我們重點(diǎn)說生成docx文檔,因?yàn)樯蓀df文檔,poi對freemark生成的doc文檔轉(zhuǎn)成pdf無法辨識(shí))

  • 如何生成docx文檔,以及將其生成pdf文檔
    docx是一個(gè)zip壓縮文件,解壓后的內(nèi)容如下:



    主要關(guān)注:document.xml (文檔結(jié)構(gòu)),document.xml.rels(圖片引用關(guān)系配置),以及media(存放圖片的目錄)目錄
    還是直接上代碼吧
    首先寫一個(gè)要生成的docx樣式,修改后綴為zip,然后將其解壓,設(shè)置動(dòng)態(tài)數(shù)據(jù),修改document.xml 和document.xml.rels文件按照freeMarker數(shù)據(jù)格式編寫
    document.xml (文檔結(jié)構(gòu),橘色部分freemarker需要設(shè)置的動(dòng)態(tài)數(shù)據(jù)):

    文檔結(jié)構(gòu),橘色部分freemarker引用document.xml.rels中的id:

    document.xml.rels(圖片引用關(guān)系配置,橘色部分freemarker需要?jiǎng)討B(tài)生成的圖片引用id)

  • 依賴jar

    <dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.23</version></dependency><dependency><groupId>com.artofsolving</groupId><artifactId>jodconverter-maven-plugin</artifactId><version>2.2.1</version></dependency <dependency><groupId>fr.opensagres.xdocreport</groupId><artifactId>org.apache.poi.xwpf.converter.core</artifactId><version>1.0.5</version></dependency><dependency><groupId>fr.opensagres.xdocreport</groupId><artifactId>org.apache.poi.xwpf.converter.pdf</artifactId><version>1.0.5</version></dependency> public class XMlToDocx {private static String OS = System.getProperty("os.name").toLowerCase();/*** 根據(jù)數(shù)據(jù)生成文本* @param dataMap 數(shù)據(jù)* @param outFilePath 生成的document.xml和document.xml.rels對應(yīng)的目錄名稱* @param template 模板對象* @throws Exception*/private static void toText(Map<String,Object> dataMap,String outFilePath,Template template)throws Exception {File docFile = new File(outFilePath);FileOutputStream fos = new FileOutputStream(docFile);Writer out = new BufferedWriter(new OutputStreamWriter(fos),10240);template.process(dataMap,out);if(out != null){out.close();}}/*** 生成word docx* @param dataMap 數(shù)據(jù)* @param ftlPath ftl存放的目錄(模板)* @param docFilePath 生成的document.xml和document.xml.rels對應(yīng)的目錄名稱* @param fileList fileList 圖片文件* @throws Exception*/public static void makeWord(Map<String,Object> dataMap,String ftlPath,String docFilePath, List<File> fileList) throws Exception {/** 初始化配置文件 **/Configuration configuration = new Configuration();String fileDirectory = ftlPath;/** 加載文件 **/configuration.setDirectoryForTemplateLoading(new File(fileDirectory));/** 加載模板 **/Template template = configuration.getTemplate("document.xml");/** 指定輸出word文件的路徑 **/String outFilePath = docFilePath+".xml";toText(dataMap,outFilePath,template);template = configuration.getTemplate("document.xml.rels");outFilePath = docFilePath+".xml.rels";toText(dataMap,outFilePath,template);try {ZipInputStream zipInputStream = ZipUtils.wrapZipInputStream(new FileInputStream(new File(fileDirectory+File.separator+"report.zip")));//該zip文件是docx重命名后的壓縮文件ZipOutputStream zipOutputStream = ZipUtils.wrapZipOutputStream(new FileOutputStream(new File(docFilePath+".docx")));File fileText = new File(docFilePath+".xml");File fileImg = new File(docFilePath+".xml.rels");ZipUtils.replaceItem(zipInputStream, zipOutputStream, new FileInputStream(fileText), new FileInputStream(fileImg),fileList);if(fileText.exists()){fileText.delete();}if(fileImg.exists()){fileImg.delete();}} catch (Exception e) {System.out.println(e.toString());}}/*** 生成pdf*/public static void makePdfByXcode(String ftlPath,String docFilePath){try {XWPFDocument document=new XWPFDocument(new FileInputStream(new File(docFilePath+".docx")));File outFile=new File(docFilePath+".pdf");if(!outFile.getParentFile().exists()){outFile.getParentFile().mkdirs();}OutputStream out=new FileOutputStream(outFile);PdfOptions options= PdfOptions.getDefault();IFontProvider iFontProvider = new IFontProvider() {@Overridepublic Font getFont(String familyName, String encoding, float size, int style, Color color) {try {BaseFont bfChinese = null;if( OS.indexOf("linux")>=0){bfChinese = BaseFont.createFont(ftlPath+"/font/msyh.ttf", BaseFont.IDENTITY_H,BaseFont.NOT_EMBEDDED);}else{bfChinese = BaseFont.createFont("C:/WINDOWS/Fonts/STSONG.TTF", BaseFont.IDENTITY_H,BaseFont.NOT_EMBEDDED);}Font fontChinese = new Font(bfChinese, size, style, color);if (familyName != null)fontChinese.setFamily(familyName);return fontChinese;} catch (Exception e) {e.printStackTrace();return null;}}};options.fontProvider( iFontProvider );PdfConverter.getInstance().convert(document,out,options);}catch ( Exception e) {e.printStackTrace();}}} public class ZipUtils {private static String docText = "word/document.xml";//要替換的document.xml的位置private static String imgName = "word/_rels/document.xml.rels"; //要替換的document.xml.rels的位置private static String mediaName = "word/media/";//圖片meida的位置/**** @param zipInputStream zip文件的zip輸入流* @param zipOutputStream 輸出的zip輸出流* @param docTextInputStream 替換后的document.xml文本* @param imgInputStream 替換后的document.xml.rels文本* @param fileList 需要壓入meida的圖片*/public static void replaceItem(ZipInputStream zipInputStream,ZipOutputStream zipOutputStream,InputStream docTextInputStream,InputStream imgInputStream, List<File> fileList){//if(null == zipInputStream){return;}if(null == zipOutputStream){return;}if(null == docTextInputStream){return;}boolean replaceMedia = false;//ZipEntry entryIn;try {while((entryIn = zipInputStream.getNextEntry())!=null){String entryName = entryIn.getName();ZipEntry entryOut = new ZipEntry(entryName);// 只使用 namezipOutputStream.putNextEntry(entryOut);// 緩沖區(qū)byte [] buf = new byte[8*1024];int len;if(entryName.equals(docText)){// 使用替換流(替換文字內(nèi)容)while((len = (docTextInputStream.read(buf))) > 0) {zipOutputStream.write(buf, 0, len);}}else if(entryName.equals( imgName)){// 使用替換流(替換圖片)while((len = (imgInputStream.read(buf))) > 0) {zipOutputStream.write(buf, 0, len);}}else if(entryName.contains(mediaName)&&replaceMedia){}else if(entryName.contains(mediaName)&&!entryName.equals(mediaName)&&!replaceMedia){//將圖片壓縮到media目錄中replaceMedia = true;if(entryName.contains("image1.png")){// 輸出普通Zip流while((len = (zipInputStream.read(buf))) > 0) {zipOutputStream.write(buf, 0, len);}// 關(guān)閉此 entryzipOutputStream.closeEntry();}for(int i=0;i<fileList.size();i++){entryIn = new ZipEntry(mediaName+fileList.get(i).getName());zipOutputStream.putNextEntry(entryIn);FileInputStream in = null;try {in = new FileInputStream(fileList.get(i));while ((len = in.read(buf)) != -1){zipOutputStream.write(buf, 0, len);}// 關(guān)閉此 entryzipOutputStream.closeEntry();} catch (IOException e) {}finally {close(in);}}}else {// 輸出普通Zip流while((len = (zipInputStream.read(buf))) > 0) {zipOutputStream.write(buf, 0, len);}}// 關(guān)閉此 entryzipOutputStream.closeEntry();}} catch (IOException e) {e.printStackTrace();}finally {//e.printStackTrace();close(docTextInputStream);close(zipInputStream);close(zipOutputStream);close(imgInputStream);}}/*** 包裝輸入流*/public static ZipInputStream wrapZipInputStream(InputStream inputStream){ZipInputStream zipInputStream = new ZipInputStream(inputStream);return zipInputStream;}/*** 包裝輸出流*/public static ZipOutputStream wrapZipOutputStream(OutputStream outputStream){ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream);return zipOutputStream;}private static void close(InputStream inputStream){if (null != inputStream){try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}}private static void close(OutputStream outputStream){if (null != outputStream){try {outputStream.flush();outputStream.close();} catch (IOException e) {e.printStackTrace();}}} }

    加入以上class,按照自己指定的數(shù)據(jù)格式傳入數(shù)據(jù),則可生成docx和pdf文檔

    遇到的坑:
    1、未理解docx,其實(shí)就是一個(gè)壓縮zip文件,將其中需要替換的內(nèi)容,替換后,重新生成一個(gè)docx文檔就可以
    2、docx如果有表格樣式的動(dòng)態(tài)內(nèi)容循環(huán),修改成模板后,重新壓縮,修改后綴為docx不能打開,所以遇到表格樣式的動(dòng)態(tài)內(nèi)容循環(huán),盡量小心一些
    3、資料太少,無處尋求幫組

    第一次寫博客哈,寫的不好,希望大家多多提意見,希望對需要的朋友有幫組

    總結(jié)

    以上是生活随笔為你收集整理的如何使用freeMarker生成doc、docx文档的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。