背景:起初业务当中只用到了填充word模板文件然后进行导出,后来拓展了需求需要在文件上加盖电子签章。加电子签章只能是从pdf文件上来做,所以改用了填充pdf模版最后加盖电子签章。但是填充pdf模板文件的时候对于那种大段落有格式(首行缩进、段间距)的文本填充pdf时无法将原来格式带入进去,所以想到了先填充word模板里然后将其转换成pdf再进行电子签章。
1、业务逻辑代码
QualityConfessBottom confessBottom = qualityConfessBottomService.getById(dto.getId()); Map<String, Object> toMap = BeanUtil.beanToMap(confessBottom); // 填充word模版并获取word输出流 InputStream wordInputStream = FreeMarkerTemplateUtil.fillStreamTemplateMap(QualityExportTemplateEnum.QUALITY_CONFESS_BOTTOM,QingDaMap.wrap(toMap)); // word流转pdf流 InputStream pdfInputStream = AsposeUtil.wordStreamToPdf(wordInputStream);
2、工具类代码
package com.ruoyi.common.utils; import freemarker.cache.ClassTemplateLoader; import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.TemplateExceptionHandler; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletResponse; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.URLEncoder; /** * 自由标记模板跑龙套 * * @author doubelflower * @date 2023/08/08 */ public class FreeMarkerTemplateUtil { private static final Configuration CONFIGURATION; private FreeMarkerTemplateUtil() { } public static Template getTemplate(String templateName) throws IOException { try { return CONFIGURATION.getTemplate(templateName); } catch (IOException var2) { throw var2; } } public static void fillTemplateEntity(String fileName, BaseTemplateExport templateName, Object data) { fillTemplateMap(fileName, templateName, QingDaMap.wrap(QingDaBeanUtil.javaBeanToMap(data))); } public static void fillTemplateMap(String fileName, BaseTemplateExport templateName, QingDaMap data) { try { Template template = getTemplate(templateName.getTemplateName()); HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse(); response.reset(); response.setContentType("application/octet-stream"); response.setCharacterEncoding("UTF-8"); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8")); PrintWriter out = response.getWriter(); template.process(data, out); out.close(); } catch (Throwable var6) { throw new RuntimeException(var6); } } public static InputStream fillStreamTemplateMap(BaseTemplateExport templateName, QingDaMap data) { try { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); OutputStreamWriter writer = new OutputStreamWriter(byteArrayOutputStream); Template template = getTemplate(templateName.getTemplateName()); template.process(data, writer); writer.flush(); return new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); } catch (Throwable var6) { throw new RuntimeException(var6); } } public static void clearCache() { CONFIGURATION.clearTemplateCache(); } static { CONFIGURATION = new Configuration(Configuration.VERSION_2_3_31); CONFIGURATION.setTemplateLoader(new ClassTemplateLoader(FreeMarkerTemplateUtil.class, "/templates")); CONFIGURATION.setDefaultEncoding("UTF-8"); CONFIGURATION.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); } } package com.ruoyi.web.qualitysupervision.enums; import com.ruoyi.common.utils.BaseTemplateExport; import lombok.AllArgsConstructor; /** * 质量监督模板枚举 * * @author doubleflower * @date 2023/04/26 */ @AllArgsConstructor public enum QualityExportTemplateEnum implements BaseTemplateExport { /** * 监督交底 */ QUALITY_CONFESS_BOTTOM { /** * 监督交底 * * @return {@link String} */ @Override public String getTemplateName() { return "qualityConfessBottom.ftl"; } } } package com.ruoyi.common.utils; /** * 基本模板导出 * * @author doubleflower * @date 2023/08/08 */ @FunctionalInterface public interface BaseTemplateExport { /** * 得到模板名称 * * @return {@link String} */ String getTemplateName(); } package com.ruoyi.web.sign; import com.aspose.words.Document; import com.aspose.words.License; import com.aspose.words.SaveFormat; import lombok.SneakyThrows; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; public class AsposeUtil { /** * 加载license 用于破解 不生成水印 * * @author doubleflower * @date 2020/12/25 13:51 */ @SneakyThrows private static void getLicense() { try (InputStream is = AsposeUtil.class.getClassLoader().getResourceAsStream("License.xml")) { License license = new License(); license.setLicense(is); } } /** * word转pdf * * @param wordPath word文件保存的路径 * @param pdfPath 转换后pdf文件保存的路径 * @author doubleflower * @date 2020/12/25 13:51 */ @SneakyThrows public static void wordToPdf(String wordPath, String pdfPath) { getLicense(); File file = new File(pdfPath); try (FileOutputStream os = new FileOutputStream(file)) { Document doc = new Document(wordPath); doc.save(os, SaveFormat.PDF); } } @SneakyThrows public static InputStream wordStreamToPdf(InputStream inputStream) { getLicense(); Document doc = new Document(inputStream); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); doc.save(outputStream, SaveFormat.PDF); return new ByteArrayInputStream(outputStream.toByteArray()); } }
3、其中用到的aspose工具jar包跟认证文件我放到了百度网盘里。微信关注公众号“姓氏头像宝典”,回复aspose即可获取。