历史版本14 :带参程序数据集 返回文档
编辑时间:
内容长度:图片数:目录数:
修改原因:
1. 问题描述编辑
在实际应用中,可能需要根据表名动态地改变数据源,比如在程序数据集中,通过传进的表名参数,到数据库取出对应的表作为数据源。因为FineReport是通过AbstractTableData抽象类来读取数据源的,而上述所有的数据来源都继承实现其抽象方法 ,因此用户只要实现了AbstractTableData抽象类,也就可以用自定义类型的数据源了(程序数据集),FineReport报表引擎就能够读取定义的数据源作为报表数据源使用。以下就对这种情况举例说明。
2. 实现原理编辑
与简单程序数据集相同,即继承AbstractTableData。
3. 实现步骤编辑
3.1 定义参数
定义一个参数,并定义数据表结构,代码如下:
public ParamTableDataDemo() {
// 定义tableName参数
this.parameters = new Parameter[] { new Parameter("tableName") };
// 定义程序数据集列名
columnNames = new String[columnNum];
for (int i = 0; i < columnNum; i++) {
columnNames[i] = "column#" + String.valueOf(i);
}
}
3.2 设置数据
将数据放入到定义的表中,代码如下:
public void init() {
// 确保只被执行一次
if (valueList != null) {
return;
}
// 保存得到的数据库表名
String tableName = parameters[0].getValue().toString();
// 构造SQL语句,并打印出来
String sql = "select * from " + tableName + ";";
FRContext.getLogger().info("Query SQL of ParamTableDataDemo: \n" + sql);
// 保存得到的结果集
valueList = new ArrayList();
// 下面开始建立数据库连接,按照刚才的SQL语句进行查询
Connection conn = this.getConnection();
try {
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
// 获得记录的详细信息,然后获得总列数
ResultSetMetaData rsmd = rs.getMetaData();
colNum = rsmd.getColumnCount();
// 用对象保存数据
Object[] objArray = null;
while (rs.next()) {
objArray = new Object[colNum];
for (int i = 0; i < colNum; i++) {
objArray[i] = rs.getObject(i + 1);
}
// 在valueList中加入这一行数据
valueList.add(objArray);
}
// 释放数据库资源
rs.close();
stmt.close();
conn.close();
// 打印一共取到的数据行数量
FRContext.getLogger().info(
"Query SQL of ParamTableDataDemo: \n" + valueList.size()
+ " rows selected");
} catch (Exception e) {
e.printStackTrace();
}
}
3.3 完整的数据集代码
完整的带参程序数据集的代码如下
package com.fr.doc;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileFilter;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import com.fr.design.config.ToolBarDef;
import com.fr.doc.tag.DOC;
public class Main extends JFrame implements TreeSelectionListener {
public static void main(String[] args) {
new Main();
}
private DirectoryTree dTree;
private JPanel centerCardPane;
private RichDocPane rPane;
public Main()
{
JPanel contentPane = (JPanel)this.getContentPane();
contentPane.setLayout(new BorderLayout(0, 0));
contentPane.add(createWestPane(), BorderLayout.WEST);
centerCardPane = new JPanel();
contentPane.add(centerCardPane, BorderLayout.CENTER);
centerCardPane.setLayout(new CardLayout());
centerCardPane.add(createEmptyPane(), "EMPTY");
centerCardPane.add(createDocumentFolderPane(), "FOLDER");
centerCardPane.add(createDocumentFilePane(), "FILE");
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setExtendedState(MAXIMIZED_BOTH); // 最大化
this.setVisible(true);
}
private JToolBar toolbarActions2JToolbar(ToolbarUpdateAction[] toolbarActions, JComponent keyTarget) {
ToolBarDef def = new ToolBarDef();
for (int i = 0; i < toolbarActions.length; i++) {
def.addShortCut(toolbarActions[i]);
KeyStroke keyStroke = toolbarActions[i].getKeyStroke();
if (keyStroke != null) {
String actionName = String.format("RichDoc(%s)", toolbarActions[i].getName());
keyTarget.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStroke, actionName);
keyTarget.getActionMap().put(actionName, toolbarActions[i]);
}
}
JToolBar toolbar = ToolBarDef.createJToolBar();
def.updateToolBar(toolbar);
if(rPane != null){
toolbar.add(rPane.comboBoxPane());
}
return toolbar;
}
private JPanel createWestPane() {
JPanel west = new JPanel();
west.setLayout(new BorderLayout());
JSplitPane splitPane ;
dTree = new DirectoryTree(new File(DocContext.getContext().getHomePath()), new FileFilter() {
@Override
public boolean accept(File pathname) {
if (pathname.isDirectory()) {
return !".svn".equals(pathname.getName());
} else if (pathname.isFile()) {
return pathname.getName().endsWith(".src");
}
return false;
}
});
JPanel toolPane = new JPanel(new BorderLayout());
//swicth工作目录
final DocEnvComBoxPanel envListPane = new DocEnvComBoxPanel();
String currentEnv = DocContext.getContext().getCurrentEnv();
envListPane.setSelectedItem(currentEnv);
envListPane.addComboBoxActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
if (envListPane.isRefreshingItems()) {
return;
}
String selectedEnvName = envListPane.getSelectedItem();
DocContext docContext = DocContext.getContext();
DocEnv selectedEnv = docContext.getEnv(selectedEnvName);
dTree.setWorkspaceRoot(new File(selectedEnv.getPath()));
docContext.setCurrentEnv(selectedEnvName);
DocContext.xmlablize();
}
});
toolPane.add(envListPane, BorderLayout.NORTH);
//其他按钮
toolPane.add(toolbarActions2JToolbar(dTree.supportedActions(), dTree),BorderLayout.CENTER);
splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, toolPane, new JScrollPane(dTree));
splitPane.setDividerLocation(87);
splitPane.setDividerSize(1);
// west.add(new JScrollPane(dTree), BorderLayout.CENTER);
// west.add(toolbarActions2JToolbar(dTree.supportedActions(), dTree), BorderLayout.NORTH);
west.add(splitPane,BorderLayout.CENTER);
dTree.checkShortCutsEnabled();
dTree.addTreeSelectionListener(this);
west.setPreferredSize(new Dimension(220, west.getPreferredSize().height));
return west;
}
private JPanel createEmptyPane() {
return new JPanel();
}
private JPanel createDocumentFolderPane() {
return new JPanel();
}
private JPanel createDocumentFilePane() {
JPanel center = new JPanel();
center.setLayout(new BorderLayout(4, 4));
rPane = new RichDocPane();
// JScrollPane jsp = new JScrollPane(rPane);
// center.add(jsp, BorderLayout.CENTER);
center.add(rPane, BorderLayout.CENTER);
center.add(toolbarActions2JToolbar(rPane.supportedActions(), rPane), BorderLayout.NORTH);
return center;
}
private void showEmptyPane() {
((CardLayout)centerCardPane.getLayout()).show(centerCardPane, "EMPTY");
}
private void showFolderPane() {
((CardLayout)centerCardPane.getLayout()).show(centerCardPane, "FOLDER");
}
private void showFilePane() {
((CardLayout)centerCardPane.getLayout()).show(centerCardPane, "FILE");
}
@Override
public void valueChanged(TreeSelectionEvent e) {
// Update
if (e.getOldLeadSelectionPath() != null) {
DefaultMutableTreeNode lastSelectedTreeNode = dTree.getTreeNodeByTreePath(e.getOldLeadSelectionPath());
Object lastSelectedUserObject = lastSelectedTreeNode.getUserObject();
if (lastSelectedUserObject instanceof DocumentFile) {
updateDocumentFile((DocumentFile)lastSelectedUserObject);
} else if (lastSelectedUserObject instanceof DocumentFolder) {
updateDocumentFolder((DocumentFolder)lastSelectedUserObject);
}
}
// Populate
showEmptyPane();
if (e.getNewLeadSelectionPath() != null) {
DefaultMutableTreeNode newSelectedTreeNode = dTree.getTreeNodeByTreePath(e.getNewLeadSelectionPath());
Object userObject = newSelectedTreeNode.getUserObject();
if (userObject instanceof DocumentFile) {
showFilePane();
this.rPane.clearUndoManager();
populateDocumentFile((DocumentFile)userObject);
} else if (userObject instanceof DocumentFolder) {
showFilePane();
populateDocumentFolder((DocumentFolder)userObject);
}
}
}
private void populateDocumentFile(DocumentFile dFile) {
this.rPane.populate(dFile.getDoc(), dFile.getFile());
this.rPane.setModified(false);
}
private void updateDocumentFile(DocumentFile dFile) {
DOC doc = this.rPane.update();
dFile.setDoc(doc);
dFile.xmlablize();
}
private void populateDocumentFolder(DocumentFolder dFolder) {
this.rPane.populate(dFolder.getDoc(), new File(dFolder.getFile(),".finedoc"));
this.rPane.setModified(false);
}
private void updateDocumentFolder(DocumentFolder dFolder) {
DOC doc = this.rPane.update();
dFolder.setDoc(doc);
dFolder.xmlablize();
}
}
编译ParamTableDataDemo.java ,将生成的ParamTableDataDemo.class类文件拷贝到报表工程/WEB-INF/classes目录下。由于该类是在com.fr.data包中的,因此最终应该将该类放在/WEB-INF/classes/com/fr/data下面。此时该程序数据源便定义好了。
3.4 配置程序数据集
新建报表,在报表数据集中新建程序数据源,选择我们定义好的程序数据集,如下图,名字可以自定义,如divtable
3.5 使用程序数据集
配置好程序数据源后便可以使用定义的程序数据集了,选中该数据集点击预览按钮,即可以输入表名动态地获取相应的数据表,并制作模板,如下图
注:如果预览不出数据,请确认代码段里面定义数据库连接时URL的地址是否正确。
可以看到,我们已经将STSCORE表中的数据提取至程序数据集表中,像其他类型的数据集一样,可以通过拖拽方法实现单元格数据列绑定。