MyBatis无限级分类实现的两种方法--自关联与map集合

1、这回先创建数据库吧

下表cid是CategoryId的缩写,cname是CategoryName的缩写,pid是parentId的缩写

无限级分类一般都包含这三个属性,至少也要包含cid和pid才能建立无限级关联

ok,这个东东就是无限级分类了。

即便是外行人稍微看一眼也能发现cid为1的图书在小说和周刊两行中作为了pid,也就是说小说和周刊的父级分类就是图书

图书和饮料的pid是0,代表他们是顶级分类

如果没有其他约束条件,这张表几乎可以无限向下级延伸,是一个树形结构,这里就不写什么数学公式了,道理很简单。想必大家都懂了。

2、写个实体类

首先还是生产实体类,植入一个他本身的List集合:

 1 package cn.sohappy.acourses.bean;
 2
 3 import java.util.ArrayList;
 4 import java.util.List;
 5
 6 public class Category {
 7     private Long cid;
 8     private String cname;
 9     private Long pid;
10     private List<Category> children;
11
12    //省略getter and setter
13 }

然后初始化children并重写toString方法方便测试,完整代码如下:

 1 package cn.sohappy.acourses.bean;
 2
 3 import java.util.ArrayList;
 4 import java.util.List;
 5
 6 public class Category {
 7     private Long cid;
 8     private String cname;
 9     private Long pid;
10     private List<Category> children=new ArrayList<Category>();//这里为了防止后面空指针,初始化了children实例
11
12     public List<Category> getChildren() {
13         return children;
14     }
15
16     public void setChildren(List<Category> children) {
17         this.children = children;
18     }
19
20     public Long getCid() {
21         return cid;
22     }
23
24     public void setCid(Long cid) {
25         this.cid = cid;
26     }
27
28     public String getCname() {
29         return cname;
30     }
31
32     public void setCname(String cname) {
33         this.cname = cname;
34     }
35
36     public Long getPid() {
37         return pid;
38     }
39
40     public void setPid(Long pid) {
41         this.pid = pid;
42     }
43
44     @Override
45     public String toString() {
46         return "Category{cid:"+cid+
47                 ",cname:"+cname+
48                 ",pid:"+pid+
49                 ",children:"+children+
50                 "}";
51     }
52 }

3、写接口:

List<Category> findCategoriesByParentId(Long pid);自关联查询

List<Category> findAllCategories();一条sql查询所有,后期用Map算法分级
 1 package cn.sohappy.acourses.course0921;
 2
 3 import cn.sohappy.acourses.bean.Category;
 4
 5 import java.util.List;
 6
 7 public interface ICategoryDAO {
 8     List<Category> findCategoriesByParentId(Long pid);
 9     List<Category> findAllCategories();
10 }

4、小配置:

 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <!DOCTYPE mapper
 3         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 4         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 5 <mapper namespace="cn.sohappy.acourses.course0921.ICategoryDAO">
 6     <!--01.自关联查询-->
 7     <resultMap id="selectCategoriesByPid" type="cn.sohappy.acourses.bean.Category">
 8         <id property="cid" column="cid"/>
 9         <result property="cname" column="cname"/>
10         <result property="pid" column="pid"/>
11         <collection property="children" ofType="cn.sohappy.acourses.bean.Category" select="findCategoriesByParentId" column="cid"/>
12     </resultMap>
13     <select id="findCategoriesByParentId" resultMap="selectCategoriesByPid">
14         select * from category where pid=#{0}
15     </select>
16     <!--02.单次查询-->
17     <resultMap id="MenuOneSQL" type="cn.sohappy.acourses.bean.Category" autoMapping="false">
18         <id property="cid" column="cid"/>
19         <result property="cname" column="cname"/>
20         <result property="pid" column="pid"/>
21     </resultMap>
22     <select id="findAllCategories" resultMap="MenuOneSQL">
23         select * from category
24     </select>
25 </mapper>

5.测试类:

 1 package cn.test;
 2
 3 import cn.sohappy.acourses.bean.BillManyToOne;
 4 import cn.sohappy.acourses.bean.Category;
 5 import cn.sohappy.acourses.bean.UserOneToMany;
 6 import cn.sohappy.acourses.course0921.ICategoryDAO;
 7 import cn.sohappy.acourses.course0921.IUserDAO;
 8 import cn.sohappy.acourses.course0921.InfiniteMenuUtil;
 9 import cn.sohappy.bean.Smbms_user;
10 import cn.sohappy.util.MyBatisUtil;
11 import org.apache.ibatis.session.SqlSession;
12 import org.junit.Test;
13
14 import java.util.List;
15
16 public class test20170921 {
17     @Test
18     //自关联实现无穷分类
19     public void selfCorrelation(){
20         SqlSession session = MyBatisUtil.getSession();
21         ICategoryDAO mapper = session.getMapper(ICategoryDAO.class);
22         List<Category> categories = mapper.findCategoriesByParentId(0L);
23         for (Category item :categories) {
24             System.out.println(item);
25         }
26         session.close();
27     }
28     @Test
29     //Map集合实现无穷分类
30     public void InfiniteMenu(){
31         SqlSession session = MyBatisUtil.getSession();
32         ICategoryDAO mapper = session.getMapper(ICategoryDAO.class);
33         List<Category> categoriesClassified = new InfiniteMenuUtil().loadMenu(mapper.findAllCategories());
34         for (Category item :categoriesClassified) {
35             System.out.println(item);
36         }
37         session.close();
38     }
39 }

6、InfiniteMenu的Map算法

 1 package cn.sohappy.acourses.course0921;
 2
 3 import java.lang.reflect.InvocationTargetException;
 4 import java.lang.reflect.Method;
 5 import java.util.*;
 6
 7 public class InfiniteMenuUtil {
 8     @SuppressWarnings("unchecked")
 9     public <T> List<T> loadMenu(List<T> menus) {
10         List<T> rootMenus = new ArrayList<T>();
11         if (menus != null && menus.size() != 0) {
12             List<Method> methodsList = Arrays.asList(menus.get(0).getClass().getDeclaredMethods());
13             //这里可以自己定制啦,我定制的是以pid,id,children结尾的get方法为分别getPid,getId,getChildren.所以menu类(Category)的属性名要符合定制规范
14             Method getId = null;
15             Method getPid = null;
16             Method getChildren = null;
17             //get getMethod
18             for (Method item : methodsList) {
19                 if ("get".equals(item.getName().toLowerCase().substring(0,3))&&item.getName().length()>=6&&"pid".equals(item.getName().toLowerCase().substring(item.getName().length() - 3, item.getName().length()))){
20                     getPid = item;
21                     continue;
22                 }
23                 if ("get".equals(item.getName().toLowerCase().substring(0,3))&&item.getName().length()>=5&&"id".equals(item.getName().toLowerCase().substring(item.getName().length() - 2, item.getName().length()))){
24                     getId = item;
25                     continue;
26                 }
27                 if ("get".equals(item.getName().toLowerCase().substring(0,3))&&item.getName().length()>=11&&"children".equals(item.getName().toLowerCase().substring(item.getName().length() - 8, item.getName().length()))){
28                     getChildren = item;
29                 }
30             }
31             if (getId!=null&&getPid!=null&&getChildren!=null){
32                 //get menuMap
33                 Map<Long, T> menuMap = new HashMap<Long, T>();
34                 for (T menu : menus) {
35                     Long id = null;
36                     try {
37                         id = (Long)getId.invoke(menu);
38                     } catch (IllegalAccessException e) {
39                         e.printStackTrace();
40                     } catch (InvocationTargetException e) {
41                         e.printStackTrace();
42                     }
43                     menuMap.put(id,menu);
44                 }
45                 //add children
46                 for (T menu:menus) {
47                     Long pid = null;
48                     try {
49                         pid = (Long)getPid.invoke(menu);
50                     } catch (IllegalAccessException e) {
51                         e.printStackTrace();
52                     } catch (InvocationTargetException e) {
53                         e.printStackTrace();
54                     }
55                     if (pid==null||pid==0){
56                         rootMenus.add(menu);
57                     }else {
58                         T t = menuMap.get(pid);
59                         List<T> ts;
60                         try {
61                             ts = (List<T>) getChildren.invoke(t);
62                             ts.add(menu);
63                         } catch (IllegalAccessException e) {
64                             e.printStackTrace();
65                         } catch (InvocationTargetException e) {
66                             e.printStackTrace();
67                         }
68                     }
69                 }
70             }
71         }
72         return rootMenus;
73     }
74 }
时间: 2024-10-11 11:55:08

MyBatis无限级分类实现的两种方法--自关联与map集合的相关文章

oracle rename数据文件的两种方法

oracle rename数据文件的两种方法 2012-12-11 20:44 10925人阅读 评论(0) 收藏 举报  分类: oracle(98)  版权声明:本文为博主原创文章,未经博主允许不得转载. 第一种 alter tablespace users rename datafile '==' to '***'; 这种方式需要数据库处于open状态,表空间在offline的状态下才能更改. [sql] view plain copy SQL> alter tablespace user

登录用到了两种方法GET和POST方法 用reqeusts实现

这里需要补充的是,客户端不仅仅是一些简单的操作,它也是会处理一些运算,业务逻辑的处理等.也就是说,客户端也做着一些本该由服务器来做的一些事情 这个错误第一反应是是不是新的这个gateway节点有问题啊?但是想想这是不可能的,因为并不是所有请求都不可以,而且找了gateway部门的同事问了下,也不存在对请求单独处理的逻辑. 认证的同时要抓取页面表单的其他input标签的name和value.joomla的较为简单,网站一般不会明文传输用户名和密码,遇到这种情况需要分析引入的js文件,模拟加密算法.

设置数据库兼容级别的两种方法以及区别

转:http://blog.csdn.net/htl258/article/details/5696325 --设置数据库兼容级别的两种方法 --以设置兼容SQL Serve 2005 为例 --法一: ALTER DATABASE database_name SET COMPATIBILITY_LEVEL = 90 GO --法二: EXEC sp_dbcmptlevel database_name,90 GO database_name 要修改为数据库的名称. 各参数值对应的数据库版本: 8

MyBatis开发Dao层的两种方式(Mapper动态代理方式)

MyBatis开发原始Dao层请阅读我的上一篇博客:MyBatis开发Dao层的两种方式(原始Dao层开发) 接上一篇博客继续介绍MyBatis开发Dao层的第二种方式:Mapper动态代理方式 Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上一篇博客中Dao接口实现类方法. Mapper接口开发需要遵循以下规范: (1)Mapper.xml文件中的namespace与mapper接口的类路

一、查看Linux内核版本命令(两种方法):

一.查看Linux内核版本命令(两种方法): 1.cat /proc/version [[email protected]CentOS home]# cat /proc/versionLinux version 2.6.32-431.el6.x86_64 ([email protected]) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC) ) #1 SMP Fri Nov 22 03:15:09 UTC 2013 2.uname -a [

利用颜色和形态学两种方法进行车牌区域提取的OpenCV代码

要想提取车牌号,首先你要定位车牌区域嘛,本文分别两种方法用,即颜色和形态学的方法,对车牌区域进行判定.说得是两种方法,其实两种方法并无多大的区别,只是有一步的判断标准不一样而已,你看了下面整理出的的思路就知道两者的区别真的很小了. 方法一:利用颜色提取车牌区域的思路: ①求得原图像的sobel边缘sobelMat ②在HSV空间内利用车牌颜色阈值对图像进行二值化处理,得到图像bw_blue→ ③由下面的判别标准得到图像bw_blue_edge for (int k = 1; k != heigh

ios图片拉伸两种方法

ios图片拉伸两种方法 UIImage *image = [UIImage imageNamed:@"qq"]; 第一种: // 左端盖宽度 NSInteger leftCapWidth = image.size.width * 0.5f; // 顶端盖高度 NSInteger topCapHeight = image.size.height * 0.5f; // 重新赋值 image = [image stretchableImageWithLeftCapWidth:leftCapW

Android第五期 - 更新自己的apk本地与网络两种方法

首先是本地: ParseXmlService部分: package com.szy.update; import java.io.InputStream; import java.util.HashMap; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Element

Linux中生成密钥的两种方法

Linux中生成密钥的两种方法 SSH服务支持一种安全认证机制,即密钥认证.所谓的密钥认证,实际上是使用一对加密字符串,一个称为公钥(publickey), 任何人都可以看到其内容,用于加密:另一个称为密钥(privatekey),只有拥有者才能看到,用于解密.通过公钥加密过的密文使用密钥可以轻松解密,但根据公钥来猜测密钥却十分困难. ssh的密钥认证就是使用了这一特性.服务器和客户端都各自拥有自己的公钥和密钥.如何使用密钥认证登录linux服务器呢? 在使用密钥认证远程登入linux之前,我们