vue +SpringBoot + FreeMarker + FlyingSaucer 实现PDF在线预览、打印、下载
在此,首先感谢这篇链接的博主,无私奉献他的力量感谢互联网的无私和真诚我借助此文完成了我的需求,下载pdf简历 ,所以在此记录一笔项目的大概功能如下 vue的页面点击下载按钮就能下载简历 ,谷歌浏览器浏览器中点开这个简历如下这样的, 里面还有打印和下载一首先你需要引入如下 pom依赖<!-- freemarker依赖 --><dependency><gr...
·
在此,首先感谢
这篇链接的博主
我借助此文完成了我的需求,下载pdf简历 ,所以在此记录一笔
项目的大概功能如下 vue的页面点击下载按钮就能下载简历 ,谷歌浏览器
浏览器中点开这个简历如下这样的, 里面还有打印和下载
一 首先你需要引入如下 pom依赖
<!-- freemarker依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- FlyingSaucer依赖 -->
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf</artifactId>
<version>9.1.12</version>
</dependency>
二 工具类
接着 工具类 : 实在强大 ,可根据自身业务修改
package com.ruoyi.common.util; import com.lowagie.text.pdf.BaseFont; import com.platform.domain.ProcessJobresumeinfo; import freemarker.template.Template; import freemarker.template.TemplateException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; import org.w3c.dom.Document; import org.xhtmlrenderer.pdf.ITextFontResolver; import org.xhtmlrenderer.pdf.ITextRenderer; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import java.io.*; /** * 功能:pdf处理工具类 * */ public class PdfUtils { private PdfUtils() { } private static final Logger LOGGER = LoggerFactory.getLogger(PdfUtils.class); /** * 按模板和参数生成html字符串,再转换为flying-saucer识别的Document * * @param templateName freemarker模板名称 * @param variables freemarker模板参数 * @return Document */ private static Document generateDoc(FreeMarkerConfigurer configurer, String templateName, ProcessJobresumeinfo variables) { Template tp; try { tp = configurer.getConfiguration().getTemplate(templateName); } catch (IOException e) { LOGGER.error(e.getMessage(), e); return null; } StringWriter stringWriter = new StringWriter(); try(BufferedWriter writer = new BufferedWriter(stringWriter)) { try { tp.process(variables, writer); writer.flush(); } catch (TemplateException e) { LOGGER.error("模板不存在或者路径错误", e); } catch (IOException e) { LOGGER.error("IO异常", e); } DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); return builder.parse(new ByteArrayInputStream(stringWriter.toString().getBytes())); }catch (Exception e){ LOGGER.error(e.getMessage(), e); return null; } } /** * 核心: 根据freemarker模板生成pdf文档 * * @param configurer freemarker配置 * @param templateName freemarker模板名称 * @param out 输出流 * @param info freemarker模板参数 * @throws Exception 模板无法找到、模板语法错误、IO异常 */ private static void generateAll(FreeMarkerConfigurer configurer, String templateName, OutputStream out,ProcessJobresumeinfo info) throws Exception { if (info==null) { LOGGER.warn("警告:简历模板参数为空!"); return; } ITextRenderer renderer = new ITextRenderer(); Document doc = generateDoc(configurer, templateName, info); renderer.setDocument(doc, null); //设置字符集(宋体),此处必须与模板中的<body style="font-family: SimSun">一致,区分大小写,不能写成汉字"宋体" ITextFontResolver fontResolver = renderer.getFontResolver(); fontResolver.addFont("simsun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); //展现和输出pdf renderer.layout(); renderer.createPDF(out, false); renderer.finishPDF(); //完成pdf写入 } /** * pdf下载 * * @param configurer freemarker配置 * @param templateName freemarker模板名称(带后缀.ftl) * @param info 模板参数集 * @param response HttpServletResponse * @param fileName 下载文件名称(带文件扩展名后缀) */ public static void download(FreeMarkerConfigurer configurer, String templateName, ProcessJobresumeinfo info, HttpServletResponse response, String fileName) { // 设置编码、文件ContentType类型、文件头、下载文件名 response.setCharacterEncoding("utf-8"); response.setContentType("multipart/form-data"); try { response.setHeader("Content-Disposition", "attachment;fileName=" + new String(fileName.getBytes("gb2312"), "ISO8859-1")); } catch (UnsupportedEncodingException e) { LOGGER.error(e.getMessage(), e); } try (ServletOutputStream out = response.getOutputStream()) { generateAll(configurer, templateName, out, info); out.flush(); } catch (Exception e) { LOGGER.error(e.getMessage(), e); } } /** * pdf预览 * * @param configurer freemarker配置 * @param templateName freemarker模板名称(带后缀.ftl) * @param info 模板参数集 * @param response HttpServletResponse */ public static void preview(FreeMarkerConfigurer configurer, String templateName, ProcessJobresumeinfo info, HttpServletResponse response) { try (ServletOutputStream out = response.getOutputStream()) { generateAll(configurer, templateName, out, info); out.flush(); } catch (Exception e) { LOGGER.error(e.getMessage(), e); } } }
注意 这里有三个东西,resources下的templates加入pdfResume.ftl模板 (自己加) , 还有一个simsun.ttc字体,这个说是window系统有,但是我系统并没有,可以百度搜索下载资源,这里不做分享
flt模板
<!DOCTYPE html>
<html>
<head lang="en">
<title>${name}简历信息</title>
<style>
@page {
size: 210mm 297mm; /*设置纸张大小:A4(210mm 297mm)、A3(297mm 420mm) 横向则反过来*/
margin: 0.25in;
padding: 1em;
@bottom-center {
content: "xxx 版权所有";
font-family: SimSun;
font-size: 12px;
color: red;
};
@top-center {
content: element(header)
};
@bottom-right {
content: "第" counter(page) "页 共 " counter(pages) "页";
font-family: SimSun;
font-size: 12px;
color: #000;
};
}
</style>
</head>
<body style="font-family: 'SimSun'">
<h2>个人简历</h2><br/>
<div>
<label>姓名: ${name}</label><br/>
</div>
<div>
<label>性别:
<#if sex==0>
未知
</#if>
<#if sex==1>
男
</#if>
<#if sex==2>
女
</#if>
</label><br/>
</div>
<#if birthday??>
<div>
<label>出生年月: ${birthday?string("yyyy-MM-dd")}</label>
</div>
</#if>
<#if phone??>
<div>
<label>联系电话: ${phone} </label>
</div>
</#if>
<#if weixin??>
<div>
<label>微信号: ${weixin}</label>
</div>
</#if>
<#if advantage??>
<div>
<label>个人优势: ${advantage}</label>
</div><br/>
</#if>
<h3>求职期望</h3>
<#if hopes?exists>
<#list hopes as hope>
<h4>求职期望 ${hope_index+1}</h4>
<#if hope.jobtype??>
<div>
<label>求职类型: ${hope.jobtype}</label>
</div>
</#if>
<#if hope.jobcity??>
<div>
<label>工作城市: ${hope.jobcity}</label>
</div>
</#if>
<#if hope.jobtype??>
<div>
<label>期望职位: ${hope.jobtype}</label>
</div>
</#if>
<#if hope.job??>
<div>
<label>期望行业: ${hope.job}</label>
</div>
</#if>
<div>
<label>薪资要求:
<#if hope.paymin??>
${hope.paymin}
</#if>
<#if hope.paymax??>
${hope.paymax}
</#if>
</label>
</div><br/><br/>
</#list>
</#if>
<h3>工作经历</h3>
<#if workExpers?exists>
<#list workExpers as we>
<h4>工作经历 ${we_index+1}</h4>
<#if we.cname??>
<div>
<label>公司名称: ${we.cname}</label>
</div>
</#if>
<#if we.business??>
<div>
<label>所属行业: ${we.business}</label>
</div>
</#if>
<#if we.addtime??>
<div>
<label>入职时间: ${we.addtime}</label>
</div>
</#if>
<#if we.endtime??>
<div>
<label>离职时间: ${we.endtime}</label>
</div>
</#if>
<#if we.jobtitle??>
<div>
<label>职位名称: ${we.jobtitle}</label>
</div>
</#if>
<#if we.department??>
<div>
<label>所属部门: ${we.department}</label>
</div>
</#if>
<#if we.jobcontent??>
<div>
<label>工作内容: ${we.jobcontent}</label>
</div>
</#if>
<br/>
</#list>
</#if>
<h3>项目经验</h3>
<#if projectExps?exists>
<#list projectExps as pj>
<h4>项目 ${pj_index+1}</h4>
<#if pj.projectname??>
<div>
<label>项目名称: ${pj.projectname}</label>
</div>
</#if>
<#if pj.role??>
<div>
<label>担任角色: ${pj.role}</label>
</div>
</#if>
<#if pj.projectstarttime??>
<div>
<label>项目开始时间: ${pj.projectstarttime}</label>
</div>
</#if>
<#if pj.projectendtime??>
<div>
<label>项目结束时间: ${pj.projectendtime}</label>
</div>
</#if>
<#if pj.projectinfo??>
<div>
<label>项目链接: ${pj.projectinfo}</label>
</div>
</#if>
<br/>
</#list>
</#if>
<h3>教育经历</h3>
<#if educations?exists>
<#list educations as ed>
<h4>教育经历 ${ed_index+1}</h4>
<#if ed.schoolname??>
<div>
<label>学校名称: ${ed.schoolname}</label>
</div>
</#if>
<#if ed.education??>
<div>
<label>学历: ${ed.education}</label>
</div>
</#if>
<#if ed.profession??>
<div>
<label>专业: ${ed.profession}</label>
</div>
</#if>
<#if ed.estart??>
<div>
<label>时间段:
${ed.estart} -- ${ed.eend}</label>
</div>
</#if>
<#if ed.schoolexperience??>
<div>
<label>在校经历:
${ed.schoolexperience} </label>
</div>
</#if>
<br/>
</#list>
</#if>
<#if certificate??>
<div>
<label>资格证书:
${certificate} </label>
</div>
</#if>
</body>
</html>
三 web框架自行引入
controller info是简历信息 ,查询数据库那一些操作这里不分享了
/**
* pdf预览
*
* @param request HttpServletRequest
* @param response HttpServletResponse
*/
@RequestMapping(value = "/preview", method = RequestMethod.GET)
public void preview(HttpServletRequest request, HttpServletResponse response) {
String id = request.getParameter("id");
Jobresumeinfo info = infoService.selectinfoById(id);
PdfUtils.preview(configurer,"pdfResume.ftl",info,response);
}
/**
* pdf下载
*
* @param request HttpServletRequest
* @param response HttpServletResponse
*/
@RequestMapping(value = "/download", method = RequestMethod.GET)
public void download(HttpServletRequest request, HttpServletResponse response) {
String id = request.getParameter("id");
Jobresumeinfo info = infoService.selectinfoById(id);
PdfUtils.download(configurer,"pdfResume.ftl",info,response,"简历信息");
}
vue部分
html
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" @click="downPDF(scope.row.user)">下载</el-button>
<el-button
size="mini"
type="text"
@click="handleUpdate(scope.row)"
v-hasPermi="['platform:jobResumeInfo:edit']"
>查看</el-button>
<el-button v-if="scope.row.status == '3' && scope.row.status != '4'"
size="mini"
type="text"
@click="editWorkHours1(scope.row)"
v-hasPermi="['platform:jobResumeInfo:edit']"
>填工时</el-button>
<el-button v-if="scope.row.status != '2' && scope.row.status != '3' && scope.row.status != '4' "
size="mini"
type="text"
@click="refuseSubmitForm1(scope.row)"
v-hasPermi="['platform:jobResumeInfo:edit']"
>婉拒</el-button>
<el-button v-if="scope.row.status != '3' && scope.row.status != '4' "
size="mini"
type="text"
@click="passSubmitForm1(scope.row)"
>通过</el-button>
<!--<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['platform:jobResumeInfo:remove']"
>删除</el-button> -->
</template>
</el-table-column>
js
/** 下载pdf简历 **/
downPDF(row){
var pdfname = row.name + "-"+row.phone;
downPDF(row).then(response => {
console.log(this.pdfUrl)
const elink = document.createElement("a");
elink.href = window.URL.createObjectURL(new Blob([response], {type: `application/pdf`}));
elink.style.display = 'none';
elink.setAttribute('download', pdfname);
document.body.appendChild(elink);
elink.click();
URL.revokeObjectURL(elink.href); // 释放URL 对象
document.body.removeChild(elink);
});
更多推荐
已为社区贡献6条内容
所有评论(0)