上次介绍了分级点击查询的文章,是在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接口就不写了,估计这些代码也能够猜出来是怎么写的了。