网站和移动应用程序的开发人员通常需要控制PDF页面的准备,以便打印或通过邮件将其发送给客户。
PDF文件可以完全控制页面上文本和图形的显示。 不幸的是,PHP,JS(Web),Java或Swift(分别为Android和iOS)的标准工具中没有包含用于生成动态填充PDF文件的库。 在本文中,我想向您介绍用于生成PDF文件的开源解决方案。
JasperReports是一个开源Java库,用于生成动态填充的文件。 它具有许多用于创建复杂报告表格的工具,包括PDF格式,但也可以使用其他格式:RTF,DOCX,HTML,XLS,XLS,CSV和XML。 换句话说,开发一种表格,制作一种布局就足够了,并且可以将其导出为上述任何一种格式。
也有不错的库,例如PHP的PDFLib(商业版)及其PDFLib-Lite的开源版本。 确实,该库非常昂贵,并且lite版本仅在源代码中分发,并且在开发环境中安装它时,此限制可能会成为问题。
PDFbox是另一个用于处理PDF文档的开源Java库。 它使您可以创建新的PDF文档,管理现有文档并能够从中提取内容。 但是与JasperReports不同,它没有UI(用户界面)。
我认为JasperReports在与报告相关的大型项目中特别有用,不仅限于PDF格式。 它具有在项目中实现它所需的一切:轻松创建复杂的报表表单,方便布局的UI,服务器应用程序以及与前端的简单集成。
在本文中,我将介绍以下主题:
- 安装开发环境和服务器应用程序。
- 创建自动从数据库填充的PDF文件。
- 将服务器应用程序与前端集成,以获取创建的PDF。
要在您的项目中开始使用JasperReports,您需要下载两个应用程序:JaspersoftStudio(以下称为
工作环境 )和JasperServer(称为
服务器应用程序) 。
JaspersoftStudio是具有内置JasperReports Java库的基于Eclipse的开发环境,在其中开发了动态或静态PDF文件:例如,票据,收据,合同,分析图等。
JasperServer是一个服务器应用程序,从JaspersoftStudio部署和存储文件。 可以从移动或Web应用程序访问它们。 JasperServer有一个UI,使用它可以查看报告,为不同用户创建帐户并为他们提供适当的访问权限。 您还可以配置邮件列表到电子邮件(计划程序)。
设置工作环境和服务器应用程序
您可以使用上面的链接下载和安装应用程序。 设置两个应用程序后,有必要建立从工作环境到服务器应用程序的连接。
服务器→创建JasperReports服务器连接→指定首选的服务器名称,
URL ,用户名和密码。 单击
测试连接以验证与服务器的连接已建立。 如果看到
成功 ,请继续。

创建一个动态填充的PDF并将其发布
我们安装了开发环境,服务器并在它们之间建立了连接。 现在,让我们创建一个动态填充的原始PDF文件,该文件在启动(生成)时将从PostgreSQL中获取数据,并将其安装在服务器应用程序上。
首先,您应该将数据源(在我们的示例中为PostgreSQL)固定到工作环境中,PDF将在该工作环境中获取数据。 然后,让我们开始开发第一个PDF文件。
数据适配器→创建数据适配器→数据库JDBS连接并指定连接数据:
- JDBC驱动程序 -PostgreSQL(org.postgresql.Driver)。 如果您的DBMS没有驱动程序,则可以在“驱动程序类路径”选项卡中安装必要的驱动程序。
- JDBC URL-由它们的主机,端口和数据库名称组成。
- 用户名和密码 -从您的DBMS帐户登录。

我们单击已经熟悉的“
测试”按钮,并成功(成功)连接数据库
-Finish 。
从该数据库中,将在生产环境中填充PDF。 由于我们计划将第一个PDF文件部署到服务器,因此让我们将相同的数据源安装到服务器应用程序中:
数据源→添加资源→数据源,然后重复以上所有步骤。
现在您可以创建PDF了。 JasperReports中的源以JRXML格式存储-这是具有有线标签和JasperReports API可以使用的属性的XML。
单击
文件→新建→Jasper报告→空白A4→指定JRXML文件的名称→完成 。

创建新项目后,您将看到以下图片:

七个不同的块-每个块都有自己的行为,这些行为与其他块不同。 您可以在
文档中阅读有关此内容的更多信息。 通过单击源代码,您可以看到这些块的结构:
<?xml version="1.0" encoding="UTF-8"?> <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="Example" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="ae9517f6-ff0b-41bb-a8dc-82196190e940"> <queryString> <![CDATA[]]> </queryString> <background> <band splitType="Stretch"/> </background> <title> <band height="79" splitType="Stretch"/> </title> <pageHeader> <band height="35" splitType="Stretch"/> </pageHeader> <columnHeader> <band height="61" splitType="Stretch"/> </columnHeader> <detail> <band height="125" splitType="Stretch"/> </detail> <columnFooter> <band height="45" splitType="Stretch"/> </columnFooter> <pageFooter> <band height="54" splitType="Stretch"/> </pageFooter> <summary> <band height="42" splitType="Stretch"/> </summary> </jasperReport>
因此,让我们删除五个额外的块,仅保留两个:标题和详细信息。
删除按钮(Windows)或
Backspace (OS X)将帮助我们完成此任务。
现在添加两个元素。 您可以通过两种方式添加新元素:在XML结构中注册容器(“
源”按钮),或从右上方的“
调色板面板”窗口-静态文本中拖动所需的元素,其中将包含字段名称和文本字段,在其中填充从数据库中提取的变量字段:
<?xml version="1.0" encoding="UTF-8"?> <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="Example" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="ae9517f6-ff0b-41bb-a8dc-82196190e940"> <queryString> <![CDATA[]]> </queryString> <background> <band splitType="Stretch"/> </background> <title> <band height="30" splitType="Stretch"> <staticText> <reportElement x="0" y="0" width="100" height="30" uuid="7b697ed9-f52a-483c-965e-f0b2dc6130c1"/> <text> <![CDATA[Static Text]]> </text> </staticText> </band> </title> <detail> <band height="169" splitType="Stretch"> <textField> <reportElement x="0" y="0" width="100" height="20" uuid="41002e0b-ddb2-4e4b-a049-10810ab51208"/> <textFieldExpression> <![CDATA["Text Field"]]> </textFieldExpression> </textField> </band> </detail> </jasperReport>
可以在
queryString标记中编写数据库中的查询,也可以单击“数据集
和查询编辑器”对话框按钮。 之后,将打开一个新窗口,您需要在其中选择数据源(1),编写查询(2)并声明字段变量。
读取字段按钮(3)将在
有效请求后自动读取所有字段。 要查看数据,请单击
数据预览 (4)。

太好了! 我们得到了四个String类型的字段,现在我们几乎可以对它们执行任何操作。 例如,我们只列出它们并写一些逻辑。
我们在“静态文本”元素中打印必填字段的名称,并将其放置在“标题”容器中。 我们将在“细节”容器的“文本字段”元素中指示变量字段,因为它们会相乘。 我们的PDF将显示姓名,城市和电子邮件地址。 为了不感到无聊,让我们在文本字段元素中使用第四个字段(客户的性别,性别)编写一个简单的逻辑。
我们执行以下操作:如果委托人是女性,则如果女士是女士,则将在姓名前添加女士。 为此,请使用Java三元运算符:
<textFieldExpression> <![CDATA[$F{sex}.equals( "male" )?"Mr. "+$F{name}:"Mrs. "+$F{name}]]> </textFieldExpression>
通过单击“
源”按钮旁边的“
预览” ,可以看到结果:

从屏幕截图中可以看到,PDF已成功组装:它获取了所有值并应用了逻辑,正确放下了Mrs. 和先生
我们还将获取City输入参数,以便可以按城市过滤数据。 这可以通过单击“大纲”窗口中的“
参数”→“创建参数 ”,或通过添加具有
名称和
类属性的新
参数标签来完成:
<parameter name="City" class="java.lang.String"/>
仅保留将参数添加到SQL查询中:
SELECT Id, name, sex, city, email FROM users WHERE city = $P{City}
我们将值San Francisco传递给City参数(在下一段中我将告诉您如何操作),然后点击
数据预览以查看结果。
通过成功过滤数据收集了PDF。 我们走得更远由于我们已经有了一个动态填充的PDF文件,因此我们可以将其上传到服务器,以便与前端应用程序进一步集成。 为此,请单击“将
报告发布到JasperReports服务器”按钮→双击以打开服务器→选择要在其中下载PDF的服务器文件夹(在本例中为
Reports )→
下一步→从存储库中选择数据源→选择先前在服务器应用程序上创建的数据源→
完成 。
前端整合
JasperReports API包括其自己的用于客户端与服务器交互的RESTful实现
-REST v2 。 如果不合适,则可以使用简单的对象访问协议
SOAP 。
我们将考虑REST v2。
可以使用四种主要的CRUD(创建-读取-更新-删除)操作方法:GET(获取),POST(添加,更改,删除),PUT(添加,替换),DELETE(删除)。 所有详细信息都可以在上面链接的文档中找到。
我们将考虑本文更通用和相关的GET方法。
http://<host>:<port>/jasperserver[pro]/rest_v2/reports/path/to/report.<format>?<arguments>
上面是一个
同步请求,通过该请求,您可以在一个请求响应中获得文件(完成的PDF)输出(您可以在
此处找到异步调用)。
我认为主机和端口一切都清楚了,
/ reports / path / to / report是被调用文件的URI。 由于我们将PDF文件的源代码(Example.jrxml)部署到了报表服务器文件夹,因此URI的完整版本将为:/ reports / reports / Example。
格式是一种格式(在我们的示例中为PDF)。
参数是参数。
上面,我们添加了City参数,并将其在请求中传递给值San Francisco,以过滤该城市的数据。
如果呼叫不是来自授权区域,则需要添加另外两个参数/属性:
j_username和
j_password (用于授权的日志传递)。 默认情况下,服务器上的用户名和密码为
jasperadmin 。
因此,我们得到以下URL:
http://localhost:8080/jasperserver/rest_v2/reports/reports/Example.PDF?city=San Francisco&j_username=jasperadmin&j_password=jasperadmin
这样我们得到了一个已经生成的PDF。 例如,当您通过浏览器的地址栏调用此URL时,文件应自动下载。
您可能需要显示PDF图像。 例如,如果客户只想查看文件,则可以PNG格式显示文档,如果要下载,则可以PDF格式显示。
以Java为例,使用PDFbox库,我们将了解如何从外部应用程序生成和选择PDF文件,然后将其转换为PNG。
下面是
PullPDF类,其中的一种方法采用URL作为参数。
import java.awt.image.BufferedImage; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.URL; import java.util.Base64; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.rendering.ImageType; import org.apache.pdfbox.rendering.PDFRenderer; import org.apache.pdfbox.tools.imageio.ImageIOUtil; public class PullPDF { public String ConvertPDF2PNG(String valuefromParam) throws IOException { BufferedInputStream input_file = new BufferedInputStream(new URL(valuefromParam).openStream()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { PDDocument document = PDDocument.load(input_file); PDFRenderer pdfRenderer = new PDFRenderer(document); for (int page = 0; page < document.getNumberOfPages(); ++page) { BufferedImage bim = pdfRenderer.renderImageWithDPI(page, 300, ImageType.RGB); ImageIOUtil.writeImage(bim, "png", baos); baos.flush(); byte[] encodedBytes = Base64.getEncoder().encode(baos.toByteArray()); valuefromParam = new String(encodedBytes); } } catch (Exception e) { } return valuefromParam; } }
您可以使用例如Spring Framework获得相同的结果。 但是我试图展示一种通用的方法,在使用Java时可以在Android和Web上应用。
结论
如果要自动生成在线商店的简单支票,并且创建时间有限,那么建议您使用项目的本机工具或熟悉的框架。 由于花了很多时间安装JasperReports,因此可能不了解熟悉用于开发更复杂的报告表单的文档。 在其他情况下,JasperReports是报告自动化的良好开源解决方案。