基于Freemarker模版生成Docx和Pdf文件

产品提了个这样的需求:分别生成一个word文档和pdf文档,里面需要包含数据,这些数据需要有对应的样式比如字体大小,表格,段落等。开始的想法是用Apache POI,但看了那一大段填充值操作的代码发现太过冗长,决定采用Freemarker模版的方案。
百度了一圈看上去Spring Boot + FreeMarker制作word模板导出Word表格这种做法像那么一回事,尝试了一波后发现生成的是只能生成doc格式的文件!只能生成doc格式的文件!只能生成doc格式的文件!我要的是docx格式的呀哥???
迫不得已我又只能经过漫长的搜索尝试失败再搜索尝试失败…好吧,终于找到生成docx的方案:
1.将docx后缀修改为zip,取出其中的document.xml文档以及_rels文件夹下的document.xml.rels文档。
document.xml是填充文本类内容需要用用到的文件,比如你可以这样修改
基于Freemarker模版生成Docx和Pdf文件_第1张图片
意思是在生成新的docx时,将这个${}内容替换成我们传进来的参数,至于模版怎么整理,还有freemarker的循环,判断这些语法就自行百度吧,easy!
document.xml.rels是你的docx中需要替换其中的图片时要用到的文件,比如我将原来的


替换成了


意思是我将image1.jpeg替换成了${img.imgTargetName}这个变量对应的图片,当然zip包里的media文件夹也需要将新的图片文件写进去,需要注意的是,新文件的后缀名最好与原来文件的后缀名一致,否则生成的docx可能打不开。
2.读取zip文件的压缩流,将原来的document.xml、document.xml.rel文件替换成填充过内容的的 document.xml、document.xml.rels文件,把图片写入zip文件下word/media文件夹中
输出docx文档。
上代码

	public static String exportImgWordDocx(Map map,String wordXmlName,String wordImgXmlResName)
			throws Exception {
		Template freemarkerTemplate = configuration.getTemplate(wordXmlName);
		Template imgFreemarkerTemplate = configuration.getTemplate(wordImgXmlResName);
		InputStream fin = null;
		ServletOutputStream out = null;
		Writer writerOut = null;
		Writer writerOutImg = null;
		File outdocxXmlFile =null;
		File outdocxImgXmlFile = null;
		File docxFile = null;
		String docxPath = null;
		try {
			//指定输出word docx的数据文件的路径
			String outdocxXmlFilePath = exportResourcePath+UUID.randomUUID().toString()+".xml";
			outdocxXmlFile = new File(outdocxXmlFilePath);
			FileOutputStream fos = new FileOutputStream(outdocxXmlFile);
			writerOut = new BufferedWriter(new OutputStreamWriter(fos),10240);
			//将map数据写入到xml模板中,获取docx数据文件
			freemarkerTemplate.process(map,writerOut);


			//指定输出word docx的图片数据文件的路径
			String outdocxImgXmlFilePath = exportResourcePath+UUID.randomUUID().toString()+".xml.rels";
			outdocxImgXmlFile = new File(outdocxImgXmlFilePath);
			FileOutputStream fosImg = new FileOutputStream(outdocxImgXmlFile);
			writerOutImg = new BufferedWriter(new OutputStreamWriter(fosImg),10240);
			//将map数据写入到图片xml模板中,获取docx图片数据文件
			imgFreemarkerTemplate.process(map,writerOutImg);


			//将docx数据xml文件、图片数据xml文件替换到对应的docx实例zip压缩包中去
			ClassPathResource resource = new ClassPathResource("templates/SummaryTemplate.zip");
			InputStream zipFileInputStream = resource.getInputStream();

			docxPath = exportResourcePath +UUID.randomUUID().toString()+".docx";
			docxFile = new File(docxPath);

			ZipInputStream zipInputStream = ZipUtils.wrapZipInputStream(zipFileInputStream);
			ZipOutputStream zipOutputStream = ZipUtils.wrapZipOutputStream(new FileOutputStream(docxFile));
			String itemNameOne = "word/document.xml";
			String itemNameTwo = "word/_rels/document.xml.rels";
			List> imgList = (List>)map.get("imgList");
			ZipUtils.replaceTwoItem(zipInputStream, zipOutputStream, itemNameOne, new FileInputStream(outdocxXmlFile),itemNameTwo,new FileInputStream(outdocxImgXmlFile),imgList);


		} catch (TemplateException e) {
			StackTraceElement[] stackTraceElements = e.getStackTrace();
			logger.error(e.toString() + "---" + stackTraceElements[0].toString());
			throw new SystemRunException(e.toString() + "---" + stackTraceElements[0].toString());
		}finally {
			if (out != null) {
				out.close();
			}
			if (fin != null) {
				fin.close();
			}
			if(writerOut != null){
				writerOut.close();
			}
			if(writerOutImg != null){
				writerOutImg.close();
			}
			if(outdocxXmlFile!=null){
				outdocxXmlFile.delete();//删除docx临时数据文件
			}
			if(outdocxImgXmlFile!=null){
				//outdocxImgXmlFile.delete();//删除docx临时图片数据文件
			}
			if(docxFile!=null){
				//docxFile.delete();//删除docx临时文件
			}
		}
		return docxPath;
	}

如果需要生成pdf格式文件,也是需要先生成docx格式文件再转换成pdf格式文件,至于这个转换的过程,我找的到方案里最简单靠谱的还是用asponse-words,但这是个收费软件,csdn里很多破解版的jar下载资源,不使用破解版的话生成的pdf文件是会有水印的。
上代码:

public static void asposeWord2Pdf(String docxPath,String pdfPath){
		logger.info("docxPath" + docxPath + "pdfPath" + pdfPath);

		if (!getLicense()) {
			return;
		}
		FileOutputStream os =null;
		try {
			File file = new File(pdfPath); // 新建一个空白pdf文档
			os = new FileOutputStream(file);
			Document doc = new Document(docxPath); // Address是将要被转化的word文档
			doc.save(os, SaveFormat.PDF);
		} catch (Exception e) {
			StackTraceElement[] stackTraceElements = e.getStackTrace();
			logger.error(e.toString() + "---" + stackTraceElements[0].toString());
			throw new SystemRunException(e.toString() + "---" + stackTraceElements[0].toString());
		}finally{
			if(os!=null){
				try {
					os.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

	}

后面可能还会遇到SpringBoot引用外部jar的问题,生成的Pdf文件里都是小方块这样的问题,生成文件慢各种各样的问题,都需要一一耐心解决,别问我怎么知道的…哭!

以下都是大佬:

java利用Freemarker模板生成docx格式的word文档

java利用Freemarker模板生成格式友好的doc或者docx文档

freemarker基于docx格式创建模板导出带图片pdf文件

你可能感兴趣的:(JavaWeb日常积累,java,freemarker,spring)