mybatis多表分级点击查询

Posted 如漩涡

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis多表分级点击查询相关的知识,希望对你有一定的参考价值。

上次介绍了分级点击查询的文章,是在SQL中将两个查询结果集合在了一块返回给前端,这次说一下多表的情况下

什么叫多表的情况下?拿以往的文章,流域水系树的结构来说,要根据上一级的编码来查下一级,就是pid关系。上次是利用循环递归的方式,查询出全部流域,循环流域,在循环中做查询水系的方式,水系获取流域的编码(pid)来找出所属水系关系

但是这样啊,数据量大的时候,那这递归要很久了,前端等待的时候太长,用户体验会很差,那怎么办呢?和上次一样吧,分级,前端要一段我给一段,前端利用ztree这个插件的addNodes方法拼接上

用上回分级查询的思路,在SQL中写查询,但就写一句就行,可还有个问题,这是多个表,流域水系河流湖泊水库段六张表,这怎么办,要构造树,那六张表的XML都要做一个查询了,还是得用递归才行呀。NO NO,上次我介绍过mybatis的一大特性 $符号,可以往回看文章,下面直接上SQL代码

<select id="findTree" resultType="com.uhope.rl.watersource.core.RegionTreeNode" parameterType="java.util.HashMap">
    SELECT
      ${columnName} AS name,
      ${columnCode} AS id,
      1 AS isParent,
      id AS dataId
    FROM ${tableName}         <where>
           <if test="column != null">AND ${column} = #{code}</if>
           <if test="state != null">AND state = #{state}</if>
           <if test="columns != null">AND ${columns} = #{codes}</if>
         </where>
  </select>

返回的是一个TreeNode类扩展的子类

public class RegionTreeNode extends TreeNode {
    private String type;
    private Integer regionLevel;
    private Boolean isParent;
    private String dataId;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getDataId() {
        return dataId;
    }

    public void setDataId(String dataId) {
        this.dataId = dataId;
    }

    public Integer getRegionLevel() {
        return regionLevel;
    }

    public void setRegionLevel(Integer regionLevel) {
        this.regionLevel = regionLevel;
    }

    public Boolean getIsParent() {
        return isParent;
    }

    public void setIsParent(Boolean parent) {
        isParent = parent;
    }}

TreeNode类

public class TreeNode implements Serializable {
    private String name;
    private String id ;
    private String pId;
    private String parantpaths;

    private Boolean checked = false;
    private List<TreeNode> children;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getpId() {
        return pId;
    }

    public void setpId(String pId) {
        this.pId = pId;
    }

    public String getParantpaths() {
        return parantpaths;
    }

    public void setParantpaths(String parantpaths) {
        this.parantpaths = parantpaths;
    }

    public List<TreeNode> getChildren() {
        return children;
    }

    public void setChildren(List<TreeNode> children) {
        this.children = children;
    }

    public void addChild(TreeNode child) {
        if (children == null) {
            children = Lists.newArrayList();
        }
        children.add(child);
    }

    public Boolean getChecked() {
        return checked;
    }

    public void setChecked(Boolean checked) {
        this.checked = checked;
    }}

拓展的目的是有些字段是前端需要的,例如isParent,前端要根据这个来展开树

SQL代码中用到的是$和#符号,这样的好处是,即使六张表操作都是一样,就不用在多个XML里写了,返回的都是一个类,把要的字段和值都赋过来

看业务逻辑处理的Java代码

  /** * 流域水系河湖库段树 * @param code * @return */
    @Override
    public List<RegionTreeNode> DWRLRRTree(String code) {
        if (code == null || "".equals(code)) {
            HashMap<String, Object> basinMap = mapUtil("basin_name",
                    "basin_code", "md_drainage_basin",
                    null, null, Constant.STATE_RUN);
            List<RegionTreeNode> basin = mdDrainageBasinMapper.findTree(basinMap);
            return basin;
        } else if (code.length() == 1) {
            HashMap<String, Object> waterMap = mapUtil("water_name",
                    "water_code", "md_water_system",
                    "basin_code", code, Constant.STATE_RUN);
            List<RegionTreeNode> water = mdDrainageBasinMapper.findTree(waterMap);
            return water;
        } else if (code.length() == 3) {
            List<RegionTreeNode> nodeList = new ArrayList<>();

            RegionTreeNode riverNode = new RegionTreeNode();
            riverNode.setName(Constant.RIVERNAME);
            riverNode.setId(code + Constant.RIVER);
            riverNode.setIsParent(true);

            RegionTreeNode lakesNode = new RegionTreeNode();
            lakesNode.setName(Constant.LAKESNAME);
            lakesNode.setId(code + Constant.LAKES);
            lakesNode.setIsParent(true);

            RegionTreeNode reservoirNode = new RegionTreeNode();
            reservoirNode.setName(Constant.RESERVOINAME);
            reservoirNode.setId(code + Constant.RESERVOI);
            reservoirNode.setIsParent(true);

            nodeList.add(riverNode);
            nodeList.add(lakesNode);
            nodeList.add(reservoirNode);
            return nodeList;

        } else if (code.length() == 4) {
            String newCode = code.substring(0, 3);
            String subNum = code.substring(3, 4);
            if (subNum.equals(Constant.RIVER)) {
                HashMap<String, Object> riverMap = mapUtil("river_name",
                        "river_code", "md_river",
                        "water_code", newCode, Constant.STATE_RUN);
                List<RegionTreeNode> river = mdDrainageBasinMapper.findTree(riverMap);
                return river;
            } else if (subNum.equals(Constant.LAKES)) {
                HashMap<String, Object> lakesMap = mapUtil("lakes_name",
                        "lakes_code", "md_lakes",
                        "water_code", newCode, Constant.STATE_RUN);
                List<RegionTreeNode> lakes = mdDrainageBasinMapper.findTree(lakesMap);
                return lakes;
            } else {
                HashMap<String, Object> reservoirMap = mapUtil("reservoir_name",
                        "reservoir_code", "md_reservoir",
                        "water_code", newCode, Constant.STATE_RUN);
                List<RegionTreeNode> reservoir = mdDrainageBasinMapper.findTree(reservoirMap);
                return reservoir;
            }
        } else {
            String newCode = code.substring(8, 9);
            HashMap<String, Object> reachMap = mapUtil("reach_name",
                    "reach_code", "md_reach",
                    "their_code", code, Constant.STATE_RUN);
            reachMap.put("columns", "classify");
            reachMap.put("codes", newCode);
            List<RegionTreeNode> reach = mdDrainageBasinMapper.findTree(reachMap);
            return reach;
        }
    }

    public HashMap<String, Object> mapUtil(String columnName, String columnCode, String tableName, String column,
                                           String code, Integer state) {
        HashMap<String, Object> map = new HashMap<>(16);
        map.put("columnName", columnName);
        map.put("columnCode", columnCode);
        map.put("tableName", tableName);
        map.put("column", column);
        map.put("code", code);
        map.put("state", state);
        return map;
    }

来分析一下这段代码,先看mapUtil这个方法,返回的是一个map,用处是什么呢,因为findTree这个方法要放的是一个map,那就要new多次map对象,操作都差不多,因为XML里面需要的参数都会被put到map里去传,省去代码耦合,封装起来

DWRLRRTree这个方法有多个if,作用是前端点击一次就给我传一个code,调用的还是这个方法,就要做判断,什么都不传,为null的话,就把第一级的传给前端,那就是流域
第二次进来传的是流域的代码,根据传进来代码长度,一位是流域,三位是水系,九位的是河湖库的,那就长度判断传进来的哪个做对应的操作
一位的时候,把流域代码给水系的查询,这个时候mybatis的特性就体现出来了,什么表就传进去,什么字段就传进去,不需要每个XML都写一遍了;第三位进来的时候多做一个操作,要传河流湖泊水库这几个字回去,好区分,new了三个TreeNode类,设置了名称,id呢就是传进来的code在加一个ABC区分;第四位进来的时候将加的ABC做判断,是河流还是湖泊还是水库,然后做相应的操作,最后就是做河湖库段的了,这个也多做了一个操作,因为要知道是湖段还是河段,还是库段,还好编码中最后一位字母是用来区分的,本来想再写个if,表结构里有一个their_code来区分的,那就在数据库操作的时候多加一段进去就行了,也就是多一个AND的事情,这样不就每次传进来是哪个就查出哪个的段了吗,机智如我,嘻嘻嘻

好了,这就是大致的过程,Service接口和mapper接口就不写了,估计这些代码也能够猜出来是怎么写的了。


以上是关于mybatis多表分级点击查询的主要内容,如果未能解决你的问题,请参考以下文章

MyBatis多表联查

MyBatis注解开发多表代码操作——手把手教你实战操作

MyBatis 多条件查询动态SQL多表操作注解开发,应有尽有,一网打尽!

MyBatis 多条件查询动态SQL多表操作注解开发,应有尽有,一网打尽!

Mybatis多表查询之一对一查询的多种实现-XML配置

Mybatsi多表查询出现null字段