1.概述
1.1 問題描述
用戶在做填報報表時,希望點擊提交按鈕并不是往數據庫中填報數據,而是要獲取到填報頁面的數據進行進一步處理,這個該如何解決呢?
1.2 實現思路
在 報表填報屬性 中介紹了報表填報屬性有 2 種設置方式,一個是内置 SQL 直接綁定字段,往數據庫中填報數據,另外一種是添加自定義事件,如果需要獲取數據對數據進行進一步處理,則可選擇添加自定義事件,下面詳細介紹。
2.示例
2.1 準備數據
新建數據查詢數據集 ds1,SQL 語句爲:SELECT studentno,name,grade FROM STSCORE where name <> ''
2.2 設計填報表格
1)設計填報表格,将數據集相應字段拖到單元格中,A2 和 C2 單元格添加「數字控件」,B2 單元格添加「文本控件」,表格樣式如下圖所示:
2)C2 單元格設置爲彙總求和,如下圖所示:
3)點擊「模板>報表填報屬性」,新增一個自定義提交,點擊編輯按鈕,如下圖所示:
2.3 自定義提交類
2.3.1 方法一
1)在類裏面定義幾個 JobValue,每一個 JobValue 對應一個單元格,在報表填報屬性中通過屬性列表中将其與對應的單元格綁定起來,具體使用如 DemoSubmitJob1:
package com.fr.data;
import com.fr.script.Calculator;
public class DemoSubmitJob1 extends DefinedSubmitJob {
/**
* 當模板自定義事件增加的屬性 名稱與下面變量有對應時,則會自動賦值於此對應變量
*/
public String getJobType(){
return " ";
}
private JobValue studentno; // JobValue 對應單元格
private JobValue name;
private JobValue grade;
private boolean isPass; // 非單元格,則對應具體類型值
/**
* 每一條記錄執行一次此方法
* 同一提交事件在一個處理事務内,此對象是唯一的
*/
public void doJob(Calculator calculator) throws Exception {
// JobValue 的 getValueState()方法獲取此對應單元格的狀态
//單元格有六種狀态:
// 删除(JobValue.VALUE_STATE_DELETED)
// 默認(JobValue.VALUE_STATE_DEFAULT)
// 修改(JobValue.VALUE_STATE_CHANGED)
// 插入(JobValue.VALUE_STATE_INSERT)
// 修改删除(單元格修改值之後被删除JobValue.VALUE_STATE_CHANGED_AND_DELETED)
// 插入修改(插入狀态的單元格再被修改JobValue.VALUE_STATE_CHANGED_AND_INSERT)
if (studentno.getState().checkChanged()) {
// 此單元格的值在報表初始化後被修改過(包含修改和修改删除和修改插入三種狀态)
} else if (studentno.getState().checkInsert()) {
// 此單元格是在報表初始化後新增的(包括插入和修改插入兩種狀态)
} else if (studentno.getState().checkDeleted()) {
// 此單元格所在的記錄被執行了删除操作(包含删除和修改删除兩種狀态)
} else if (studentno.getState().checkDefault()) {
// 此單元格在報表初始化後沒有變化
}
// 值獲取
System.out.print(" 學号: " + studentno.getValue()); // 通過 JobValue 的 getValue 方法獲得單元格的值
System.out.print(" 姓名: " + name.getValue());
System.out.print(" 總分: " + grade.getValue());
System.out.print(" 是否達标: " + isPass);
System.out.println();
}
}
注:可以将所有變量全部定義成 JobValue 對象,通過 getValue() 獲取對象的值。
2)将 Java 代碼拷貝到自定義函數編輯界面,點擊「編譯」按鈕,顯示編譯成功後,點擊「保存」按鈕,如下圖所示:
注:也可以将外部編譯得到的 class 文件放到 %FR_HOME%\webapps\webroot\WEB-INF\classes 文件夾下,然後點擊選擇按鈕引用 class 文件。
3)點擊增加屬性按鈕,給提交事件添加 4 個屬性,注意值的選擇爲「單元格」和「公式」,如下圖所示:
注1:屬性名稱跟類文件中定義的 JobValue 是一緻的,必須保證「報表填報屬性」處添加的屬性名稱與類文件中定義的名稱保持一緻。如果在類文件中對應參數類型不是 JobValue 的話,則必須與屬性的數據類型保持一緻。
注2:一般來說,爲了便於維護,可以将 Java 類中的所有變量全部設爲 JobValue 對象,不論報表填報屬性中的屬性類型是什麽,均可以通過 GetValue 獲取其值。
2.3.2 方法二
1)通過 doJob 的方法參數 Calculator 中的 Property_Value 屬性, Property_Value 屬性對應一個 map 對象,Map 中包含報表填報屬性中所有屬性名稱以及它們對應的值,使用 map 中的 getValue() 方法獲取屬性值,即單元格,接着使用 JobValue 的 getValue() 方法獲取單元格的值,具體使用如 DemoSubmitJob2:
package com.fr.data;
import com.fr.script.Calculator;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class DemoSubmitJob2 extends DefinedSubmitJob {
/**
* 每一條記錄執行一次此方法
* 同一提交事件在一個處理事務内,此對象是唯一的
*/
public String getJobType(){
return " ";
}
public void doJob(Calculator calculator) throws Exception {
// 同樣可以直接在傳入的 calculator 中獲取定義的屬性及其對應的值
Map map = (Map)calculator.getAttribute(PROPERTY_VALUE);
if (map == null) return;
Set set = map.entrySet();
Iterator it = set.iterator();
Entry entry;
// 遍曆Map獲取所有屬性及其值
while (it.hasNext()) {
entry = (Entry)it.next();
System.out.print(" " + entry.getKey() + ": ");
// JobValue對應單元格
if (entry.getValue() instanceof JobValue) {
JobValue ce = (JobValue)entry.getValue();
// JobValue 的 getValueState()方法獲取此對應單元格的狀态
//單元格有六種狀态:
// 删除(JobValue.VALUE_STATE_DELETED)
// 默認(JobValue.VALUE_STATE_DEFAULT)
// 修改(JobValue.VALUE_STATE_CHANGED)
// 插入(JobValue.VALUE_STATE_INSERT)
// 修改删除(單元格修改值之後被删除JobValue.VALUE_STATE_CHANGED_AND_DELETED)
// 插入修改(插入狀态的單元格再被修改JobValue.VALUE_STATE_CHANGED_AND_INSERT)
if (ce.getState().checkChanged()) {
// 此單元格的值在報表初始化後被修改過(包含修改和修改删除和修改插入三種狀态)
} else if (ce.getState().checkInsert()) {
// 此單元格是在報表初始化後新增的(包括插入和修改插入兩種狀态)
} else if (ce.getState().checkDeleted()) {
// 此單元格所在的記錄被執行了删除操作(包含删除和修改删除兩種狀态)
} else if (ce.getState().checkDefault()) {
// 此單元格在報表初始化後沒有變化
}
System.out.print(ce.getValue()); // 通過 JobValue 的 getValue 方法獲得單元格的值
} else {
// 非單元格,則對應具體類型值
System.out.print(entry.getValue());
}
}
System.out.println();
}
}
2)将 Java 代碼拷貝到自定義函數編輯界面,點擊編譯按鈕,只有顯示編譯成功後,才能保存,如下圖所示:
注:也可以将外部編譯得到的 class 文件放到 %FR_HOME%\webapps\webroot\WEB-INF\classes 文件夾下,然後點擊選擇按鈕引用 class 文件。
3)點擊增加屬性按鈕,給提交事件添加 4 個屬性,如下圖所示:
注:方法二中是通過 Calculator 參數屬性 PROPERTY_VALUE 來獲取報表填報屬性處的屬性與屬性值,再通過 JobValue 來得到單元格的值,在類文件中并不是一一對應的獲取屬性與屬性值,而是通過 map 遍曆來獲取屬性與屬性值,所以在報表填報屬性處增加屬性時,屬性名字可随意定義,但是後面的值如果是單元格的話,必須選擇單元格類型。
2.3.3 方法三
1)自定義事件除了可繼承自 DefinedSubmitJob 這個接口之外,還可以繼承 TotalSubmitJob 接口,這兩個接口的區别在於 DefinedSubmitJob 多次執行,即一行一行的獲取模板中的數據,獲取一行數據則執行一次自定義事件,而 TotalSubmitJob 接口只執行一次,即先獲取到模板中所有的數據,然後在類裏面循環,具體使用如 DemoTotalSubmitJob:
package com.fr.data;
import com.fr.script.Calculator;
public class DemoTotalSubmitJob extends TotalSubmitJob {
/**
* 同一提交事件,在一個提交事務内只執行一次
*
* @param data 以二維表排列的所有提交數據
*/
public String getJobType() {
return " ";
}
protected void doTotalJob(Data data, Calculator calculator)
throws Exception {
data.getColumnCount(); // 獲取列的數量,每一列對應一個添加的屬性
for (int i = 0; i < data.getColumnCount(); i++) {
System.out.println(data.getColumnName(i)); // 獲取對應的屬性名稱
}
for (int i = 0; i < data.getRowCount(); i++) { // getRowCount 獲取一共多少行數據
System.out.print("ROW " + i + " {");
for (int j = 0; j < data.getColumnCount(); j++) {
if (j > 0) System.out.print(", ");
Object value = data.getValueAt(i, j); // 獲取對應位置的值
if (value instanceof JobValue) {
JobValue ce = (JobValue) value;
// JobValue 的 getValueState()方法獲取此對應單元格的狀态
//單元格有六種狀态:
// 删除(JobValue.VALUE_STATE_DELETED)
// 默認(JobValue.VALUE_STATE_DEFAULT)
// 修改(JobValue.VALUE_STATE_CHANGED)
// 插入(JobValue.VALUE_STATE_INSERT)
// 修改删除(單元格修改值之後被删除JobValue.VALUE_STATE_CHANGED_AND_DELETED)
// 插入修改(插入狀态的單元格再被修改JobValue.VALUE_STATE_CHANGED_AND_INSERT)
if (ce.getState().checkChanged()) {
// 此單元格的值在報表初始化後被修改過(包含修改和修改删除和修改插入三種狀态)
} else if (ce.getState().checkInsert()) {
// 此單元格是在報表初始化後新增的(包括插入和修改插入兩種狀态)
} else if (ce.getState().checkDeleted()) {
// 此單元格所在的記錄被執行了删除操作(包含删除和修改删除兩種狀态)
} else if (ce.getState().checkDefault()) {
// 此單元格在報表初始化後沒有變化
}
value = ce.getValue(); // 通過 JobValue 的 getValue 方法獲得單元格的值
}
System.out.print(data.getColumnName(j) + " : " + value);
}
System.out.print("}");
System.out.println();
}
}
}
2)将 Java 代碼拷貝到自定義函數編輯界面,點擊編譯按鈕,只有顯示編譯成功後,才能保存,如下圖所示:
注:也可以将外部編譯得到的 class 文件放到 %FR_HOME%\webapps\webroot\WEB-INF\classes 文件夾下,然後點擊選擇按鈕引用 class 文件。
3)點擊增加屬性按鈕,給提交事件添加 4 個屬性,如下圖所示:
注:方法三與方法二中的使用方式類似。在報表填報屬性處增加屬性時,屬性名字可随意定義,但是後面的值如果是單元格的話,必須選擇單元格類型。
2.4 效果預覽
2.4.1 方法一
1)保存報表,選擇「填報預覽」,前端點擊「提交」按鈕,如下圖所示:
2)成功提交後,文件夾 %FR_HOME%\bin 下會生成文件 out.log,如下圖所示:
3)記事本打開 out.log,可以看到導出的填報信息,如下圖所示:
2.4.2 方法二
1)保存報表,選擇「填報預覽」,前端點擊「提交」按鈕,如下圖所示:
2)成功提交後,文件夾 %FR_HOME%\bin 下會生成文件 out.log,如下圖所示:
3)記事本打開 out.log,可以看到導出的填報信息,如下圖所示:
2.4.3 方法三
1)保存報表,選擇「填報預覽」,前端點擊「提交」按鈕,如下圖所示:
2)成功提交後,文件夾%FR_HOME%\bin下會生成文件out.log,如下圖所示:
3)記事本打開out.log,可以看到導出的填報信息,如下圖所示:
2.5 其他應用
自定義事件不僅可用於報表填報屬性處,也可用於按鈕控件中的提交事件,具體應用參見文檔:上傳下載文件插件
3.模板下載
1)方法一
已完成模板可參見:%FR_HOME%\webapps\webroot\WEB-INF\reportlets\doc\Form\LineForm\填報自定義提交.cpt
點擊下載模板:填報自定義提交.cpt
2)方法二
已完成模板可參見:%FR_HOME%\webapps\webroot\WEB-INF\reportlets\doc\Form\LineForm\填報自定義提交2.cpt
點擊下載模板:填報自定義提交2.cpt
3)方法三
已完成模板可參見:%FR_HOME%\webapps\webroot\WEB-INF\reportlets\doc\Form\LineForm\填報自定義提交3.cpt
點擊下載模板:填報自定義提交3.cpt