Extjs4 treePanel異步加載菜單(后台從數據庫讀取)


運行環境:springMVC+mybatis

 

一、建表

說明:0表示此節點為非葉子節點,即此節點還包括了子節點;1表示此節點為葉子節點,即此節點沒有子節點。;關於圖標iconCls是從Extjs的文件的icons文件夾找的。命名方式是把找到的圖標名去掉下划線,然后首字母大寫即可。

二、運用mybatis 的generator插件自動生成pojo、映射文件及訪問接口並做適當的添加修改。

1.pojo

package com.shyy.web.entity;

import java.util.List;

public class Tree {
    private String id;

    private String text;

    private String iconCls;

    private Boolean leaf;

    private String fatherId;

    private List<Tree> children;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public String getIconCls() {
        return iconCls;
    }

    public void setIconCls(String iconCls) {
        this.iconCls = iconCls;
    }

    public Boolean getLeaf() {
        return leaf;
    }

    public void setLeaf(Boolean leaf) {
        this.leaf = leaf;
    }

    public String getFatherId() {
        return fatherId;
    }

    public void setFatherId(String fatherId) {
        this.fatherId = fatherId;
    }

    public List<Tree> getChildren() {
        return children;
    }

    public void setChildren(List<Tree> children) {
        this.children = children;
    }

    @Override
    public String toString() {
        return "Tree{" +
                "id='" + id + '\'' +
                ", text='" + text + '\'' +
                ", iconCls='" + iconCls + '\'' +
                ", leaf=" + leaf +
                ", fatherId='" + fatherId + '\'' +
                ", children=" + children +
                '}';
    }
}

2.映射文件:

需要注意的是, <result property="leaf" column="leaf" jdbcType="TINYINT" javaType="Boolean" />這樣的話,mybatis就會自動將數據庫中的TINYINT類型的leaf轉化成布爾類型,0會轉化為false,1會轉化為true。這里一定要有這個,不然在執行時會報異常。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.shyy.web.service.TreeMapper" >
  <resultMap id="BaseResultMap" type="com.shyy.web.entity.Tree" >
    <id column="id" property="id" jdbcType="VARCHAR" />
    <result column="text" property="text" jdbcType="VARCHAR" />
    <result column="iconCls" property="iconCls" jdbcType="VARCHAR" />
    <result column="leaf" property="leaf" jdbcType="TINYINT" javaType="Boolean" />
    <result column="fatherId" property="fatherId" jdbcType="VARCHAR" />
  </resultMap>
  <sql id="Base_Column_List" >
    id, text, iconCls, leaf, fatherId
  </sql>
  <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.String" >
    select 
    <include refid="Base_Column_List" />
    from t_tree
    where id = #{id,jdbcType=VARCHAR}
  </select>
  <select id="getFather" resultMap="BaseResultMap">
      SELECT
      <include refid="Base_Column_List" />
      FROM t_tree
      WHERE fatherId IS NULL
  </select>
  <select id="getChildren" resultMap="BaseResultMap" parameterType="java.lang.String">
      SELECT
      <include refid="Base_Column_List" />
      FROM t_tree
      WHERE fatherId = #{fatherId}
  </select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.String" >
    delete from t_tree
    where id = #{id,jdbcType=VARCHAR}
  </delete>
  <insert id="insert" parameterType="com.shyy.web.entity.Tree" >
    insert into t_tree (id, text, iconCls, 
      leaf, fatherId)
    values (#{id,jdbcType=VARCHAR}, #{text,jdbcType=VARCHAR}, #{iconCls,jdbcType=VARCHAR}, 
      #{leaf,jdbcType=TINYINT}, #{fatherId,jdbcType=VARCHAR})
  </insert>
  <insert id="insertSelective" parameterType="com.shyy.web.entity.Tree" >
    insert into t_tree
    <trim prefix="(" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        id,
      </if>
      <if test="text != null" >
        text,
      </if>
      <if test="iconCls != null" >
        iconCls,
      </if>
      <if test="leaf != null" >
        leaf,
      </if>
      <if test="fatherId != null" >
        fatherId,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        #{id,jdbcType=VARCHAR},
      </if>
      <if test="text != null" >
        #{text,jdbcType=VARCHAR},
      </if>
      <if test="iconCls != null" >
        #{iconCls,jdbcType=VARCHAR},
      </if>
      <if test="leaf != null" >
        #{leaf,jdbcType=TINYINT},
      </if>
      <if test="fatherId != null" >
        #{fatherId,jdbcType=VARCHAR},
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="com.shyy.web.entity.Tree" >
    update t_tree
    <set >
      <if test="text != null" >
        text = #{text,jdbcType=VARCHAR},
      </if>
      <if test="iconCls != null" >
        iconCls = #{iconCls,jdbcType=VARCHAR},
      </if>
      <if test="leaf != null" >
        leaf = #{leaf,jdbcType=TINYINT},
      </if>
      <if test="fatherId != null" >
        fatherId = #{fatherId,jdbcType=VARCHAR},
      </if>
    </set>
    where id = #{id,jdbcType=VARCHAR}
  </update>
  <update id="updateByPrimaryKey" parameterType="com.shyy.web.entity.Tree" >
    update t_tree
    set text = #{text,jdbcType=VARCHAR},
      iconCls = #{iconCls,jdbcType=VARCHAR},
      leaf = #{leaf,jdbcType=TINYINT},
      fatherId = #{fatherId,jdbcType=VARCHAR}
    where id = #{id,jdbcType=VARCHAR}
  </update>
</mapper>

3.訪問映射文件的接口(沒有實現類,直接由該接口訪問對應的映射文件)

package com.shyy.web.service;

import com.shyy.web.entity.Tree;

import java.util.List;

public interface TreeMapper {
    int deleteByPrimaryKey(String id);

    int insert(Tree record);

    int insertSelective(Tree record);

    Tree selectByPrimaryKey(String id);

    List<Tree> getFather();

    List<Tree> getChildren(String id);

    int updateByPrimaryKeySelective(Tree record);

    int updateByPrimaryKey(Tree record);
}

4.控制層代碼

package com.shyy.web.controller.anntation;

import java.util.ArrayList;
import java.util.List;

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

import com.shyy.web.entity.Tree;
import com.shyy.web.service.TreeMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.shyy.web.controller.response.EmptyResponse;
import com.shyy.web.controller.response.NormalResponse;
import com.shyy.web.controller.response.Response;
import com.shyy.web.entity.Privilege;
import com.shyy.web.service.PrivilegeService;
import com.shyy.web.service.impl.PrivilegeServiceImpl;

@Controller
@RequestMapping("/menu/")
public class PrivilegeController {

    Logger logger = LoggerFactory.getLogger(PrivilegeController.class);

    @Autowired
    private TreeMapper treeMapper;


    @SuppressWarnings("unused")
    @RequestMapping("showmyMenu")
    @ResponseBody
    public List<Tree> myMenus(HttpServletRequest req, HttpServletResponse resp) {
        System.out.println("-aaa--");
        List<Tree> pris = treeMapper.getFather();//一級菜單
        List<Tree> menus = new ArrayList<Tree>();

        for(Tree pri:pris){//迭代一級菜單找二級菜單
            List<Tree> prisNode = treeMapper.getChildren(pri.getId());//二級菜單
            pri.setChildren(prisNode);

            for (Tree privilege : prisNode) {//迭代二級菜單找三級菜單
                List<Tree> childNode = treeMapper.getChildren(privilege.getId());//三級菜單
                privilege.setChildren(childNode);
                //如果有四級菜單,則需迭代三級菜單找四級菜單
            }
            menus.add(pri);
        }

        System.out.println(menus);

        if (menus != null || menus.size() > 0) {
            return menus;
        } else {
            return null;
        }
    }

    public String test(){
        return "wang";
    }

}

js代碼:

Ext.onReady(function(){

            var model = Ext.define("TreeModel", { // 定義樹節點數據模型
                extend : "Ext.data.Model",
                fields : [{name : "id",type : "string"},
                    {name : "text",type : "string"},
                    {name : "iconCls",type : "string"},
                    {name : "leaf",type : "boolean"},
                    {name : 'url',type:"string"},
                    {name : 'description',type:"string"}]
            });

            var store = Ext.create('Ext.data.TreeStore', {
                model : model,//定義當前store對象的Model數據模型
//                autoLoad : true,
                proxy : {
                    type : 'ajax',
                    url : '../menu/showmyMenu',//請求
                    reader : {
                        type : 'json',
//                        root : 'data'//數據
                    }
                },
                root : {//定義根節點,此配置是必須的
//                    text : '管理菜單',
                    expanded : true
                }

            });

            Ext.create('Ext.tree.Panel', {
                title: 'Simple Tree',
                width: 200,
                height: 550,
                store: store,
                rootVisible: false,//隱藏根節點
                renderTo: Ext.getBody()
            });

  });

說明:在http://liuchangming1993-126-com.iteye.com/blog/1938482文章中的博主用的struts2,返回形式與本文的springMVC不同,因此這里沒有指定root屬性。

 

下面看一下js中的ajax請求返回的數據(片段):

[Tree{id='101', text='圖像報表', iconCls='Chartbar', leaf=false, fatherId='null',
children=[Tree{id='1001', text='餅狀圖', iconCls='Chartpie', leaf=false, fatherId='101', children=[Tree{id='10001', text='餅狀圖一', iconCls='Chartpieadd', leaf=true, fatherId='1001', children=null}, Tree{id='10002', text='餅狀圖二', iconCls='Chartpiedelete', leaf=true, fatherId='1001', children=null}]},
Tree{id='1002', text='線狀圖', iconCls='Chartline', leaf=false, fatherId='101', children=[Tree{id='10003', text='線狀圖一', iconCls='Chartcurveadd', leaf=true, fatherId='1002', children=null}, Tree{id='10004', text='線狀圖二', iconCls='Chartcurvedelete', leaf=true, fatherId='1002', children=null}]}]}]

可以看出是reader 將對象的數據轉化成了json格式。

 

運行效果:

 

方法二

這里的邏輯是一次性加載完所有的菜單返回至前台,在http://liuchangming1993-126-com.iteye.com/blog/1938482的博客中用到的是另一種方式,即根據用戶點擊的菜單展開子菜單。

現在用這種方式實現一下:

說明:因為之前建的表t_tree與pojo的主鍵都是id,發現與Extjs沖突,所以這次將表的主鍵改為tid,然后自動生成相應代碼。

一、在映射文件中加一個sql

    <select id="findLeaf" parameterType="String" resultMap="BaseResultMap">
        SELECT
        <include refid="Base_Column_List" />
        FROM t_tree
        WHERE 1=1
        <choose>
            <when test="_parameter!=null and _parameter!=''">
                and fatherId = #{fatherId}
            </when>
            <otherwise>
                and fatherId IS NULL
            </otherwise>
        </choose>
    </select>

二、修改訪問映射文件的接口,即增加訪問上面sql的方法

package com.shyy.web.service;

import com.shyy.web.entity.Tree;

import java.util.List;

public interface TreeMapper {
    int deleteByPrimaryKey(String tid);

    int insert(Tree record);

    int insertSelective(Tree record);

    Tree selectByPrimaryKey(String tid);

    List<Tree> getFather();

    List<Tree> getChildren(String id);

    List<Tree> findLeaf(String id);

    int updateByPrimaryKeySelective(Tree record);

    int updateByPrimaryKey(Tree record);
}

三、修改控制器,增加一個方法

    @SuppressWarnings("unused")
    @RequestMapping("showmyMenu2")
    @ResponseBody
    public List<Tree> myMenus2(HttpServletRequest req, HttpServletResponse resp,@RequestParam String tid) {

        System.out.println("tid:"+tid);

        List<Tree> menus = new ArrayList<Tree>();
        menus = treeMapper.findLeaf(tid);

        if (menus != null || menus.size() > 0) {
            return menus;
        } else {
            return null;
        }
    }

四、修改js

        Ext.onReady(function(){
            var store = Ext.create('Ext.data.TreeStore', {
                autoLoad : true,
                proxy : {
                    type : 'ajax',
                    url : '../menu/showmyMenu2',//請求
                    reader : {
                        type : 'json',
//                        root : 'menuList'//數據
                    },
                    //傳參
                    extraParams : {
                        tid : ''
                    }
                },
                root : {
//                    text : '管理菜單',
                    expanded : true
                },
                listeners : {
                    'beforeexpand' : function(node,eOpts){
                        //點擊父親節點的菜單會將節點的id通過ajax請求,將到后台
                        this.proxy.extraParams.tid = node.raw.tid;
                    }
                }
            });

            Ext.create('Ext.tree.Panel', {
                renderTo : Ext.getBody(),
                title : '動態加載TreePanel',
                width : 300,
                height : 500,
                useArrows : true,
                rootVisible: false,
                store : store
            });

        });

注:

1. 這個配置默認是false,但是即使注釋掉此配置也是沒有影響的;

2.可以看出上面的js已去掉了model 配置,是沒有影響的,在Ext.data.TreeStore的API中有這樣的說明:

Using Models 用例模型

如果未指定模型Model,將創建實現於Ext.data.NodeInterface的一種隱式模型。 標准的Tree字段列表也將被復制到Model上來保持自身的狀態。 在Ext.data.NodeInterface文檔中列出了這些字段。

 

那么model是干嘛的(如上面的創建的繼承於Ext.data.Model的實例"TreeModel"),NodeInterface又是干嘛的?下面看一下Ext.data.NodeInterface的API簡介:

本類是一個應用到Model的原型上的方法集合,使其具有Node API。這意味着樹狀模型 具有所有與樹相關的方法。通常情況下, 開發者不會直接使用本類。為了保存樹的狀態和UI, 本類會在模型上創建一些額外的字段(如果它們不存在)。 這些字段記錄為config選項。

 

到這里model的作用就明確了,舉例來說,像本文定義的model,比如它有一個字段名為“leaf”,那么由於在Ext.data.NodeInterface中也具有這個配置屬性,所以這個leaf的值會在加載時起作用。其他定義的字段在樹面板上起到什么作用則均可在Ext.data.NodeInterface找到答案。

 

在api中可以看出Ext.data.TreeStore繼承了Ext.data.NodeStore,而Ext.data.NodeStore的接口正是Ext.data.NodeInterface

 

3.上面js中listeners 定義的‘beforeexpand’事件也來源於Ext.data.NodeInterface。在本節點展開前觸發。

 

4.reader 中的root配置,在Ext.data.TreeStore的API中有這樣的說明:

Reading Nested Data 讀取內嵌數據

對於樹讀取內嵌數據,在Ext.data.reader.Reader中必須配置一個root屬性, 這樣reader可以找到關於每個節點的內嵌數據。 如果未指定root,那么它將默認為'children'

這里介紹它的作用是“讀取內嵌數據”,我並未指定,然而它說默認為‘children’,剛好我在設計菜單的pojo時對於子菜單屬性的引用名就是children:

private List<Tree> children;

所以如果上面的引用是別的什么,那么就要指定了?——這里不作測試了。

 

 

運行效果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM