相信有同学已经发现了,当预览生成为PDF时,会发现一个非常严重的问题,那就是只显示英文与数字,中文完全无法显示。如下图。
选择用PDF预览,会打开电脑上安装的PDF查看软件。
生成的PDF文件中,所有中文都无法显示,这是模板预览生成的PDF文件,如果用JAVA工程生成相信也是一样无法看到中文,这跟我们想要的效果明显不符。
我们的模板设计软件Jaspersoft studio是可以选择字体,如果我们选择一个中文字体,会不会可以在预览中看到中文呢?注意,这里只是针对于Jaspersoft studio的预览查看,并不适用于Java工程中代码生成PDF无法显示中文问题。
很奇怪的地方是上面的六个字体样式与下面的字体样式有一个明显的分隔线,它们有什么不同吗?这就是我们要讲解的重点。
上面的六个字体样式明显没有中文字体,那我们只好选择下面的字体了。
将语文的字体设为微软雅黑,再看看预览是否有效果。
源码里的描述如下:
生成预览
语文依然没有显示,这个方法无效果。
在工程目录,有三个自动导入的项目包,如下图,一个是Java JRE,其余两个都是Jasperreport工程相差的包
我们的重点是JasperReports Library里面的fonts字体包,展开该Jar包。
里面放置了许多.ttf字体文体,而这些字体的名称与模板的选择字体框上方的字体基本一致。
由此可以大胆猜测,这个fonts包里放的字体就是模板实际用于生成文件所用的字体,我们在模板里选择的字体在源码中可以看到是一个标签”fonts-name=dejavvu..”,当Jasperreports解析模板文件时,会根据这个字体的名字然后去fonts字体包中查找对应的字体,如果用就使用该字体,如果没有就使用一个默认的字体。
我们可以在studio中导入一个中文字体,来实现pdf预览可查看中文的效果。
名字可以随便取,然后选取电脑上下载好的字体文件ttf格式的。
最重要的一步,选择PDF ENconding一定要选择这个选项Identity-H,要不然依然是显示空白的中文。至于为什么选择这个,是因为我在上一步选择的是从文件夹里导入字体文件,然后将电脑系统自带的Font文件夹给选中,结果是将所有几乎上百个是.tff格式的字体都给导进去了。
选择文件夹导入,如果是ttf的软件会自动分析pdf encoding,所以可以从这个方法知道华文宋体的编码方式。
为了显示方便,所以我删掉了没用的字体,只留下了华文宋体。
现在来看看预览效果如何,现在选取字体的时候华文宋体出现在了上面的六个默认字体中了。
只有设置了华文字体的语文才正常地显示,说明PDF要想显示中文需要设置中文格式的字体。
一开始我遇到这个问题时,网上搜的方法几乎都是将ItextAsian导入至工程中,事实上这并没有什么效果。虽然我们的Pdf是用Itext生成了,但是在Jasperreports 6.3.1里面加入补充包不起作用。
现在我们来试验一下IText是否起作用,模板是最开始的需要传入参数的那个,我将语文数学设为华文宋体。
我的Jar包中是有这个ItextAsian的。
运用代码生成Pdf文档。
package test;
import java.util.HashMap;
import net.sf.jasperreports.engine.JREmptyDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
public class JasperCreatePdf {
public static void main(String[] args) {
//1.设定模板二进制文件路径,一定要可以通过该路径找到该文件
String reportPath="./src/JasperSample.jasper";
//2.设定报表的外部参数,map集合,这里要注意map的key值一定要与模板里Parameters的名字一致
HashMap map=new HashMap<>();
map.put("name", "王小明");
map.put("id", "2017022301");
map.put("rank", "32");
map.put("yuwen", "81");
map.put("shuxue", "102");
map.put("english", "123");
map.put("shengwu", "67");
map.put("wuli", "75");
map.put("huaxue", "86");
map.put("rankone", "21");
try {
//3.通过JasperFillManager工具进行填充报表,填充成功后会生成一个JasperPring文件,该文件用于输出
JasperPrint jasperPrint=JasperFillManager.fillReport(reportPath, map,new JREmptyDataSource());
//4.设定目标文件输出的路径
String desFilePath="./src/JasperPdfDemoTest.pdf";
//5.通过JasperExportManager管理工具进行报表输出文档,此外设定为输出PDF文件
JasperExportManager.exportReportToPdfFile(jasperPrint,desFilePath);
} catch (JRException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
刷新工程,可以看到生成的Pdf文档,依然是中文一片空白,所以ITextAsian的方案无用。
当初在网上找过许多方法,最后找到一个靠谱的,它的解决方案就是将我们的中文字体包加入到Fonts这个Jar包中,然后导入工程中,这样就可以一劳永逸解决字体的问题,至于ITextAsian则是因为从Jasperreports6.0开始就不支持这种方法解决中文问题。下面来为大家介绍如何将中文字体加入到Fonts字体包中。
这个文件就是用以声明字体文件的,从它的结构很容易就可以看出一个命名字体的标签fontFamilly,下面的子标签是normal,bold,italic即正常,粗体,斜体对应的字体文件,还有pdfEncoding标签,exportFonts标签,是不是与上面我们导入字体的设置差不多。
下面的文件我只保留了一个字体说明,省去了自带的两个字体,以便于说明。
<fontFamilies>
<fontFamily name="DejaVu Sans">
<normal>net/sf/jasperreports/fonts/dejavu/DejaVuSans.ttfnormal>
<bold>net/sf/jasperreports/fonts/dejavu/DejaVuSans-Bold.ttfbold>
<italic>net/sf/jasperreports/fonts/dejavu/DejaVuSans-Oblique.ttfitalic>
<boldItalic>net/sf/jasperreports/fonts/dejavu/DejaVuSans-BoldOblique.ttfboldItalic>
<pdfEncoding>Identity-HpdfEncoding>
<pdfEmbedded>truepdfEmbedded>
<exportFonts>
<export key="net.sf.jasperreports.html">'DejaVu Sans', Arial, Helvetica, sans-serifexport>
<export key="net.sf.jasperreports.xhtml">'DejaVu Sans', Arial, Helvetica, sans-serifexport>
exportFonts>
fontFamily>
<fontFamily name="SansSerif">
<exportFonts>
<export key="net.sf.jasperreports.html">'DejaVu Sans', Arial, Helvetica, sans-serifexport>
<export key="net.sf.jasperreports.xhtml">'DejaVu Sans', Arial, Helvetica, sans-serifexport>
exportFonts>
fontFamily>
fontFamilies>
从上面的标签里面可以看出,我们的字体文件就放在这个文件夹里面,现在我们来看看里面有什么。
里面全都是.ttf文件,与标签里的内容一一对应。
我们将一个中文字体复制至该文件夹,接下来的事情就很简单了,我们只需复制xml里面的声明标签,改下名字,就可以配置好中文字体了。
其实这一步很简单,我们只需要参照上面的字体信息就可以配置好我们的自定义字体了,但是要注意名字一定要与模板里的选用的字体名字一致,否则是找不到该字体的。
<fontFamilies>
<fontFamily name="DejaVu Sans">
<normal>net/sf/jasperreports/fonts/dejavu/DejaVuSans.ttfnormal>
<bold>net/sf/jasperreports/fonts/dejavu/DejaVuSans-Bold.ttfbold>
<italic>net/sf/jasperreports/fonts/dejavu/DejaVuSans-Oblique.ttfitalic>
<boldItalic>net/sf/jasperreports/fonts/dejavu/DejaVuSans-BoldOblique.ttfboldItalic>
<pdfEncoding>Identity-HpdfEncoding>
<pdfEmbedded>truepdfEmbedded>
<exportFonts>
<export key="net.sf.jasperreports.html">'DejaVu Sans', Arial, Helvetica, sans-serifexport>
<export key="net.sf.jasperreports.xhtml">'DejaVu Sans', Arial, Helvetica, sans-serifexport>
exportFonts>
fontFamily>
<fontFamily name="华文宋体">
<normal>net/sf/jasperreports/fonts/dejavu/STSONG.TTFnormal>
<bold>net/sf/jasperreports/fonts/dejavu/STSONG.TTFbold>
<italic>net/sf/jasperreports/fonts/dejavu/STSONG.TTFitalic>
<boldItalic>net/sf/jasperreports/fonts/dejavu/STSONG.TTFboldItalic>
<pdfEncoding>Identity-HpdfEncoding>
<pdfEmbedded>truepdfEmbedded>
<exportFonts>
<export key="net.sf.jasperreports.html">'华文宋体', Arial, Helvetica, sans-serifexport>
<export key="net.sf.jasperreports.xhtml">'华文宋体', Arial, Helvetica, sans-serifexport>
exportFonts>
fontFamily>
<fontFamily name="SansSerif">
<exportFonts>
<export key="net.sf.jasperreports.html">'DejaVu Sans', Arial, Helvetica, sans-serifexport>
<export key="net.sf.jasperreports.xhtml">'DejaVu Sans', Arial, Helvetica, sans-serifexport>
exportFonts>
fontFamily>
<fontFamily name="华文宋体">
<exportFonts>
<export key="net.sf.jasperreports.html">'华文宋体', Arial, Helvetica, sans-serifexport>
<export key="net.sf.jasperreports.xhtml">'华文宋体', Arial, Helvetica, sans-serifexport>
exportFonts>
fontFamily>
fontFamilies>
这一步是比较关键的,我们只需将刚才配置好的xml文件与放置字体文件的文件夹打包成一个Jar包,注意一定要出到最外面的fonts文件夹中,因为我们的Jar包需要一个完整的路径包。
下面我们用jar命令来生成一个Jar包
jar cvf fonts.jar *
这句话的意思是将当前目录下的所有文件输出到名为fonts.jar的文件上。
导入新的fonts.jar后,运行java工程,查看pdf文件。
最后提供该章生成的包含华文宋体的fonts.jar包。
下载传送门