简介《Jasper报表制作小技巧》面向使用 Jaspersoft 进行报表开发与维护的 IT 从业者及中初级开发者聚焦报表结构理解与常见制作细节帮助读者减少在字段配置、分组展示和 PDF 输出等环节的试错成本。压缩包内仅含 1 个 docx 文档整体约 599KB便于直接查阅和随用随查。文档围绕 Title、Page Header、Detail、Summary 等七个 Band 说明报表骨架并延伸到 JSON 数据源接入、中文字段 PDF 显示设置、手工新增字段、明细分组、序号列变量、自定义纸张大小及 Crosstab 交叉表等实操要点内容偏重可落地的配置思路与注意事项。目前已有 242 人学习适合需要快速梳理 Jasper 报表制作流程、补齐细节盲区并提升报表输出质量的读者参考。1. Jasper 报表制作小技巧先认清 Band再谈拖控件Jasper 报表制作这件事真正卡人的往往不是拖控件而是 Band 的显示时机、PDF 字体和打印配置这三处。Jasper 报表适合把 JSON 或 SQL 数据快速变成可打印的 PDF、面单、明细表新手能按 Band 拖出第一版熟手更关心分组分页、Crosstab 汇总和菜单挂载后参数是否对齐。如果正准备接手一套已经编译过的模板先别急着改样式先把 Band 高度和字段类型对一遍。很多“预览正常、上传后掉字”的问题根子不在模板丑不丑而在 PDF 字体属性和查询条件 JSON 没有落到同一个字段名上。下面按结构、数据源、PDF 与交叉表、打印配置、避坑、验证的顺序拆尽量把每个参数落到具体位置。2. Band 结构落地Title、Page Header、Detail 与 Summary 的显示边界2.1 七个 Band 的显示时机与典型放置物报表设计器打开后左侧大纲树和中间设计区会同时出现一堆 Band。刚接触时最容易犯的错是把页眉内容放进 Title或者把合计值塞进 Detail预览时看着差不多一导出多页 PDF 就露馅。Band 的本质是“显示时机 重复范围”不是普通的容器。先把下面这张表对一遍再动手拖控件。Band出现位置典型内容容易踩的点Title整个报表第一页最上面报表大标题、单位、打印时间以为每页都出现结果第二页消失Page Header每页上部页码、创建人、公共说明第一页会排在 Title 下面不是最顶端Column Header每页列名区域列名称不放列数据分组后忘了隐藏导致每页重复列头Detail每条记录重复销售记录、明细行把合计放这里每行都算一遍Column Footer列级统计列小计、列说明与 Page Footer 混用统计范围错Page Footer每页最下端页码、页级说明页码变量放错重置类型Summary最后一页 Detail 之后整表合计、汇总以为每页都出实际只出一次Group Header/Footer每个分组前后组说明、组统计组头高度没设 0多出空白页Last Page Footer最后一页最后部分最后一页专用签章与 Page Footer 同时出现位置重叠Title 只在整个报表的第一页最上面显示这一点和 Page Header 有本质区别。Page Header 每页都出现第一页时它排在 Title 下面从第二页开始才跑到页面最上端。页码、创建时间、创建人这些公共要素放 Page Header 比较稳报表大标题放 Title不要指望它每页重复。Column Header 放的是列名不是列数据这个边界一旦混淆后面做分组时会把列名拖进 Detail导致每一行都重复一遍表头。Detail 是报表内容段放需要重复出现的内容比如销售记录、入库明细。Column Footer 放列级别的统计值或列说明Page Footer 放页级别的统计值或页说明Summary 放整个报表最后一页的合计。Group Header 和 Group Footer 是分组前后的区域按月份、按店铺、按供应商分组时组说明和组统计分别放这里。Last Page Footer 只出现在最后一页的最后部分适合放签章或最终确认信息。把这些位置记成“时机表”比记快捷键有用快捷键以实际安装版本为准网上清单不一定对得上。2.2 用 Group 把“按店铺分页”做出来两种隐藏 columnHeader 的做法报表明细分组是高频需求。比如希望以月份为单位分开显示销售记录或者按店铺把明细归档到同一页这时要在报表大纲中右键报表名选择 Create Group再选中分组字段。创建完组之后设计区会多出 Group Header 和 Group Footer。此时如果直接预览常见现象是每组开头多出一段空白或者列名在每页重复出现看起来像“分组没生效”。问题多半不在分组字段而在 Band 高度和 Column Header 的占位。第一种做法是设置 Band 属性。选中分组区域后在右下角属性面板找到 Band Properties把 Height 设为 0同时勾选 Start New Column、Start New Page 前的复选框。Height 设为 0 不是删除 Band而是让它不占垂直空间Start New Page 让每个分组从新页开始适合“同店铺明细归档在同一页”的效果。这里要注意属性名是 Start不是某些旧资料里写成 Sart 的拼写找的时候按实际面板为准。第二种做法是针对单个分组字段直接设置 Column Header 的 Height 为 0同时把 Column Header 中原有的列名全部移到 Group Header 中。分组字段在创建分组时已经选过也可以放进 Group Header 后隐藏显示。这样做的逻辑是Column Header 每页重复分组后每个店铺一页列名应该跟着组走而不是每页固定出现。实际效果类似按店铺分页同店铺明细归在同一页列名只在组头出现一次。操作位置参数建议值说明Group HeaderHeight0 或不占位不想显示组头说明时设 0Group HeaderStart New Page勾选每组从新页开始Column HeaderHeight0列名已移到 Group Header 时使用Group FooterHeight按需放组统计时保留否则设 0DetailHeight按行高不要为了“撑满页面”盲目拉大分组后出现空白页先看三个地方Column Header 是否还占着高度Group Header 是否保留了不需要的空白区域页面边距是否和 Start New Page 冲突。我一般会先把不需要的 Band 高度全部设 0再逐块恢复这样能快速定位是哪一块把页面撑开了。血泪经验是不要一上来就删 Band删掉之后统计变量可能找不到重置区域设 0 更可控。2.3 自定义纸张与面单只留 Detail页面格式参数怎么改快递面单或者部分管理报表需要自定义纸张大小。新建完报表初始页面后点击页面最边框外侧部分在 Report 属性部分选择 Edit Page Format再选 Format 里的 Custom。此时注意下方 Units 选择 mm 或需要的长度计量单位不要用默认单位直接填数字。宽度、高度、边距三者要一起看纸张宽度减去左右边距才是可用列宽面单打印机对边距很敏感边距留太小容易切字留太大又浪费纸。参数常见设置作用注意Unitsmm长度单位不要混用 px 和 mmPage Width按面单纸宽纸张宽度含边距Page Height按面单纸高纸张高度与打印机设置一致Margins25 mm四周留白太小易切字Column Width页面宽减边距内容区宽度与 Detail 内控件对齐面单场景一般只保留 Detail 区域其他区域高度设置为 0。Title、Page Header、Column Header、Column Footer、Page Footer、Summary 如果不需要全部把 Height 设为 0而不是只把内容清空。清空内容但保留高度PDF 里仍然会占位打印出来就是一段空白。设置完之后不要只看设计器预览直接导一份 PDF 看分页和边距这一步能省掉很多返工。注意自定义纸张的单位、宽高、边距要和实际打印机驱动里的纸张设置一致否则设计器里刚好打印出来偏移几毫米。3. JSON 数据源从挂载到编译字段映射、手工补字段与序号变量3.1 数据源关联与字段映射先预览再拖控件以 JSON 作为常用数据源时一般顺序是添加数据源新建报表页关联数据源添加数据字段添加并修改字段标签属性设置分组预览编译。添加数据源主要用于预览没有数据源也可以生成报表但字段类型和表达式没法验证。新建报表页后把数据源关联到报表再在报表大纲里添加 fields。字段的 Name 必须与 JSON 里的 key 或数据库查询字段保持一致描述可以写中文类型要按实际数据选不要全部默认 String。先看一段 JSON 示例{ code: ASN20240501, shipFromName: 某供应商, closedAt: 2024-05-01 10:00:00, totalQty: 120, openQty: 20, itemCode: ITEM-001 }这段 JSON 里code、shipFromName是字符串closedAt是日期时间totalQty、openQty是数值。映射字段时code的 Name 写code描述写“入库单号”closedAt类型选 Date 或 DateTimetotalQty类型选 Integer。如果全部选 String后面做 Crosstab 统计时Sum会失效或者变成计数这是很常见的翻车点。我一般会先在数据源预览里看一遍 JSON 结构再拖字段避免字段名拼错。字段JSON 类型报表字段类型用途codestringjava.lang.String单号、条件查询shipFromNamestringjava.lang.String供应商名closedAtstring/datejava.util.Date日期条件、排序totalQtynumberjava.lang.Integer数量统计openQtynumberjava.lang.Integer未结数量字段标签是设计区里显示的中文名字段 Name 是表达式里引用的名字两者不要混。标签可以改“收货商品统计标签”这类中文但 Name 保持和 JSON key 一致。属性设置里可以调字体、边框、对齐但 PDF 中文字体不要在这里单独设一半后面第 4 章会统一处理。3.2 漏字段别重建fields 手工新增与 Name 对齐使用 JSON 数据源时偶尔会漏掉个别字段。有人第一反应是重建数据源其实没必要。在左下角报表大纲中右键 fields选择手工新增所需字段然后在属性框中重命名 Name 和描述选择对应字段类型。Name 必须与数据库查询字段或 JSON key 保持一致描述只是显示用。新增完字段后把它拖到 Detail 或 Group Header 里预览看是否能取到值。手工补字段最容易错的是 Name 大小写和空格。JSON 里是shipFromName字段 Name 写成shipfromname或shipFromName表达式里就取不到值预览显示 null。另一个坑是类型选错数量字段选了 String排序会按字符串排2会排在10后面日期字段选了 String期间条件比较会失效。补字段时我一般会复制 JSON key 粘贴到 Name再手动核对一遍类型。{ field: shipFromName, id: shipFromName, name: 供应商名, type: string }上面这段是打印配置里的条件字段示例field和id尽量保持一致name是界面显示名type是 SQL 查询时用到的条件字段类型。字段定义和打印配置里的命名参数要对齐否则后面 SQL 模板绑定不上。这个对齐动作在手工补字段时就要做不要等到上传系统才发现参数名对不上。3.3 明细序号列Create Variable 的表达式与重置策略报表明细里经常要加序号列方便统计和对照。可以利用报表大纲中的 Fx 函数功能右键 fx 选择 Create Variable在属性 Object 面板里重命名并设置参数最后把序号变量拖到 Detail 区作为第一列显示。整表连续序号可以直接用内置的$V{REPORT_COUNT}分组内序号则要新建变量并设置 Reset Type 为 Group。// 变量名groupSeq // Value Classjava.lang.Integer // Initial Value Expression0 // Expression$V{groupSeq} 1 // Reset TypeGroup // Reset Group你的分组名 // Increment TypeNone这段变量的逻辑是初始值为 0每计算一行时表达式取当前值加 1遇到指定分组时重置回初始值。Reset Type选 Group 后每个店铺或每个月份内部从 1 开始排如果选 Report整张报表连续编号。Increment Type一般选 None让表达式按行递推即可。变量拖到 Detail 第一列后Text Field 表达式写$V{groupSeq}不要写${groupSeq}。序号列还有两个细节。第一变量名不要和内置变量重名比如REPORT_COUNT、PAGE_NUMBER重名后排错很费时间。第二如果分组后序号没有重置先检查 Reset Group 是否选中了正确的组名再检查变量计算顺序。我一般会先把变量放到 Group Header 预览一次确认每组第一行是 1再拖到 Detail。这样比整张报表导出来找问题快得多。4. PDF 中文、Crosstab 与打印配置字体样式、隐显表达式和查询条件 JSON4.1 PDF 中文落字pdfStyle 全局样式和逐控件设置PDF 报表打印中最常见的问题是中文掉字。设计器预览能显示中文上传到系统后字就没了或者变成方框。原因通常不是字体装没装而是 PDF 导出时没有指定pdfFontName和pdfEncoding。预览用的是系统字体PDF 导出走的是另一套字体映射。对每一个中文标签属性做适当修改是一种做法更稳的是在 jrxml 的 styles 里加一个全局默认样式。style namepdfStyle isDefaulttrue pdfFontNameSTSong-Light pdfEncodingUniGB-UCS2-H isPdfEmbeddedtrue/这段样式放在 jrxml 的 styles 区域isDefaulttrue表示作为默认样式生效。pdfFontNameSTSong-Light指定 PDF 中文字体名pdfEncodingUniGB-UCS2-H指定中文编码isPdfEmbeddedtrue表示嵌入字体。属性面板里也可以在 Advanced 面板逐控件设置 PDF Font name、PDF Encoding、Embedded但逐个改容易漏尤其是后来新增的标签。全局样式加逐控件抽查是我比较推荐的做法。提示改完字体样式后不要只看设计器预览直接导一份 PDF 打开看中文是否完整再上传系统验证。如果项目里使用自定义 TTF 字体需要做字体扩展不在小技巧范围内。常见做法是先用 PDF 内置中文字体把模板跑通再换自定义字体。注意STSong-Light这类字体名要和实际运行环境支持的一致换了环境导出方框先查字体映射不要先怀疑模板。4.2 面单标识隐显EQUALS 表达式别写反快递面单或管理报表里有时需要用“E”区分陆运件或航空件只在一定条件下打印某个标识。这类需求用控件的 Print When Expression 做显示隐藏不要用 Band 的 Print When除非整块区域都要隐藏。表达式可以用EQUALS函数判断字段是否等于特定值返回 Boolean。// Text Field 的 Print When Expression EQUALS($F{deliveryType}, E)这段表达式的意思是当deliveryType等于E时打印该控件否则不显示。$F{deliveryType}是字段表达式E是目标值。如果字段可能为 null直接写EQUALS可能返回 null导致控件行为不稳定可以改成下面这种先判空的写法。$F{deliveryType} ! null $F{deliveryType}.equals(E)! null先挡掉空值.equals(E)再做字符串比较。注意不要写成$F{deliveryType} E字符串比较用equals更稳。Print When Expression 放在控件属性里不要放到 Band 上放错位置会出现“整个区域都不显示”的现象排查时先看表达式挂在哪一层。4.3 Crosstab 交叉表统计字段类型和 Summary 区约束交叉报表一般用 Crosstab 控件。做之前先处理字段类型导入数据源或手工新建 Fields 时需要用到的统计字段必须调整为 Integer 类型。比如明细里统计收发货绩效ReceiptCount或TotalQty在 JSON 中读取过来默认是 String必须改成 int。类型不改Crosstab 里选 Sum 会统计不出数值或者变成计数。{ ReceiptCount: 12, TotalQty: 120 }这两个字段在 JSON 里是数值但数据源读取时可能被识别成 String。手工新增字段时Value Class 选java.lang.Integer不要选java.lang.String。Crosstab 的明细字段计算函数选 Sum行组、列组按业务字段拖。Crosstab 只可存放于 Summary 区拖到 Detail 区会报错或不显示。设计时去掉多余的功能区域根据需要保留 Title、Summary其他 Band 高度设 0。拖动 Crosstab 时选择引用已存在数据源根据向导右上角表格粉色阴影提示按需依次选择数据字段下一步依次左侧、明细。添加明细字段时把 calculation 函数均改为 Sum最后完成。完成后把 Crosstab 覆盖到整个界面双击 Crosstab 可修改深蓝色 Static Text 上部、左部的字段名称。大多数时候还需要选中 Crosstab 中全部明细字段把字体大小改为 6 号、居中因为默认字体过大可能显示不出来。检查项正确做法错误后果统计字段类型Integer/Double/BigDecimalSum 失效或变计数Crosstab 位置Summary 区Detail 区不显示或报错明细字段字体6 号、居中列宽不够内容溢出行组/列组按业务字段拖顺序错汇总口径乱数据源引用已存在数据源新建空源预览无数据交叉表显示不全先看字体大小和列宽再看统计字段类型最后看 Crosstab 是否被其他 Band 遮挡。把 Crosstab 拉到覆盖整个 Summary 区通常能解决大部分显示问题。4.4 打印配置 JSON 与 SQL 命名参数上传前先对齐模板编译完还要完成上传和配置。选择“配置”—“打印配置”—“报表”新增报表新建代码标识原模板名称尽量与此处一致填写描述、报表类型编写特定的条件和 SQL 语句模板。条件部分可以理解为 SQL 条件子句前半句是字段属性名称基本不做修改后半段是用户查询条件。field、id、name、type四个为必填字段field与id尽量保持一致type为下一步 SQL 查询中用到的条件字段类型。[ {field: , id: h1_basic, name: 基本信息, type: h1}, {field: beg, id: beg, name: 起始日期, type: date}, {field: end, id: end, name: 结束日期, type: date}, {field: itemCode, id: itemCode, name: 商品编码, type: string}, {field: code, id: code, name: 入库单号, type: string}, {field: shipFromName, id: shipFromName, name: 供应商名, type: string} ]这段 JSON 里h1类型是分组标题不参与 SQL 条件beg、end是日期类型itemCode、code、shipFromName是字符串类型。对于作业报表除name外其他都无需做太大更改管理报表如果需要用到期间、其他自定义条件必须对上述部分做补充。field和id对应字段名称可自取但一旦定了SQL 里的命名参数就要跟着一致。select rh.closedAt, rd.receiptCode, rh.shipFromName, it.itemCategory1, it.code, it.userDef3, it.name, rd.totalQty, rd.openQty, (rd.totalQty - rd.openQty) as redQty, rd.warehouseCode, (select barcode from item_barcode ib where ib.itemCode rd.itemCode limit 1) as BARCODE from RECEIPT_HEADER rh inner join RECEIPT_DETAIL rd on rh.id rd.receiptId inner join ITEM it on rd.itemCode it.code where rh.leadingSts 900 and rh.trailingSts 900 and (rh.code :code or rh.code is null) and (rd.itemCode :itemCode or rd.itemCode is null) and (rh.shipFromName :shipFromName or rh.shipFromName is null) and (rh.closedAt :beg or rh.closedAt is null) and (rh.closedAt :end or rh.closedAt is null) order by rh.closedAt desc这段 SQL 里:code、:itemCode、:shipFromName、:beg、:end对应 JSON 里的field和id。or :param is null的写法是为了让条件为空时不过滤适合管理报表的可选查询。日期字段用和包住起止范围注意beg和end的类型是 date不要传字符串。示例里的limit 1是按常见数据库写法给的实际数据库如果不支持改成对应的取一条写法不要照抄。SQL 模板写完后先在数据库客户端里绑定变量跑一遍确认结果集字段名和报表字段 Name 对得上。4.5 菜单 View JSON 挂载与管理报表预览分叉模板上传完成后通过“开发”—“菜单配置”找到报表所需打印界面的界面类型和界面名称在 View JSON 中打开对应加载项在打印区域添加对应作业报表。文档名称对应模板名称id对应打印配置中的代码名称点击更新完成。这里的三处对齐很关键打印配置里的代码标识、上传的模板名称、View JSON 里的文档名称和 id任何一处不一致菜单入口可能有了但打印列表里看不到报表。管理报表不走这套挂载。可以在“管理”—“报表查询”中直接双击预览查询选择自定义期间、添加完其他字段后点击 PDF 下载完成预览和打印。作业报表和 ordinary 管理报表的分叉要分清作业报表偏固定打印入口管理报表偏查询式预览。上传顺序上先把打印配置建好再上传对应模板最后配菜单如果先配菜单后改代码标识记得回头把 View JSON 里的 id 同步改掉。配置项对应关系常见错误打印配置代码标识模板名称尽量一致代码标识与模板名不一致模板上传对应报表文件上传了旧版本模板View JSON 文档名称模板名称文档名称写错View JSON id打印配置代码名称id 指向了别的配置查询条件 JSONSQL 命名参数field/id 与参数名不一致挂载完成后不要只在菜单里点一次。用作业报表入口打一次再用管理报表查询入口预览一次两边都看 PDF 下载结果。作业报表看的是固定入口是否通管理报表看的是条件参数是否生效。5. 避坑排查中文掉字、分组空白页、Crosstab 显示不全等 5 个现场问题5.1 预览中文正常上传后中文消失或变方框现象设计器预览里中文完整导出 PDF 也正常上传到系统后中文标签全部消失或者变成方框。原因只改了控件的普通字体没有设置pdfFontName、pdfEncoding、isPdfEmbedded。预览走系统字体PDF 导出走 PDF 字体映射上传后运行环境没有对应字体就掉字。解决在 jrxml 的 styles 里加全局pdfStyle设置pdfFontNameSTSong-Light、pdfEncodingUniGB-UCS2-H、isPdfEmbeddedtrue再对新增的中文控件逐個抽查 Advanced 面板。改完直接导 PDF 验证不要只看设计器。5.2 分组后多出空白页同店铺明细没有归到一页现象创建 Group 后每组后面多出一张空白页或者同店铺明细仍然散在多页。原因Column Header 还占着高度Group Header 或 Group Footer 有不需要的空白区域Start New Page 与页面边距冲突。解决先选中 Column Header把 Height 设为 0再把列名移到 Group Header选中 Group Header按需设 Height 为 0勾选 Start New Page检查页面边距是否把内容区挤到下一页。不要直接删 Band设 0 更安全删掉后统计变量的重置区域可能丢失。5.3 Crosstab 只显示部分列或者统计值不对现象交叉表只显示左边几列右边列被截断或者明细字段选了 Sum结果变成计数。原因Crosstab 默认字体过大列宽不够统计字段在 JSON 里是 String没有改成 IntegerCrosstab 没有放在 Summary 区。解决把 Crosstab 放到 Summary 区统计字段 Value Class 改为 Integer 或 Double明细字段 calculation 选 Sum选中 Crosstab 全部明细字段字体改 6 号、居中把 Crosstab 拉宽覆盖 Summary 区双击修改 Static Text 的行列名称。5.4 SQL 参数不生效查询返回全量或提示参数未定义现象管理报表里选了起止日期和商品编码点击查询还是返回全量或者运行时报参数未定义。原因JSON 里的field/id与 SQL 命名参数不一致type写错或者or :param is null让空值条件放行了。解决把 JSON 的field、id和 SQL 里的:beg、:end、:itemCode逐个对齐日期字段type用 date字符串用 string数量用 integer先在数据库客户端绑定变量跑 SQL确认结果集字段名与报表字段 Name 一致再回系统配置。5.5 菜单挂载后看不到报表或打印列表为空现象菜单配置里已经加了入口点击后打印列表没有对应报表或者文档名称显示但点打印没反应。原因View JSON 里的文档名称与模板名称不一致id与打印配置代码标识不一致模板没有上传成功或者上传的是旧版本。解决按“打印配置代码标识 → 模板名称 → View JSON 文档名称和 id”三处对齐重新上传模板更新 View JSON 后刷新页面。作业报表和管理报表分开验证作业报表走菜单入口管理报表走报表查询预览两边都下载 PDF 看结果。排查顺序看什么快速判断1PDF 字体样式中文掉字先查 pdfStyle2Band 高度空白页先查 Column Header/Group Header3字段类型Crosstab 统计不对先查 Integer4参数名查询不生效先对 field/id 与 :param5三处名称菜单看不到先对代码标识、模板名、View JSON6. 导出 PDF 前的三看一测把模板验证做成固定动作模板改完最怕的是“设计器里好好的上传后不能用”。我现在的习惯是导出 PDF 前做三看一测不跳过。三看一看 Band 高度面单是不是只留了 Detail其他 Band 是否设 0二看字段类型Crosstab 的统计字段是不是 Integer/Double日期字段是不是 Date三看参数名打印配置 JSON 的field/id与 SQL 里的:beg、:end、:itemCode是否一一对应。一测用空条件、单条件、全条件各导一次 PDF检查中文、分页、合计和参数过滤。检查项动作通过标准Band 高度看不需要的 Band 是否设 0面单无多余空白页字段类型看统计字段 Value ClassSum 能出数值参数名对 JSON 与 SQL 命名参数条件过滤生效空条件不填条件导 PDF返回全量且不报错单条件只填一个条件导 PDF过滤结果正确全条件起止日期加编码导 PDF结果集和合计都对有次我偷懒只看了设计器预览就上传结果中文全掉返工半小时。从那以后每次改完模板我都强制先本地导一份带中文和合计的 PDF再用管理报表空条件预览一遍最后才去配菜单。希望帮到你。本文还有配套的精品资源点击获取