🔍
📢
无限级分类MyBatis实现方法:自关联与map集合

无限级分类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 }

频道:Java