目录
需求描述
如下图所示,sub_rule表的detail字段是json类型的(数据库采用的是postgresql),里面存的是预先定义好的规则,例如某规则是{"开发类型":["新功能","优化细节交互"], "代码规模":["100-500行","500-100行"], "开发能力":["1A","1B","2A"]},则通过这条规则的任务就是需求分析1。
其中开发类型、代码规模、开发能力表示3个大维度,是与的关系,需要同时满足;各自下面又有子维度,是或的关系,通过一个即可。
假设这时候有某个任务,它的评估规则是{"开发类型":["新功能"], "代码规模":["0-100行"], "开发能力":["1A","1B"]},那么它匹配数据库中所有规则的结果应该是需求分析2。再举个栗子,假设有个任务的评估规则是{"开发类型":["新功能"], "开发能力":["1B","2A"]},那么它匹配数据库中所有规则的结果应该是设计1,它缺少代码规模维度,因此不应该通过需求分析1。
解决思路
传进来的数据data应该是要类似json的格式,这里采用map。那么首先,应该能够遍历map的key,拿到对应的value1;其次,拿到json数据中key对应的value2;比较两个value,满足value1包含于value2。但这里还会有一个问题,就是上述的第二个例子,若任务的评估规则是{"开发类型":["新功能"], "开发能力":["1B","2A"]},那么以map来进行循环,这样仅会循环两个大维度,且相应的子维度有满足条件了,不会再判断其他维度,因此得到了设计1和需求分析1。针对这种情况,可以加上一个维度大小的判断,即表中的dimension_size字段,先过滤到大维度不一样的规则,再循环判断。
运行结果
服务方法,构造map,模拟规则{"开发类型":["新功能"], "开发能力":["1B","2A"]}
public List<SubRule> findRuleByDimensionId() {
Map<String, List<String>> con = new HashMap<>();
List<String> list = new ArrayList<>();
list.add("\"新功能\"");
// list.add("\"优化细节交互\"");
// List<String> list2 = new ArrayList<>();
// list2.add("\"100-500行\"");
List<String> list3 = new ArrayList<>();
list3.add("\"2A\"");
list3.add("\"1B\"");
con.put("开发类型", list);
// con.put("代码规模", list2);
con.put("开发能力", list3);
List<SubRule> subRules = indexMapper.findRuleByDimensionId(con, 2);
for (SubRule subRule : subRules) {
System.out.println(subRule);
}
return subRules;
}
mapper中的查询语句,这里用到postgresql的知识,中文文档链接:http://www.postgres.cn/docs/9.5/datatype-json.html
<select id="findRuleByDimensionId" resultMap="subRuleVO" parameterType="java.util.Map">
SELECT * FROM sub_rule WHERE sub_rule.dimension_size = #{dimensionSize} AND
<foreach collection="con" index="key" item="values" separator="and" >
(sub_rule.detail::json#>>'{${key}}')::jsonb @> '${values}'
</foreach>
</select>
关于foreach的知识
item | 循环体中的具体对象。支持属性的点路径访问,如item.age,item.info.details。 具体说明:若collection属性为list或array,则item代表list或array里面的一个元素。若collection属性对应一个map,则item代表的是map中的value集合中的单个value 该参数为必选。 |
collection | foreach遍历的对象,作为入参时,List对象默认用list代替作为键,数组对象有array代替作为键,Map对象没有默认的键。也就是传入的集合(list,array,map)的名字,这个名字可以在foreach里面随便引用) 如果传入参数类型为map,这个入参有注解@Param("params"),则map的所有的key集合可以写成params.keys,所有值集合可以写成params.values。这样foreach就可以对key集合或值集合进行迭代了。 上面只是举例,具体collection等于什么,就看你想对那个元素做循环。 |
separator | 元素之间的分隔符,例如在in()的时候,separator=","会自动在元素中间用“,“隔开,避免手动输入逗号导致sql错误,如in(1,2,)这样。该参数可选。 |
open | foreach代码的开始符号,一般是(和close=")"合用。常用在in(),values()时。该参数可选。 |
close | foreach代码的关闭符号,一般是)和open="("合用。常用在in(),values()时。该参数可选。 |
index | 在list和数组中,index是元素的序号,在map中,index是元素的key,该参数可选。 |
从结果可以看出来,确实只得到了设计1,而没有需求分析1。