FineReport 作為插件化架構的報表工具,提供了豐富的擴展點。當內置控件無法滿足特定業務需求(如特殊過濾邏輯、自定義交互)時,開發自定義控件是最佳選擇。本文以「自定義下拉框」為例,完整演示從後端註冊、核心邏輯實現到前端渲染的全鏈路開發過程。
後端 (Java) 前端 (JavaScript)
┌─────────────────────┐ ┌─────────────────────┐
│ WidgetRegister │ 1.註冊信息 │ │
│ - classForWidget() │◄─────────────►│ │
│ - appearanceForWidget() │ │
│ - iconPathForWidget() │ │
│ - nameForWidget() │ │
└─────────┬───────────┘ └──────────┬──────────┘
│ │
▼ ▼
┌─────────────────────┐ ┌─────────────────────┐
│ CustomComboBox │ 2.數據模型 │ FR.CustomComboBoxEditor │
│ - getXType() │◄─────────────►│ - _init() │
│ - createDataFilter()│ │ - shortcut映射 │
└─────────┬───────────┘ └─────────────────────┘
│
▼
┌─────────────────────┐
│ CustomComboBoxDataFilter │
│ - isMatch() 核心過濾邏輯 │
└─────────────────────┘
package com.hg.free.plugin.customcombo.param;
import com.fr.design.designer.creator.XComboBox;
import com.fr.design.fun.impl.AbstractParameterWidgetOptionProvider;
import com.fr.form.ui.Widget;
public class WidgetRegister extends AbstractParameterWidgetOptionProvider {
@Override
public Class<? extends Widget> classForWidget() {
// 返回核心控件類 (後端數據模型)
return CustomComboBox.class;
}
@Override
public Class<?> appearanceForWidget() {
// 返回設計器界面編輯器類 (設計時UI)
return XComboBox.class;
}
@Override
public String iconPathForWidget() {
// 設計器面板顯示的圖標路徑 (相對 classpath)
return "/com/fr/web/images/combobox.png";
}
@Override
public String nameForWidget() {
// 設計器面板顯示的控件名稱
return "自定義下拉框";
}
}
package com.hg.free.plugin.customcombo.param;
import com.fr.form.ui.ComboBox;
import com.fr.ui.DataFilter;
public class CustomComboBox extends ComboBox {
private static final long serialVersionUID = 7169771062153345236L;
@Override
public String getXType() {
// 關鍵:前端通過此類型標識查找對應的 JS 渲染器
return "customcombo";
}
@Override
protected DataFilter createDataFilter() {
// 核心:返回自定義過濾器,改變匹配邏輯
return new CustomComboBoxDataFilter();
}
}
package com.hg.free.plugin.customcombo.param;
import com.fr.form.ui.ComboBoxDataFilter;
public class CustomComboBoxDataFilter extends ComboBoxDataFilter {
@Override
public boolean isMatch(String txt, String filter) {
// 原始邏輯:前綴匹配 (txt.startsWith(filter))
// 自定義邏輯:包含匹配 (txt.contains(filter))
if (txt == null && filter != null) return false;
if (txt == null && filter == null) return true;
// 支持大小寫不敏感包含匹配
return txt.toLowerCase().contains(filter.toLowerCase());
}
}
| 場景 | 原始匹配 | 自定義匹配 |
|---|---|---|
| 用戶輸入「京」 | 匹配「北京」、「京津」 不匹配「南京」 | 匹配「北京」、「南京」、「京津」 |
| 用戶輸入「sh」 | 匹配「Shanghai」 不匹配「shanghai」 | 匹配「Shanghai」、「shanghai」、「Sh」 |
;(function($) {
// 繼承內置 ComboBoxEditor
FR.CustomComboBoxEditor = FR.extend(FR.ComboBoxEditor, {
_init: function() {
// 調用父類初始化
FR.CustomComboBoxEditor.superclass._init.apply(this, arguments);
// 可在此擴展前端行為:
// - 自定義下拉面板模板
// - 添加鍵盤快捷鍵
// - 集成第三方 UI 庫 (如 Select2)
}
});
// 關鍵:將 xtype "customcombo" 映射到渲染器
$.shortcut("customcombo", FR.CustomComboBoxEditor);
})(jQuery);
xtype: "customcombo"$.shortcut("customcombo") 獲取構造函數FR.CustomComboBoxEditor,傳入配置數據<project name="custom-combo-plugin" default="jar">
<property name="src.dir" value="src"/>
<property name="build.dir" value="build"/>
<property name="dist.dir" value="dist"/>
<target name="compile">
<javac srcdir="${src.dir}" destdir="${build.dir}"
includeantruntime="false" encoding="UTF-8">
<classpath>
<fileset dir="${fr.home}/WebReport/WEB-INF/lib" includes="*.jar"/>
</classpath>
</javac>
</target>
<target name="jar" depends="compile">
<jar destfile="${dist.dir}/custom-combo.jar" basedir="${build.dir}">
<manifest>
<attribute name="Plugin-Class" value="com.hg.free.plugin.customcombo.param.WidgetRegister"/>
</manifest>
</jar>
</target>
</project>
custom-combo.jar 放入 WebReport/WEB-INF/lib_init 替換下拉模板WidgetDataProvider 接口Validator 接口自定義校驗規則log4j.logger.com.fr=DEBUG 觀察控件生命周期ComboBox、ComboBoxDataFilter 是最佳學習範本掌握 FineReport 自定義控件開發,關鍵在於理解 後端數據模型 ↔ xtype 標識 ↔ 前端渲染器 的三角映射關係。以此為核心,配合插件化打包部署,即可將任意業務邏輯封裝為可視化組件,極大提升報表開發效率與表達能力。