从数据库填充DefaultMutableTreeNode

时间:2012-06-24 05:40:39

标签: java swing jdbc jtree treenode

我是Java的新手,我想创建一个包含Map对象的DefaultMutableTreeNode类。

我编写了一个TreeNodeMap类,它继承自更通用的TreeNode类,后者继承自DefaultMutableTreeNode。

TreeNodeMap类包含方法 populate ,它采用了相当长的参数列表。我计划通过将一些参数转换为单个对象并重载方法来改进方法的可读性,这样我就不必在第一次调用中传递一组空值(递归)。

注意:如果您不关心我对方法的详细解释,请直接跳到此处的代码

最初我创建一个只包含子节点而没有数据的空节点,这是ROOT。我们的想法是让一个方法允许调用者使用'field_id','field_label','parent_id'列传递任何查询。在初始调用时,查询与Where子句一起传递,其中'parent_id为null',因此获得所有没有父节点的节点。所有这些节点都添加到ROOT节点。在遍历Resultset时,每个节点的 populate 方法被调用,现在传递一个'Where子句',其中parent_id = [当前节点id],从而获得该节点的所有子节点。这将以递归方式发生,直到使用层次结构创建所有节点。

(请记住,我是JAVA的新手,所以感谢任何反馈)

public void populate( boolean isRoot, String parentFieldId, String parentFieldLabel, String childFieldId, String childFieldLabel, 
            int parentId, String tableName, String whereClause, String orderByClause, String additionalColumns, List<Map<String, String>> queryParams) throws SQLException, Exception{
        ResultSet rs = null;
        Connection con = null;
        PreparedStatement ps = null;
        try{

            DBConnection dbConnection = new DBConnection("localhost", 3306, "root", "password", "test", DBDrivers.DBTYPE_MYSQL);
            con = dbConnection.getConnection();

            String treeNodeSql = "Select " + parentFieldId + ", " + parentFieldLabel + 
                                                ", " + childFieldId + ", " + childFieldLabel;
            if(additionalColumns != null && additionalColumns.trim().length() > 0)
                treeNodeSql +=  " ," + additionalColumns;

            treeNodeSql += " From " + tableName + " WHERE 1=1";

            if(whereClause != null && whereClause.trim().length() > 0 ){
                treeNodeSql += " AND " + whereClause;
            }

            if(isRoot){
                treeNodeSql += " AND " + parentFieldId + " is null";
            }else{
                if(parentFieldId == null || parentFieldId.trim().length() == 0)
                    throw new Exception(" The populate() method requires a parentId when isRoot is false.");
                treeNodeSql += " AND " + parentFieldId + " = ?";
            }
                //order clause append
            if(orderByClause != null && orderByClause.trim().length() > 0)
                treeNodeSql += " " + orderByClause;

                //prepare statement
             ps = con.prepareStatement(treeNodeSql); 
            int ixParam = 0;

                for(Map qParam : queryParams){
                    if(qParam.get("datatype") == "int"){
                        ps.setInt(++ixParam, Integer.parseInt((String) qParam.get("value")));
                    }else if(qParam.get("datatype") == "string"){
                        ps.setString(++ixParam, (String) qParam.get("value"));
                    }
                }

            out.println(treeNodeSql);
            if(parentId > 0){
                ps.setInt(queryParams.size()+1, parentId);
            }
            rs = ps.executeQuery();

            while(rs.next()){
                HashMap<String, Object> childNodeData = new HashMap<String, Object>(4);
                childNodeData.put("parentFieldId", parentFieldId);
                childNodeData.put("parentFieldIdValue", Integer.toString(rs.getInt(parentFieldId)));
                childNodeData.put("parentFieldLabel", parentFieldLabel);
                childNodeData.put("parentFieldLabelValue", rs.getString(parentFieldLabel));
                childNodeData.put("childFieldId", childFieldId);
                childNodeData.put("childFieldIdValue", Integer.toString(rs.getInt(childFieldId)));
                childNodeData.put("childFieldLabel", childFieldLabel);
                childNodeData.put("childFieldLabelValue", rs.getString(childFieldLabel));

                out.println("parentId: " + rs.getInt(parentFieldId)
                                + ", parentLabel: " + rs.getString(parentFieldLabel)
                                + ", childId: " + rs.getInt(childFieldId)
                                + ", childLabel: " + rs.getString(childFieldLabel));
                TreeNodeMap childNode = new TreeNodeMap(childNodeData);
                this.add(childNode);
                childNode.populate(false, parentFieldId, parentFieldLabel, childFieldId, childFieldLabel, rs.getInt(childFieldId), tableName, whereClause, orderByClause, additionalColumns, queryParams);
            }
        }catch(SQLException e){
            throw e;

        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            out.println(e.getCause());
            out.println(e.getMessage());
            e.printStackTrace();
            throw e;
        }finally {
            try { rs.close(); } catch (Exception e) {  }
            try { ps.close(); } catch (Exception e) {  }
            try { con.close(); } catch (Exception e) {  }
        }
    }   

对方法的初始调用如下所示:

treeNode.populate(true, "supervisor_id", "supervisor", "employee_id", "employee", 0, "vw_employee", null, null, null, queryParams);

我用这种方法看到的问题是数据库将被查询X次并且使用大数据集我认为这会导致一些问题。我也为每个查询打开一个连接!所以我考虑在创建方法后(在递归调用中)将Connection传递给方法,但后来我不确定如何正确地关闭它。我可以编写一个条件来检查节点是否是ROOT,然后关闭连接,但如果代码在两者之间失败会发生什么。

所以最后我的问题: 1-最好的方法是什么? 2-我是否应该通过连接,以便在树的种群期间只有一个连接保持打开状态?如果是,那么我该如何正确关闭它。 3-我应该将Resultset缓存到ArrayList中并使用它吗?

1 个答案:

答案 0 :(得分:3)

您的性能问题可能是必要的。取而代之的是,

  1. 实施TreeModel,如此FileTreeModel所示。这样,只需要查询可见节点。这是一个相关的例子here

  2. 通过javax.sql.DataSource,而不是Connection

  3. 您的类implements TreeModel可以封装任何缓存的数据,但也提供了一些更新陈旧条目的方法。显示缓存值后,请考虑使用SwingWorker刷新模型,如图here所示。您可能希望查看List<Record>

  4. ,而不是Map<PrimaryKey, Record>