http://blog.csdn.net/lenotang/article/details/3102727
1. 首先还是主要的显示页面tree.html,这里有两个地方要注意一下,一个是我们引用的JS如果采用GBK的默认编码,浏览器会显示未结束的字符串常量的错误,所以我们一般会修改JS文件的编码方式为UTF-8,或者在导入JS时加上编码字符集。第二个是我们要定义一个显示TreePanel的DIV。
2. 然后是我们的主体JS文件,tree.js,为了凸显主题,这个我已经做了必要的简化,还做了详细的注释,大家好好看一下。
- Ext.onReady(function() {
- Ext.QuickTips.init();
- Ext.BLANK_IMAGE_URL = 'resources/p_w_picpaths/default/s.gif';
-
-
- var Tree = Ext.tree;
-
- var treeloader = new Tree.TreeLoader({
-
- });
-
-
- var treepanel = new Tree.TreePanel({
-
- el : 'tree-panel',
- region : 'west',
- title : '功能菜单',
- width : 200,
- minSize : 180,
- maxSize : 250,
- split : true,
- autoHeight : false,
- frame : true,
-
-
-
- enableDD : true,
- containerScroll : true,
- rootVisible : true,
- border : true,
- animate : true,
- loader : treeloader
-
- });
-
- var rootnode = new Tree.AsyncTreeNode({
- id : '0',
- text : '家电品牌总类',
- draggable : false,
- expanded : true
- });
-
-
- treepanel.setRootNode(rootnode);
-
-
- treepanel.on('beforeload', function(node) {
- treepanel.loader.dataUrl = 'tree.jsp?parentId=' + node.id;
- });
-
- treepanel.render();
-
- rootnode.expand(true);
-
-
- function treeClick(node, e) {
- if (node.isLeaf()) {
- e.stopEvent();
- var n = contentPanel.getComponent(node.id);
- if (!n) {
- var n = contentPanel.add({
- 'id' : node.id,
- 'title' : node.text,
- closable : true,
- autoLoad : {
- url : 'tabFrame.jsp?url=grid.html',
- scripts : true
- }
- });
- }
- contentPanel.setActiveTab(n);
- }
- }
-
- treepanel.on('click', treeClick);
-
-
- var rightClick = new Ext.menu.Menu({
- id : 'rightClickCont',
- items : [{
- id : 'rMenu1',
- text : '添加节点',
-
- handler : function() {
- alert('添加节点的实现!');
- }
- }, {
- id : 'rMenu2',
- text : '编辑节点'
- }, {
- id : 'rMenu3',
- text : '删除节点'
- }]
- });
-
- treepanel.on('contextmenu', function(node, event) {
- event.preventDefault();
- rightClick.showAt(event.getXY());
- });
-
-
-
-
-
-
-
- treepanel.on('nodedrop', function(e) {
-
- if (e.point == 'append') {
- alert('当前"' + e.dropNode.text + '"划到"' + e.target.text
- + '"里面!');
- } else if (e.point == 'above') {
- alert('当前"' + e.dropNode.text + '"放在了"' + e.target.text
- + '"上面!');
- } else if (e.point == 'below') {
- alert('当前"' + e.dropNode.text + '"放在了"' + e.target.text
- + '"下面!');
- }
- });
-
-
- var treeEditer = new Tree.TreeEditor(treepanel, {
- allowBlank : false
- });
-
-
-
-
-
- treeEditer.on("beforestartedit", function(treeEditer) {
- var tempNode = treeEditer.editNode;
- if (tempNode.isLeaf()) {
- return true;
- } else {
- return false;
- }
- });
-
- treeEditer.on("complete", function(treeEditer) {
- alert("被修改为" + treeEditer.editNode.text);
- });
-
-
-
-
-
-
-
-
-
- treepanel.root.appendChild(new Ext.tree.TreeNode({
- id : 'htmlPanel',
- text : '通过html打开',
- listeners : {
- 'click' : function(node, event) {
- event.stopEvent();
- var n = contentPanel.getComponent(node.id);
- if (!n) {
- n = contentPanel.add({
- 'id' : node.id,
- 'title' : node.text,
- closable : true,
- html : '<iframe scrolling="auto" frameborder="0" width="100%" height="100%" src="grid.html"></iframe>'
- });
- }
- contentPanel.setActiveTab(n);
- }
- }
- }));
-
-
- treepanel.root.appendChild(new Ext.tree.TreeNode({
- id : 'autoLoadPanel',
- text : '通过autoLoad打开',
- listeners : {
- 'click' : function(node, event) {
- event.stopEvent();
- var n = contentPanel.getComponent(node.id);
- if (!n) {
- n = contentPanel.add({
- 'id' : node.id,
- 'title' : node.text,
- closable : true,
- autoLoad : {
- url : 'tabFrame.jsp?url=grid.html',
- scripts : true
- }
- });
- }
- contentPanel.setActiveTab(n);
- }
- }
- }));
-
-
- var contentPanel = new Ext.TabPanel({
- region : 'center',
- enableTabScroll : true,
- activeTab : 0,
- items : [{
- id : 'homePage',
- title : '首页',
- autoScroll : true,
- html : '<div style="position:absolute;color:#ff0000;top:40%;left:40%;">Tree控件和TabPanel控件结合功能演示</div>'
- }]
- });
-
- new Ext.Viewport({
- layout : 'border',
- defaults : {
- activeItem : 0
- },
- items : [treepanel, contentPanel]
- });
-
- });
3. 再接着是tree.js中ExtJS的TreeLoader调用的tree.jsp,在目录树上点击TreeNode后会加载下一级节点。tree.jsp负责TreeNode点击后,传回由下一级节点构造的JSON数据,也就是前台树异步请求访问的后台WEB组件。它会调用JAVABEAN操作数据库,得到每个节点的子节点数据。这里由于我们后台需要返回给客户端JSON格式的数据,也就是需要操作JSON数据格式。所以我们首先要下载JSON-lib,地址:http://json-lib.sourceforge.net/打开网址后,首页上有一段话:
Json-lib requires (at least) the following dependencies in your classpath:
jakarta commons-lang 2.3
jakarta commons-beanutils 1.7.0
jakarta commons-collections 3.2
jakarta commons-logging 1.1.1
ezmorph 1.0.4
需要下载上述jar文件,配合JSON-lib 一起使用。
commons 下载地址:http://commons.apache.org/
ezmorph 下载地址:http://ezmorph.sourceforge.net
或者,到 http://www.docjar.com 搜索下载。
JSON的用法,我们已经提过多次,大家可参考相关文档。看看tree.jsp的代码:
<%@ page language="java" pageEncoding="utf-8"%>
<jsp:useBean class="org.leno.javabean.JSONTree" id="JSONTree"></jsp:useBean>
<%
String parentId = "";
if (request.getParameter("parentId") != null) {
parentId = request.getParameter("parentId").toString();
}
JSONTree.setparentId(parentId);
%>
<%=JSONTree.getJSONString()%>
4. 后台用到的JAVA类,这里包括访问数据库的数据源工厂类DataSourceFactory(这里用到了DBCP连接池,大家要记得导入连接sqlserver 2000数据库和dbcp连接池的相关JAR包!),定义树节点的属性,包括节点ID、Text、图标、是否为叶子节点、是否展开等的类JSONTreeNode,还有类似DAO能够封装数据访问和格式转换细节的JSONTree。
-
- package org.leno.javabean;
-
- import java.sql.SQLException;
- import org.apache.commons.dbcp.BasicDataSource;
-
- public class DataSourceFactory {
-
-
-
-
- private static BasicDataSource ds;
-
- public static BasicDataSource getDataSource() {
- if (ds == null) {
- ds = new BasicDataSource();
- ds.setDriverClassName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
- ds.setUrl("jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=java28");
- ds.setUsername("sa");
- ds.setPassword("123");
- ds.setMaxActive(5);
- }
- return ds;
-
- }
-
- public static void main(String[] args) {
-
- try {
- System.out.println(DataSourceFactory.getDataSource()
- .getConnection());
- } catch (SQLException e) {
-
- e.printStackTrace();
- }
-
- }
-
- }
- package org.leno.javabean;
-
-
-
-
-
- public class JSONTreeNode {
-
- private String id;
- private String text;
- private String cls;
- private boolean leaf;
- private String href;
- private String hrefTarget;
- private boolean expandable;
- private String description;
-
- get/set……
- }
- package org.leno.javabean;
-
- import java.sql.*;
- import java.util.*;
- import net.sf.json.JSONArray;
-
- public class JSONTree {
- private String parentId;
-
- public String getJSONString(){
- Connection con =null;
- Statement st = null;
- ResultSet rs = null;
- List<JSONTreeNode> treeNodeArray = null;
-
- String SQLString = "SELECT * FROM Categories WHERE parentId="+this.parentId+" ORDER BY categoryId";
-
- try
- {
- con = DataSourceFactory.getDataSource().getConnection();
- st = con.createStatement();
-
- rs = st.executeQuery("SELECT parentId FROM Categories WHERE parentId>0 Group By parentId Order By parentId");
-
- StringBuffer parentIDBuffer =new StringBuffer();
- parentIDBuffer.append("|");
- while(rs.next())
- {
- parentIDBuffer.append(rs.getString("parentId"));
- parentIDBuffer.append("|");
- }
-
- String parentIDString = parentIDBuffer.toString();
-
- rs = st.executeQuery(SQLString);
- treeNodeArray = new ArrayList<JSONTreeNode>();
- while(rs.next())
- {
- JSONTreeNode treeNode = new JSONTreeNode();
- String categoryId = rs.getString("categoryId");
- treeNode.setId(categoryId);
- treeNode.setText(rs.getString("categoryName"));
- treeNode.setDescription(rs.getString("description"));
-
-
-
-
- if (parentIDString.indexOf("|"+categoryId+"|")>=0)
- {
- treeNode.setCls("folder");
- treeNode.setLeaf(false);
- treeNode.setExpandable(false);
- }
- else
- {
- treeNode.setCls("file");
- treeNode.setLeaf(true);
- treeNode.setExpandable(false);
- }
- treeNodeArray.add(treeNode);
- }
-
- JSONArray JsonArray = JSONArray.fromObject(treeNodeArray);
-
- return JsonArray.toString();
- }
- catch(Exception e)
- {
- System.out.println("getJSONString() of JSONTree.java throws : "+e.toString());
- return "";
- }
- finally
- {
- try {
- if(con!=null&&!con.isClosed()){
- con.close();
- }
- } catch (SQLException e) {
-
- e.printStackTrace();
- }
- }
- }
-
-
- public String getparentId() {
- return parentId;
- }
-
- public void setparentId(String parentId) {
- this.parentId = parentId;
- }
-
- }
5. 最后是我们的数据库脚本script.sql,大家用SQLServer 2000数据库创建一个java28的database,然后执行下列脚本即可。