Several Ways to Realize Tree Structure by mybatis Single Table Self-Association

Keywords: xml Database SQL Mybatis

The javaBean is as follows:

public class Permission implements Serializable {
    private Integer id;
    private String name;
    private String icon;
    private String url;
    private boolean open;//Are the leaves open?
    private Integer pid;//Father id
    private boolean checked;//Is it selected?
    private List<Permission> children =new ArrayList<Permission>();//subset
}

The first is to use mybatis mapping to implement:
1. Configure in the mapper mapping file:

 <!--Recursive result set-->
<resultMap id="RecursionResultMap" type="com.ssm.bean.Permission">
  <id column="id" jdbcType="INTEGER" property="id" />
  <result column="pid" jdbcType="INTEGER" property="pid" />
  <result column="name" jdbcType="VARCHAR" property="name" />
  <result column="icon" jdbcType="VARCHAR" property="icon" />
  <result column="url" jdbcType="VARCHAR" property="url" />
  <!--One-to-many, recursive configuration-->
  <collection property="children" ofType="com.ssm.bean.Permission" column="id" select="recursionChildren"/>
</resultMap>
<select id="selectRoot" resultMap="RecursionResultMap">
  select id, pid, name, icon, url
  from t_permission where pid is null or pid =0
</select>
<select id="recursionChildren" resultMap="RecursionResultMap">
  select id, pid, name, icon, url
  from t_permission where pid = #{id}
</select>

2.Service Layer: Call the selectRoot method

public List<Permission> selectRoot() {
    return permissionMapper.selectRoot();
}

3.Controller layer:

@RequestMapping("/permissionALL")
@ResponseBody
public List<Permission> all(){
    List<Permission> list= permissionService.selectRoot();
    return list;
}   

The results are as follows:

The second is through recursion:
1.mapper.xml configuration:

<resultMap id="BaseResultMap" type="com.ssm.bean.Permission">
  <id column="id" jdbcType="INTEGER" property="id" />
  <result column="pid" jdbcType="INTEGER" property="pid" />
  <result column="name" jdbcType="VARCHAR" property="name" />
  <result column="icon" jdbcType="VARCHAR" property="icon" />
  <result column="url" jdbcType="VARCHAR" property="url" />
</resultMap>
<select id="selectChildren" resultMap="BaseResultMap">
  select id, pid, name, icon, url
  from t_permission where pid = #{id}
</select>

2.Service layer:

public List<Permission> selectChildren(Integer id) {
   	return permissionMapper.selectChildren(id);
 }

3.Controller layer:

@RequestMapping("/initPermission1")
@ResponseBody
public Permission initPermission1(){
    Permission permission=new Permission ();
    try{
        permission.setId(1);//This place should query the root node through the database, because the id of the root node is 1 in the database, so I stole a little lazy.
        queryChildPermissions(permission);//Recursively get all nodes
    }catch (Exception e){
        throw  e;
    }
    return permission;
}
private void queryChildPermissions (Permission permission){
    List<Permission> children=  permissionService.selectChildren(permission.getId());//Query subsets by id
    permission.setChildren(children);//Put the queried set of child nodes into the permission set
    for(Permission innerChildren:children){        //Traversing through subsets of subsets
        queryChildPermissions(innerChildren);      //Put it into a subset of subnodes
    }
}

4. Calling initPermission1 method, the query results are consistent with the first method. These two methods are not recommended because sql statements will be issued every time a recursion is executed, which occupies a lot of resources.

Third: Find out all records at one time and traverse the results through nested loops
1.mapper.xml configuration;

<resultMap id="BaseResultMap" type="com.ssm.bean.Permission">
  <id column="id" jdbcType="INTEGER" property="id" />
  <result column="pid" jdbcType="INTEGER" property="pid" />
  <result column="name" jdbcType="VARCHAR" property="name" />
  <result column="icon" jdbcType="VARCHAR" property="icon" />
  <result column="url" jdbcType="VARCHAR" property="url" />
</resultMap>
 <select id="selectAll" resultMap="BaseResultMap">
      select id, pid, name, icon, url
      from t_permission
 </select>

2.Service layer:

public List<Permission> selectAll() {
    return permissionMapper.selectAll();
}

3.Controller layer:

@RequestMapping("/initPermission2")
@ResponseBody
public Permission initPermission2(){

    Permission permission=new Permission ();
    List<Permission> lists=permissionService.selectAll();//Query all nodes
    try{
        for(Permission ps:lists){//Traversing node
            Permission child=ps;
            if(ps.getPid().equals(0)||ps.getPid()==null){//Get the root node, the Integer type is the wrapper class, and determine the object reference
                permission=ps;//Root node
            }else{
                for (Permission innerpermission:lists){
                    if(child.getPid()==innerpermission.getId()){//If the pid of a node is identical to the id of a node in the collection
                        Permission parent=innerpermission;//Name this node as the parent node
                        parent.getChildren().add(child);//Then put the child in its father's collection.
                        break;
                    }
                }
            }
        }
    }catch (Exception e){
        throw  e;
    }
            return permission;
}

The results of the query are consistent with those of the previous two methods. All data are found at one time, and the results are obtained by nested loop traversal. It is not necessary to send sql statements frequently, but if there is more data, too many cycles will affect performance.

Fourth: Find all data at once and implement tree structure through Map set

Service layer and mapper.xml are the same as the third way
Controller layer:

@RequestMapping("/initPermission")
@ResponseBody
public Permission initPermission(){
    Permission permission=new Permission ();
    List<Permission> lists=permissionService.selectAll();//Query all nodes
    Map<Integer,Permission> map=new HashMap<Integer,Permission>();//Store all nodes in the map set
    try{
        for(Permission ps:lists) {
           map.put(ps.getId(),ps);//Use all IDs as key s, Permission objects as values, and store them in the map collection
        }
        for(Permission ps:lists){//Traverse all nodes
            Permission child=ps;
            if (child.getPid().equals(0)||child.getPid()==null){
                permission=ps;//Remove the root node
            }else{
                Permission parent=map.get(child.getPid());//Getting the parent node through the pid of the child node
                parent.getChildren().add(child);//Place child nodes in parent nodes
            }
        }
    }catch (Exception e){
        throw  e;
    }
    return permission;
}

The results of the four queries are the same. Relatively speaking, it is the most efficient to implement tree structure through Map.

Posted by notionlogic on Fri, 04 Oct 2019 07:57:15 -0700