运行环境: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.autoLoad 这个配置默认是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;

所以如果上面的引用是别的什么,那么就要指定了?——这里不作测试了。

运行效果:

Extjs4 treePanel异步加载菜单(后台从数据库读取)的更多相关文章

  1. [Ext.Net]TreePanel 异步加载数据

    异步加载数据指的是页面加载的时候只显示根目录,点击根目录再去加载其子目录. 下面就来介绍下这种异步加载的树结构要怎么实现 现将例子的图 QQ图片20131225134353.jpg (12.1 KB, ...

  2. Ecplise 中 加载JDBC 连接 Mysql 数据库读取数据

    准备工作 首先下载 JDBC 驱动,下载地址https://www.mysql.com/products/connector/ 将压缩包解压得到文件 mysql-connector-java-5.1. ...

  3. Android图片异步加载

    原:http://www.cnblogs.com/angeldevil/archive/2012/09/16/2687174.html 相关:https://github.com/nostra13/A ...

  4. Android 之异步加载LoaderManager

    LoaderManager: Loader出现的背景: Activity是我们的前端页面展现,数据库是我们的数据持久化地址,那么正常的逻辑就是在展示页面的渲染页面的阶段进行数据库查询.拿到数据以后才展 ...

  5. EasyUI ComboTree无限层级异步加载示例

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="EasuUIDemoTree.a ...

  6. 【EasyUI学习-2】Easyui Tree的异步加载

    作者:ssslinppp       1. 摘要 2. tree的相关介绍 3. 异步加载tree数据,并实现tree的折叠展开 3.1 功能说明: 3.2 前台代码 3.3 后台代码 4. 其他 1 ...

  7. 【Android】纯代码创建页面布局(含异步加载图片)

    开发环境:macOS 10.12 + Android Studio 2.2,MinSDK Android 5.1 先看看总体效果 本示例是基于Fragment进行的,直接上代码: [界面结构] 在 F ...

  8. 使用jOrgChart插件, 异步加载生成组织架构图

    jOrgChart插件是一个用来实现组织结构图的Jquery的插件- 一.特点 1.支持拖拽修改子节点: 2.支持节点缩放展示: 3.方便修改css定义样式: 4.超轻量型: 5.兼容性好,基本支持所 ...

  9. Android异步加载访问网络图片-解析json

    来自:http://www.imooc.com/video/7871 推荐大家去学习这个视频,讲解的很不错. 慕课网提供了一个json网址可以用来学习:http://www.imooc.com/api ...

随机推荐

  1. input 데이터의 자판입력모드의 한글/영문 자동전환, 영문고정 하는 방법 웹프로그래밍 팁

      input 태그의 style 속성의 ime-mode 변경으로 한글/영문의 자동전환이나 영문만 입력이 되도록 할 수 있다.     style="ime-mode:activ ...

  2. 再次阅读《精通CSS-高级Web标准解决方案(第二版)》

    昨天(2015年11月21日) 在我们学校举行了大型招聘会.我面试了三家企业.有一家企业是先做笔试题的,做完后发现自己还是很多细节处理得不够.无论还有没有二面,我还是要重新把<精通CSS> ...

  3. Linux 命令 - ftp: 网络文件传输工具

    命令格式 ftp [-pinegvd] [host] 命令参数 -A 传输文件模式为主动模式. -p 传输文件模式为被动模式. -i 关闭交互模式. -n 关闭自动登录功能. -e 不记录历史命令. ...

  4. Linux - 文件的压缩与归档

    文件压缩 常用的压缩命令有 gzip.bzip2 等. gzip 命令 命令格式 gzip [ -acdfhlLnNrtvV19 ] [-S suffix] [ name ...  ] 命令参数 -c ...

  5. 【转载】Apache kafka原理与特性(0.8V)

    http://blog.csdn.net/xiaolang85/article/details/37821209 前言: kafka是一个轻量级的/分布式的/具备replication能力的日志采集组 ...

  6. 去重 oracle

    --去重DELETE FROM DEPR_MONTHS_LIST AWHERE (A.ASSET_ID,A.DEPR_DATE,A.UNIT_COST_ID) IN(SELECT B.ASSET_ID ...

  7. JS实现登录页面记住密码和enter键登录

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>按 ...

  8. CSS的浮动和清除

    CSS浮动和清除 什么是浮动? 在实现效果上,让元素浮起来(飘起来),动起来(向左或向右移动) 浮动本质:就是将两个块元素同存一行. float 取值:主要是对浮动的方向进行控制 left:让元素向左 ...

  9. VS2010

    1,vc++目录——>包含目录: Visual Studio will search for the include files referred to in your source code ...

  10. Poj 2586 / OpenJudge 2586 Y2K Accounting Bug

    1.Link: http://poj.org/problem?id=2586 2.Content: Y2K Accounting Bug Time Limit: 1000MS   Memory Lim ...