pdf 文档自动生成方法
优质
小牛编辑
131浏览
2023-12-01
安装配置KnpSnappyBundle扩展
先安装扩展,执行:
composer require knplabs/knp-snappy-bundle
再安装wkhtmltopdf工具
wget http://download.gna.org/wkhtmltopdf/0.12/0.12.3/wkhtmltox-0.12.3_linux-generic-amd64.tar.xz
xz -d wkhtmltox-0.12.3_linux-generic-amd64.tar.xz
拷贝二进制到/usr/local/bin
因为linux存在无法转中文的问题,所以下载一个simsun.ttc拷贝到/usr/share/fonts即可
创建pdf链接
配置路由如下:
pdf_latest:
path: /pdf/{title}_{year}_{month}_{day}.pdf
requirements:
"year": "201[6-9]"
"month": "[01]\d"
"day": "[0123]\d"
defaults: { _controller: AppBundle:Pdf:generate }
这里的title后面会作为查数据的关键词来形成一类pdf(这样做的是为了按不同类别把文章生成多个pdf)
这里的年月日后面会用来限定博客的最后更新日志,这样这个pdf会看起来定期有更新
配置里的requirements通过正则表达式约束url的值
创建PdfContoller
如下:
<?php
namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Kernel;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Query;
use Doctrine\Common\Persistence\ObjectRepository;
class PdfController extends Controller
{
/**
* @var ObjectRepository
*/
protected $blogPostRepository;
/**
* @var Kernel
*/
protected $kernel;
/**
* @var EntityManager
*/
protected $em;
public function generateAction(Request $request, $title, $year, $month, $day)
{
$time = mktime(0, 0, 0, $month, $day, $year);
$now = time();
if ($time > $now) {
return new Response('file not exist');
}
$this->kernel = $this->get('kernel');
$rootDir = $this->kernel->getRootDir();
$pdfFilePath = $rootDir . '/../web/pdf/' . $title . '/' . $year . "-" . $month . "-" . $day . '.pdf';
$this->em = $this->get('doctrine.orm.entity_manager');
$qb = $this->em->createQueryBuilder();
$q = $qb->select(array('blogpost'))->from('AppBundle:BlogPost', 'blogpost')
->where($qb->expr()
->lt('blogpost.createTime', '\'' . date("Y-m-d 00:00:00", $time) . '\'')
)
->andWhere($qb->expr()
->like('blogpost.title', '\'%' . $title . '%\'')
)
->getQuery();
if (file_exists($pdfFilePath)) {
unlink($pdfFilePath);
}
$this->get('knp_snappy.pdf')->generateFromHtml(
$this->renderView(
'pdf/generate.html.twig',
array('blogposts' => $q->getresult())
),
$pdfFilePath
);
return new BinaryFileResponse($pdfFilePath);
}
}
讲解一下:
首先要判断指定的年月日是不是超过当前日期,如果超过会返回错误
接下来确定生成本地的pdf文件路径
然后用url获取到的年月日和title来查数据库,获取博客集合
再利用knp_snappy.pdf服务把网页渲染好并转成pdf
最后返回pdf文件作为Response
创建渲染模板generate.html.twig
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<!-- 新 Bootstrap 核心 CSS 文件 -->
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">
<!-- 可选的Bootstrap主题文件(一般不用引入) -->
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
<!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
<script src="https://cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script>
<!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
<script src="https://cdn.bootcss.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
</head>
<body>
{% for blogpost in blogposts %}
<div class="container-fluid">
<div class="row">
<div class="col-sm-3 col-xs-1"></div>
<div class="col-sm-6 col-xs-10">
<div class="row">
<h1><a href="http://{{ app.request.httphost }}{{ path('blog_show', {'blogId':blogpost.id}) }}"
target="_blank">{{ blogpost.title }}</a></h1>
</div>
<div class="row">
<small>发表于 {{ blogpost.createTimeStr }}</small>
</div>
<div class="row">
<hr/>
</div>
<div class="row">
<br/>
{{ blogpost.body|replace({'img alt="" src="':"img src=\"http://#{app.request.httphost}"})|raw }}
</div>
</div>
</div>
</div>
<br/>
<br/>
{% endfor %}
</body>
</html>
讲解一下:
这依然是按照html的方式加载bootstrap框架,遍历所有的博客并展示他们的title、createTimeStr、body等
注意:这里的a和img里的链接都是用完整的url,这是因为如果用相对的url则wkhtmltopdf无法生成超链接和图片
直接访问http://localhost/app_dev.php/pdf/全栈工程师/2016-06-07.pdf就可以直接下载到2016-06-07以前title包含“全栈工程师”的所有博客拼成的一个pdf文件啦