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 }