springboot下freemarker导出PDF(绝对路径,相对路径加载模板方式)

一、依赖准备

gradle:

implementation(group: 'org.freemarker', name: 'freemarker', version: '2.3.32');

//根据springboot版本来

implementation(group:'org.springframework.boot',name:'spring-boot-starter-freemarker',version: '3.1.5');

maven:


            org.freemarker
            freemarker
            2.3.32

            org.springframework.boot

            spring-boot-starter-freemarker

 二、FreemarkerComponent 、FreemarkerTemplateAbsolutePathLoader 工具组件封装

package com.example.demo;

import freemarker.template.Configuration;
import freemarker.template.Template;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

import java.io.File;

@Component
public class FreemarkerComponent {

    protected static Logger LOG = LoggerFactory.getLogger(FreemarkerComponent.class);

    /**
     *
     */
    private final FreeMarkerConfigurer configurer;
    
    private final ApplicationContext applicationContext;

    public FreemarkerComponent(FreeMarkerConfigurer configurer, ApplicationContext applicationContext) {
        this.configurer = configurer;
        this.applicationContext = applicationContext;
    }

    /**
     * @param templateName 模板名称
     * @param t            对象
     */
    public  String formatTemplate(String templateName, T t) {
        try {
            Template template = configurer.getConfiguration().getTemplate(templateName);
            String txt = FreeMarkerTemplateUtils.processTemplateIntoString(template, t);
            if (LOG.isDebugEnabled()) {
                LOG.debug(txt);
            }
            return txt;
        } catch (Exception e) {
            LOG.error("freemarker format exception", e);
        }
        return null;
    }

    public  String findTemplateByAbsolutePathAndTemplateName(String absolutePath,String templateName,T t) {
        try {
            FreemarkerTemplateAbsolutePathLoader freemarkerTemplateAbsolutePathLoader = applicationContext.getBean(FreemarkerTemplateAbsolutePathLoader.class);
            File source = freemarkerTemplateAbsolutePathLoader.findTemplateSource(absolutePath);
            if(source != null){
                Configuration configuration = configurer.getConfiguration();
                configuration.setDirectoryForTemplateLoading(source);
                Template template = configuration.getTemplate(templateName);
                String text =  FreeMarkerTemplateUtils.processTemplateIntoString(template, t);
                if (LOG.isDebugEnabled()) {
                    LOG.debug(text);
                }
                return text;
            }
        }catch (Exception e){
            LOG.error("freemarker format exception", e);
        }
        return null;
    }
}
package com.aoyuntek.lendlease.components;

import freemarker.cache.TemplateLoader;
import org.springframework.stereotype.Component;

import java.io.*;


/**
 * freemarker根据绝对路径加载文件
 * @author hulei
 */
@Component
public class FreemarkerTemplateAbsolutePathLoader implements TemplateLoader {

    public File findTemplateSource(String absolutePath) {
        return new File(absolutePath);
    }

    public long getLastModified(Object templateSource) {
        return ((File) templateSource).lastModified();
    }

    public Reader getReader(Object templateSource, String encoding)
            throws IOException {
        if (!(templateSource instanceof File)) {
            throw new IllegalArgumentException("templateSource is a: " + templateSource.getClass().getName());
        }
        return new InputStreamReader(new FileInputStream((File) templateSource), encoding);
    }

    @Override
    public void closeTemplateSource(Object templateSource) {

    }
}

三、yaml配置说明

3.1 模板位置
springboot下freemarker导出PDF(绝对路径,相对路径加载模板方式)_第1张图片

根据目录可以看到ftl模板(内容是html)位于resources/templates/email和resources/templates/pdf两个文件夹下

导出PDF用到的是pdf下的两个模板,这里主要是想说明下,yaml中freemarker配置怎么配,多个文件夹下的模板加载

springboot下freemarker导出PDF(绝对路径,相对路径加载模板方式)_第2张图片

 注意freemarker缩进,位于spring层级下

freemarker:
  suffix: .ftl
  template-loader-path: classpath:/templates/pdf,classpath:/templates/email
  #自定义 pdf 绝对路径,可以注释
  template-pdf-absolute-loader-path: D:/code-tunnel-web/tunnel-web/src/main/resources/templates/pdf
  #自定义 email 绝对路径,可以注释
  template-email-absolute-loader-path: D:/code-tunnel-web/tunnel-web/src/main/resources/templates/email
  charset: utf-8

这个配置主要是让freemarker去这两个文件夹下加载所有的模板,具体用到哪个模板需要根据名称来确定,绝对路径有则从绝对路径加载(文末代码中有判断)

四、导出PDF实例

yaml中还有配置,即把各个模板的名称都自定义配置到了yml中

springboot下freemarker导出PDF(绝对路径,相对路径加载模板方式)_第3张图片

 需要传入模板名称时直接通过@Value注解从yaml配置中获取即可,如下图

springboot下freemarker导出PDF(绝对路径,相对路径加载模板方式)_第4张图片

 当然也可以不这么写,直接在用到的时候写模板名称即可,在配置里写是为了方便模板改名,看如下代码

springboot下freemarker导出PDF(绝对路径,相对路径加载模板方式)_第5张图片

打勾的地方是判断有没有从yml获取到绝对路径配置,有则用绝对路径,调用绝对路径查找模板方法

没有则用相对路径加载模板,调用相对路径查找模板方法

springboot下freemarker导出PDF(绝对路径,相对路径加载模板方式)_第6张图片

downloadPDF方法解释:界面勾选一条,则导出一个pdf,勾选超过一条,则把多个pdf压缩成zip

@Override
@SuppressWarnings("unchecked")
public void downloadPDF(HttpServletRequest request, HttpServletResponse response, List ids) throws Exception {
    Map> configMap = (Map>) this.getReviewConfig().getReturnObj();
    if(!Objects.equals(1, ids.size())){
        pdfZipHandle(ids,response,configMap);
    }else if(ids.size() == 1){
        PTTDetail detail = (PTTDetail) this.get(ids.get(0)).getReturnObj();
        response.setContentType("application/octet-stream;charset=utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + new String((detail.getNumber() + ".pdf").getBytes(), StandardCharsets.ISO_8859_1));
        String result = createPDFString(configMap,detail);
        HtmlConverter.convertToPdf(result, response.getOutputStream());
    }
}

private String createPDFString(Map> configMap,PTTDetail detail) throws Exception {
    Map map = new HashMap<>();
    this.reBuildTableValue(detail, configMap);
    map.put("sign", this.groupSign(detail));
    map.put("ptt", detail);
    map.put("orj", JsonUtil.jsonToBean(detail.getOrJson(), ORDetail.class));
    map.put("reviewMap", detail.getReviews().stream().collect(Collectors.groupingBy(Review::getType)));
    map.put("dateTime", this.createPDFDate(detail));
    map.put("attendees", this.createAttendees(detail));
    if(StringUtils.isEmpty(absolutePath)){
        return freemarkerComponent.formatTemplate(this.pttDetailNewTemplate, map);
    }
    return freemarkerComponent.findTemplateByAbsolutePathAndTemplateName(absolutePath,this.pttDetailNewTemplate, map);
}

//pdf压缩zip
private void pdfZipHandle(List selectIds,HttpServletResponse response,Map> configMap) throws IOException {
    response.setHeader("Content-Disposition", "attachment;filename=" + new String(( "PTT.zip").getBytes(), StandardCharsets.ISO_8859_1));
    ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream());
    for (String id : selectIds) {
        try {
            PTTDetail detail = (PTTDetail) this.get(id).getReturnObj();
            // html字符串
            String result = createPDFString(configMap,detail);
            ZipEntry zipEntry = new ZipEntry(String.format("%s.pdf", detail.getNumber()));

            zipOutputStream.putNextEntry(zipEntry);

            PdfDocument pdfDocument = new PdfDocument(new PdfWriter(zipOutputStream),
                    new DocumentProperties());
            //设置流不关闭
            pdfDocument.setCloseWriter(false);

            HtmlConverter.convertToPdf(result, pdfDocument, null);
        } catch (Exception e) {
            LOGGER.error("down zip pdf error");
        }
    }
    zipOutputStream.close();
}

你可能感兴趣的:(pdf)