准备好空白的word模板
在需要的字段中填写字段名称
如果需要插入图片的地方需要优先插入备用图片
将word文档另存存为xml格式
这里说明一下,使用office和使用wps是有错位编码的,根据应用习惯去进行word的格式化
将生成的xml文件复制一份,并更改后缀名为ftl文件
正常的pom文件以外还要引入以下库
<!-- freeMarker begin--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency> <dependency> <groupId>com.documents4j</groupId> <artifactId>documents4j-local</artifactId> <version>1.0.3</version> </dependency> <dependency> <groupId>com.documents4j</groupId> <artifactId>documents4j-transformer-msoffice-word</artifactId> <version>1.0.3</version> </dependency>
package cc.vace.cloud.str.util; import cc.vace.cloud.str.util.SpringUtil; import freemarker.template.Template; import freemarker.template.TemplateException; import org.apache.commons.io.IOUtils; import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; import java.io.*; import java.util.Map; public final class FreemarkerParseUtils { /** * a不可实例化 */ private FreemarkerParseUtils() { } /** * a把ftl文件解析成html字符串内容 * * @param templatePath ftl文件路径 * @param model 模型数据(插值) * @return 解析后的html文件内容 */ public static String parse(String templatePath, Map<String, Object> model) { StringWriter stringWriter = null; BufferedWriter writer = null; File f = new File(templatePath); if (!f.getParentFile().exists()) { f.getParentFile().mkdirs(); } try { //获取模板 Template template = SpringUtil .getBean("freeMarkerConfigurer", FreeMarkerConfigurer.class) .getConfiguration() .getTemplate(templatePath); stringWriter = new StringWriter(); writer = new BufferedWriter(stringWriter); //将模板与数据模型合并 template.process(model, writer); writer.flush(); } catch (Exception e) { e.printStackTrace(); } finally { IOUtils.closeQuietly(writer); IOUtils.closeQuietly(stringWriter); } return stringWriter.toString(); } /** * a解析ftl文件内容 * * @param content 原ftl模板文件内容 * @param model 模板文件数据 * @return 解析后的html文件内容 */ public static String parseFtlContent(String content, Map<String, Object> model) { // 获取配置 StringWriter out = new StringWriter(); try { Template template = new Template("template", new StringReader(content), SpringUtil.getBean("freeMarkerConfigurer", FreeMarkerConfigurer.class).getConfiguration()); template.process(model, out); } catch (TemplateException | IOException e) { return ""; } String htmlContent = out.toString(); if (out != null) { try { out.close(); } catch (IOException e) { return ""; } } return htmlContent; } }
2.SpringUtil
package cc.vace.cloud.str.util; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; @Component public class SpringUtil implements ApplicationContextAware { private static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { if (SpringUtil.applicationContext == null) { SpringUtil.applicationContext = applicationContext; } System.out.println("========ApplicationContext配置成功,在普通类可以通过调用SpringUtils.getAppContext()获取applicationContext对象,applicationContext=" + SpringUtil.applicationContext + "========"); System.out.println("---------------------------------------------------------------------"); } //获取applicationContext public static ApplicationContext getApplicationContext() { return applicationContext; } //通过name获取 Bean. public static Object getBean(String name) { return getApplicationContext().getBean(name); } //通过class获取Bean. public static <T> T getBean(Class<T> clazz) { return getApplicationContext().getBean(clazz); } //通过name,以及Clazz返回指定的Bean public static <T> T getBean(String name, Class<T> clazz) { return getApplicationContext().getBean(name, clazz); } }
package cc.vace.cloud.str.util; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import sun.misc.BASE64Encoder; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; /** * 图片工具类 */ @Component public class ImageUtil { /** * 将图片内容转换成Base64编码的字符串 * @param imageFile 图片文件的全路径名称 * @return 转换成Base64编码的图片内容字符串 */ public static String getImageBase64String(String imageFile) { if (StringUtils.isEmpty(imageFile)) { return ""; } File file = new File(imageFile); if (!file.exists()) { return ""; } InputStream is = null; byte[] data = null; try { is = new FileInputStream(file); data = new byte[is.available()]; is.read(data); is.close(); } catch (IOException e) { e.printStackTrace(); } BASE64Encoder encoder = new BASE64Encoder(); return encoder.encode(data); } }
package cc.vace.cloud.str.util; import com.documents4j.api.DocumentType; import com.documents4j.api.IConverter; import com.documents4j.job.LocalConverter; import freemarker.core.ParseException; import freemarker.template.*; import java.io.*; import java.util.HashMap; import java.util.Map; public class TemplateUtil { /** * a生成word文件 * * @param dataMap 模板中需要展示的动态数据,用map集合来保存 * @param templateName 模板名称 * @param fileCompletePath 输出文件完整路径,例如:D:/wordFile/ * @throws IOException * @throws ParseException * @throws MalformedTemplateNameException * @throws TemplateNotFoundException * @throws TemplateException */ public static void createFile(Map dataMap, String templateName, String fileCompletePath) throws Exception { File file = new File(fileCompletePath); if (!file.getParentFile().exists()) { file.getParentFile().mkdirs(); } // 创建配置实例 Configuration configuration = new Configuration(); // 设置编码 configuration.setDefaultEncoding("UTF-8"); // ftl模板文件 configuration.setClassForTemplateLoading(TemplateUtil.class, "/"); // 获取模板 Template template = configuration.getTemplate(templateName); // 输出文件 File outFile = new File(fileCompletePath); // 如果输出目标文件夹不存在,则创建 if (!outFile.getParentFile().exists()) { outFile.getParentFile().mkdirs(); } // 将模板和数据模型合并生成文件 Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "UTF-8")); // 生成文件 template.process(dataMap, out); // 关闭流 out.flush(); out.close(); } public static void createTemplateAndConverter(Map dataMap, String templateName, String fileCompletePath) throws Exception { // 创建配置实例 Configuration configuration = new Configuration(); // 设置编码 configuration.setDefaultEncoding("UTF-8"); // ftl模板文件 configuration.setClassForTemplateLoading(TemplateUtil.class, "/"); // 获取模板 Template template = configuration.getTemplate(templateName); // 将模板和数据模型合并生成文件 // Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "UTF-8")); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); Writer writer = new BufferedWriter(new OutputStreamWriter(byteArrayOutputStream, "UTF-8")); // 生成文件 template.process(dataMap, writer); File file = new File(fileCompletePath); if (!file.getParentFile().exists()) { file.getParentFile().mkdirs(); } OutputStream outputStream = new FileOutputStream(file); IConverter converter = LocalConverter.builder().baseFolder(new File(file.getParentFile().getPath())).build(); converter.convert(new ByteArrayInputStream(byteArrayOutputStream.toByteArray())).as(DocumentType.DOCX).to(outputStream).as(DocumentType.PDF).execute(); } public static void main(String[] args) throws Exception { Map map = new HashMap(); // map数据,模板, createFile(map,"templates/csdn.ftl","D:/csdn_generate.doc"); } }
这时我们的文件时这个样子的
格式化一下代码
在ftl文件中,有可能会需要更改里边我们设置的参数
将多余的标签删除,直到参数为实际参数为止
最终效果(如果本来就是${参数}可以不用修改)
找到图片base64编码区域,将编码删除,设置成我们的图片参数
<pkg:part pkg:name="/word/media/image1.png" pkg:contentType="image/png" pkg:compression="store"> <pkg:binaryData>${img1}</pkg:binaryData> </pkg:part>
这里需要注意,如果你是多张图片位置,但是在设置模板的时候为同一个图片,则只会有一个图片包出现,需要自己添加新的图片包
找到Relationships中的image1.png,在文件中有多个Relationships,一定要找到image1.png的Relationship
在后面追加
根据image1.png的id:rtd4搜索找到应用的地方
或者
修改其中一个改成我们自己写的ID就可以啦
@Override public void test(BaseQuery query) { Map map = new HashMap(); map.put("name","张三"); map.put("id","202145154545"); map.put("sex","男的"); map.put("nation","汉族"); map.put("img1",ImageUtil.getImageBase64String("C:/Users/king/Desktop/hh.png")); //图片路径,并由ImageUtil生成base64编码格式 map.put("img2",ImageUtil.getImageBase64String("C:/Users/king/Desktop/mz.png")); //"template/blog.ftl":指向模板 //"D:/blog1.doc":生成的文件路径以及文件名 TemplateUtil.createFile(map,"template/blog.ftl","D:/blog1.doc"); }
运行之后我们就可以在d盘找到blog.doc文件啦