Struts1基于Json数据格式的ExtJs单选树(Struts1+Spring+Hibernate)

功能描述:根据Json格式数据生成单选树,然后将选择后的数据回调到文本框中

与别的服务器上系统对接的接口:

http://172.16.1.136:5000/tjfae_oa_service/org/orgtree?parentId=0&code=e8ca9f833c615e52647b4e88b87bc32c&type=oa&time=1332746215687,当在地址栏中输入该地址会返回json格式的数据

json数据格式:[{"id":"1","text":"根机构","leaf":false}],

当parentId=1时,数据为:[{"id":"20","text":"山东资产交易所","leaf":false},{"id":"10","text":"北京地区总部","leaf":true},{"id":"30","text":"上海地区总部","leaf":true}, {"id":"40","text":"深圳地区总部","leaf":true}]

同理:当从action跳转时也一样:/members/urlEncapsulation.do?parentId=0

一、先看效果图再贴代码:

1、

2、当点击上图的"选择管理员",就会通过action跳转到一个新的窗口(我的是RadioTree.jsp),然后显示以下数据

3、当点击根机构时,实现异步加载形成单选树结构

4、当选中一个员工,确定,将选中的员工回调到文本框

二、以上是效果图,接下来是实现的代码:

1、userRadioTree.jsp代码:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
String Path = request.getContextPath();
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <!-- base library -->
    <link rel="stylesheet" type="text/css" href="/scripts/ext/resources/css/ext-all.css" />
    <link rel="stylesheet" type="text/css" href="/scripts/ext/resources/css/css.css" />
    <!-- ExtJS library: base/adapter -->
    <script type="text/javascript" src="/scripts/ext/adapter/ext/ext-base.js"></script>
    <!-- ExtJS library: all widgets -->
    <script type="text/javascript" src="/scripts/ext/ext-all.js"></script>
    <script type="text/javascript" src="/scripts/ext/TreeCheckNodeUI.js"></script>   //该js好多版本都没有,但是对于单选树来说很重要,(如果不加的话可能会形成复选框,这一点我没有试)我会在下面将代码贴出来
    <script type="text/javascript" src="/scripts/ext/ext-lang-zh_CN.js"></script>
  <script type="text/javascript">
      
      Ext.onReady(function(){
        
         var treeLoader = new Ext.tree.TreeLoader({
             baseAttrs: {uiProvider: Ext.ux.TreeCheckNodeUI }   
         });
         
         // 添加一个树形面板
        var treepanel = new Ext.tree.TreePanel({
            // renderTo:"tree_div",//如果使用renderTo,则不能使用setRootNode()方法,需要在TreePanel中设置root属性。
            el : 'tree-panel',// 将树形添加到一个指定的div中,非常重要!
            baseCls:'',
            region : 'west',
            title : '人员单选树',
            width : 200,
            minSize : 180,
            maxSize : 250,
            split : true,
            autoHeight : false,
            frame : true,// 美化界面
            autoScroll : true, // 自动滚动
            enableDD : false,// 是否支持拖拽效果
            onlyLeafCheckable: true,  
            containerScroll : true,// 是否支持滚动条
            checkModel: 'single',   // 对树的级联多选     多选: 'multiple'(默认)单选: 'single'
                                           //级联多选: 'cascade'(同时选父和子); 'parentCascade'(选父);'childCascade'(选子)
            rootVisible : false, // 是否隐藏根节点,很多情况下,我们选择隐藏根节点增加美观性
            border : true, // 边框
            animate : true, // 动画效果
            loader : treeLoader,
            buttons: [{
                 text: '确认',
                    handler: function(){
                        var chooseNodeName = '',chooseNodeId = '',selNodes = treepanel.getChecked();
                        var chooseParentId='',chooseParentName='';
                        Ext.each(selNodes, function(node){
                            if(chooseNodeName.length > 0){
                                chooseNodeName += ',';
                                chooseNodeId += ',';
                            }
                            chooseNodeName += node.text;//选中的员工姓名
                            chooseNodeId += node.id;//选中的员工ID
                            chooseParentId=node.parentNode.id;//父结点ID,此处一定要注意:node.parentNode后面一定要加.id,不加的话在火狐不报错,在IE就会报
                        });
                        window.opener.userRadioCallBack(chooseNodeId,chooseNodeName,'',chooseParentId);//回调函数同样重要
                        window.close();
                        
                    }
           }]
        });
        
        // 异步加载根节点
        var rootnode = new Ext.tree.AsyncTreeNode({
            id : '${rootId}', //根结点ID,因为我的根结点为0(parentId=0),所以id也可以直接写成"id:0",当然你也可以根据自己的需求用uuid来表示,或者用其他变量表示都可以
            text : '根节点',
            draggable : false,// 根节点不容许拖动
            expanded : true
        });

        // 为tree设置根节点
        treepanel.setRootNode(rootnode);
        
         // 响应加载前事件,传递node参数
        treepanel.on('beforeload', function(node) {
           treepanel.loader.dataUrl = "${Path}/members/interdomainTurnAction.htm?parentId="+node.id+""; // 定义子节点的Loader,此处调用action就是实现了点击不同结点,展开不同的机构
        });
        
        // 渲染树形
        treepanel.render();
         
        // 展开节点,第一个参数表示是否级联展开子节点
        rootnode.expand(false);//默认为false
        
    });  
  </script>
  <body>
            <div id="tree-panel" align="left" style="margin-left:auto; margin-right:auto"></div>
  </body>
</html>

2、/members/interdomainTurnAction.htm跳转的action:  InterdomainTurnAction(异步加载结点形成树结构,不需要跳转任何页面)

package com.score.web.action.members;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;


import com.score.common.util.Security;
import com.score.web.action.core.BaseAction;
/**
 * 跨域跳转,根据接口获取不同服务器上的数据,写入到相应的页面,并生成单选树
 * @author Administrator
 *
 */
public class InterdomainTurnAction extends BaseAction {
    public ActionForward execute(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        PrintWriter out = response.getWriter();
        String urlString = "http://172.16.1.136:5000/tjfae_oa_service/org/usertree?";//此处为另一台服务器上的接口,当然我们也可以用自己的action地址来实现该功能(在自己的action中实现返回json数据的方法,格式一定要和上面的json格式一样,其他的json格式没试过)
        String  type = "oa";//加密用(自己的里面也可以不用写)
        Date date = new Date();
        Long timeLong = date.getTime();//加密用(自己的里面也可以不用写)
        String keys = type+timeLong; //加密用(自己的里面也可以不用写)
        //接收从userRadioTree.jsp页面传过来的当前节点
        String pid = request.getParameter("parentId");
        //进行加密,获取32位密码
        String result =Security.getPassword(keys, "UTF-8");//该方法为加密方法,同上面一样用来加密的,可以不用写(加密方法在我的博客中有[MD5加密],可以自己找,此处就不贴代码了)
        //拼接URL
        StringBuffer sBuffer = new StringBuffer();
        sBuffer.append(urlString).append("parentId=").append(pid).append("&code=").append(result).append("&type=").append(type).append("&time=").append(timeLong);
        // 根据拼凑的URL,打开连接,URL.openConnection函数会根据URL的类型,
        // 返回不同的URLConnection子类的对象,这里URL是一个http,因此实际返回的是HttpURLConnection       
        URL getUrl = new URL(sBuffer.toString());
        HttpURLConnection connection = (HttpURLConnection) getUrl
                .openConnection();
        // 进行连接,但是实际上get request要在下一句的connection.getInputStream()函数中才会真正发到服务器
        connection.connect();
        // 取得输入流,并使用Reader读取
        BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(),"utf-8"));//设置编码,否则中文乱码
        System.out.println("=============================");
        System.out.println("InterdomainTurnAction....");
        System.out.println("=============================");
        String lines;
        //如果读取的数据不为null的话,将数据写入页面
        while ((lines = reader.readLine()) != null){
            out.print(lines);
            System.out.println(lines);
        }
        //关闭输入流
        reader.close();
        return null;
    }
}
3、选择管理员页面(效果图1所在的页面selectManager.jsp)设置:

    <table width="100%" border="0" cellpadding="0" cellspacing="1" bgcolor="#a8c7ce">
        <tr>
            <td height="20" class="STYLE6" width="30%">
                   管理员:
            </td>
            <td class="STYLE10" width="65%"> 
              <input type="hidden" id="managerId" name="managerId" />
              <input type="text" id="managerName" name="managerName" readonly="readonly"  />
            <input type="button" onclick="selectManager()" value="选择管理员"/>    
            </td>
        </tr>
    </table>

selectManager.jsp页面JavaScript代码:

//选择管理员
function selectManager(){
    window.open("/members/urlEncapsulation.htm");
}
//回调函数,(userRadioTree.jsp)返回OA系统办工人员的ID及姓名,并赋值给文本框

//注意:回调函数一定要和InterdomainTurnAction里面的回调函数一致
  function userRadioCallBack(chooseNodeId,chooseNodeName,n){
    $("#managerId").val(chooseNodeId);
    $("#managerName").val(chooseNodeName);
  }

4、/members/urlEncapsulation.htm action:

package com.score.web.action.members;




import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import com.score.web.action.core.BaseAction;
/**
 * 跳转单选树页面
 * @author Administrator
 *
 */
public class UrlEncapsulationAction extends BaseAction{
    public ActionForward execute(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        //获取根节点        
        String rootId = request.getParameter("parentId");
        if("".equals(rootId)||rootId==null){//如果根节点为空的话,将根节点设置为0
            rootId="0";
        }
        System.out.println("-------UrlEncapsulationAction--------->>>"+rootId);
        request.setAttribute("rootId", rootId);
        return mapping.findForward("oaUrl");    
    }
}
5、TreeCheckNodeUI.js(此处代码不需要修改,只需要引用即可)

/**
 * @class Ext.ux.TreeCheckNodeUI
 * @extends Ext.tree.TreeNodeUI
 *
 * 对 Ext.tree.TreeNodeUI 进行checkbox功能的扩展,后台返回的结点信息不用非要包含checked属性
 *
 * 扩展的功能点有:
 * 一、支持只对树的叶子进行选择
 *    只有当返回的树结点属性leaf = true 时,结点才有checkbox可选
 *       使用时,只需在声明树时,加上属性 onlyLeafCheckable: true 既可,默认是false
 *
 * 二、支持对树的单选
 *    只允许选择一个结点
 *       使用时,只需在声明树时,加上属性 checkModel: "single" 既可
 *
 * 二、支持对树的级联多选
 *    当选择结点时,自动选择该结点下的所有子结点,或该结点的所有父结点(根结点除外),特别是支持异步,当子结点还没显示时,会从后台取得子结点,然后将其选中/取消选中
 *    使用时,只需在声明树时,加上属性 checkModel: "cascade" 或"parentCascade"或"childCascade"既可
 *
 * 三、添加"check"事件
 *    该事件会在树结点的checkbox发生改变时触发
 *    使用时,只需给树注册事件,如:
 *    tree.on("check",function(node,checked){...});
 *
 * 默认情况下,checkModel为'multiple',也就是多选,onlyLeafCheckable为false,所有结点都可选
 *
 * 使用方法:在loader里加上 baseAttrs:{uiProvider:Ext.ux.TreeCheckNodeUI} 既可.
 * 例如:
 *   var tree = new Ext.tree.TreePanel({
 *        el:'tree-ct',
 *        width:568,
 *        height:300,
 *        checkModel: 'cascade',   //对树的级联多选
 *        onlyLeafCheckable: false,//对树所有结点都可选
 *        animate: false,
 *        rootVisible: false,
 *        autoScroll:true,
 *        loader: new Ext.tree.DWRTreeLoader({
 *            dwrCall:Tmplt.getTmpltTree,
 *            baseAttrs: { uiProvider: Ext.ux.TreeCheckNodeUI } //添加 uiProvider 属性
 *        }),
 *        root: new Ext.tree.AsyncTreeNode({ id:'0' })
 *    });
 *    tree.on("check",function(node,checked){alert(node.text+" = "+checked)}); //注册"check"事件
 *    tree.render();
 *
 */

Ext.ux.TreeCheckNodeUI = function() {
    //多选: 'multiple'(默认)
    //单选: 'single'
    //级联多选: 'cascade'(同时选父和子);'parentCascade'(选父);'childCascade'(选子)
    this.checkModel = 'multiple';
    
    //only leaf can checked
    this.onlyLeafCheckable = false;
    
    Ext.ux.TreeCheckNodeUI.superclass.constructor.apply(this, arguments);
};

Ext.extend(Ext.ux.TreeCheckNodeUI, Ext.tree.TreeNodeUI, {

    renderElements : function(n, a, targetNode, bulkRender){
        var tree = n.getOwnerTree();
        this.checkModel = tree.checkModel || this.checkModel;
        this.onlyLeafCheckable = tree.onlyLeafCheckable || false;
        
        // add some indent caching, this helps performance when rendering a large tree
        this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';

        //var cb = typeof a.checked == 'boolean';
        var cb = (!this.onlyLeafCheckable || a.leaf);
        var href = a.href ? a.href : Ext.isGecko ? "" : "#";
        var buf = ['<li class="x-tree-node"><div ext:tree-node-id="',n.id,'" class="x-tree-node-el x-tree-node-leaf x-unselectable ', a.cls,'" unselectable="on">',
            '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
            '<img src="', this.emptyIcon, '" class="x-tree-ec-icon x-tree-elbow" />',
            '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
            cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : '/>')) : '',
            '<a hidefocus="on" class="x-tree-node-anchor" href="',href,'" tabIndex="1" ',
             a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "", '><span unselectable="on">',n.text,"</span></a></div>",
            '<ul class="x-tree-node-ct" style="display:none;"></ul>',
            "</li>"].join('');

        var nel;
        if(bulkRender !== true && n.nextSibling && (nel = n.nextSibling.ui.getEl())){
            this.wrap = Ext.DomHelper.insertHtml("beforeBegin", nel, buf);
        }else{
            this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf);
        }
        
        this.elNode = this.wrap.childNodes[0];
        this.ctNode = this.wrap.childNodes[1];
        var cs = this.elNode.childNodes;
        this.indentNode = cs[0];
        this.ecNode = cs[1];
        this.iconNode = cs[2];
        var index = 3;
        if(cb){
            this.checkbox = cs[3];
            Ext.fly(this.checkbox).on('click', this.check.createDelegate(this,[null]));
            index++;
        }
        this.anchor = cs[index];
        this.textNode = cs[index].firstChild;
    },
    
    // private
    check : function(checked){
        var n = this.node;
        var tree = n.getOwnerTree();
        this.checkModel = tree.checkModel || this.checkModel;
        
        if( checked === null ) {
            checked = this.checkbox.checked;
        } else {
            this.checkbox.checked = checked;
        }
        
        n.attributes.checked = checked;
        tree.fireEvent('check', n, checked);
        
        if(this.checkModel == 'single'){
            var checkedNodes = tree.getChecked();
            for(var i=0;i<checkedNodes.length;i++){
                var node = checkedNodes[i];
                if(node.id != n.id){
                    node.getUI().checkbox.checked = false;
                    node.attributes.checked = false;
                    tree.fireEvent('check', node, false);
                }
            }
        } else if(!this.onlyLeafCheckable){
            if(this.checkModel == 'cascade' || this.checkModel == 'parentCascade'){
                var parentNode = n.parentNode;
                if(parentNode !== null) {
                    this.parentCheck(parentNode,checked);
                }
            }
            if(this.checkModel == 'cascade' || this.checkModel == 'childCascade'){
                if( !n.expanded && !n.childrenRendered ) {
                    n.expand(false,false,this.childCheck);
                }else {
                    this.childCheck(n);  
                }
            }
        }
    },

    
    // private
    childCheck : function(node){
        var a = node.attributes;
        if(!a.leaf) {
            var cs = node.childNodes;
            var csui;
            for(var i = 0; i < cs.length; i++) {
                csui = cs[i].getUI();
                if(csui.checkbox.checked ^ a.checked)
                    csui.check(a.checked);
            }
        }
    },
    
    // private
    parentCheck : function(node ,checked){
        var checkbox = node.getUI().checkbox;
        if(typeof checkbox == 'undefined')return ;
        if(!(checked ^ checkbox.checked))return;
        if(!checked && this.childHasChecked(node))return;
        checkbox.checked = checked;
        node.attributes.checked = checked;
        node.getOwnerTree().fireEvent('check', node, checked);
        
        var parentNode = node.parentNode;
        if( parentNode !== null){
            this.parentCheck(parentNode,checked);
        }
    },
    
    // private
    childHasChecked : function(node){
        var childNodes = node.childNodes;
        if(childNodes || childNodes.length>0){
            for(var i=0;i<childNodes.length;i++){
                if(childNodes[i].getUI().checkbox.checked)
                    return true;
            }
        }
        return false;
    },
    
    toggleCheck : function(value){
        var cb = this.checkbox;
        if(cb){
            var checked = (value === undefined ? !cb.checked : value);
            this.check(checked);
        }
    }
});

posted @ 2012-05-04 13:41  中国聚龙  阅读(1844)  评论(0编辑  收藏  举报