package com.persagy.proxy.adm.utils; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.ObjectNode; import com.persagy.proxy.adm.request.AdmQueryCriteria; import com.persagy.proxy.adm.request.OrderItem; import com.persagy.proxy.adm.request.QueryCriteria; import java.math.BigDecimal; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * ADM通用查询条件 * @author Charlie Yu * @date 2021-08-16 */ public class AdmQueryCriteriaHelper { /** 条件匹配字符串 */ private static final String[] COND_STR = {" = "," != "," > "," >= "," < "," <= "," in "," isnull "," contain "," startwith "," endwith "}; /** 需要替换的字段对照 Map */ private static Map> RENAME_MAP = new HashMap<>(16); /** 与数据中台的操作参数对照 */ private static Map OPERATOR_MAP = new HashMap<>(); static { OPERATOR_MAP.put("!=", "$ne"); OPERATOR_MAP.put(">", "$gt"); OPERATOR_MAP.put(">=", "$gte"); OPERATOR_MAP.put("<", "$lt"); OPERATOR_MAP.put("<=", "$lte"); OPERATOR_MAP.put("in", "$in"); OPERATOR_MAP.put("contain", "$like"); OPERATOR_MAP.put("startwith", "$likeLeft"); OPERATOR_MAP.put("endwith", "$likeRight"); } /** * 将ADM的查询条件转换为DMP的 * 调用前注意: * - 调用前将name赋值,才会将条件中adm的属性替换为dmp的属性 * - 统计查询时将isOnlyCount设置为true * 调用后注意(需要调用者自行处理的): * - 不处理级联,级联应在调用者里处理级联调用转换后查询赋值 * - 不处理projection,查询后自行根据projection筛选返回属性。(dmp只能指定扩展属性,而adm的是针对所有属性的) * @param admCriteria * @return */ public static QueryCriteria toDmpCriteria(AdmQueryCriteria admCriteria) { QueryCriteria dmpCriteria = new QueryCriteria(); // 拷贝分页 copyPageInfo(admCriteria, dmpCriteria); // 处理filters dmpCriteria.setCriteria(toCriteria(admCriteria.getName(), admCriteria.getFilters())); if(StringUtils.isNotEmpty(admCriteria.getName())){ // 处理name dmpCriteria.getCriteria().put("objType", admCriteria.getName()); } // 处理排序 dmpCriteria.setOrders(toOrderItem(admCriteria.getOrders())); // 处理统计 dmpCriteria.setOnlyCount(admCriteria.isOnlyCount()); return dmpCriteria; } /** * 处理分页信息 * @param admCriteria * @param dmpCriteria */ private static void copyPageInfo(AdmQueryCriteria admCriteria, QueryCriteria dmpCriteria) { // 页码 Integer pageNumber = admCriteria.getPageNumber(); if(pageNumber == null || pageNumber < 1) { pageNumber = 1; } dmpCriteria.setPage(pageNumber.longValue()); // 条数 Integer pageSize = admCriteria.getPageSize(); if(pageSize == null || pageSize > admCriteria.getMaxRow()) { pageSize = admCriteria.getMaxRow(); } dmpCriteria.setSize(pageSize.longValue()); } /** * 排序字符串转换为对象 * @param orderStr */ private static List toOrderItem(String orderStr) { if(StrUtil.isBlank(orderStr)) { return null; } // 按,分隔 String[] orders = StrUtil.split(orderStr, ","); List orderList = new ArrayList<>(); for(String order:orders) { // 按空格分隔 String[] items = StrUtil.split(order, " "); // 去除空串 items = ArrayUtil.removeEmpty(items); if(ArrayUtil.isEmpty(items)) { continue; } OrderItem orderItem = new OrderItem(); // 第一位为排序字段 orderItem.setColumn(items[0].trim()); // 只有一位 或 第二位不是desc 表示为升序 orderItem.setAsc(items.length <= 1 || !"desc".equalsIgnoreCase(items[1])); orderList.add(orderItem); } return orderList; } /** * 将ADM过滤条件转换为DMP查询 * 由于数据中台不支持or条件,因此不能转换为中台的KV条件形式,只能转换为sql * @param filters * @return */ private static ObjectNode toCriteria(String name, String filters) { ObjectNode criteria = JsonNodeFactory.instance.objectNode(); // filters格式参考:http://doc.sagacloud.cn/doc/service/dev/lib/web/filters.html#%E8%BF%87%E6%BB%A4%E6%9D%A1%E4%BB%B6 if(StrUtil.isBlank(filters)) { return criteria; } // 替换逻辑运算符: && || ; filters = StrUtil.replace(filters, "&&", " and "); filters = StrUtil.replace(filters, "||", " or "); filters = StrUtil.replace(filters, ";", " and "); // 处理[] filters = StrUtil.replace(filters, "[", " ( "); filters = StrUtil.replace(filters, "]", " ) "); // 查找下一个 连接点[and or为连接点] ensureOrCondition(name, criteria, filters); return criteria; } /** * 从or条件中截取表达式 * @param criteria * @param filters */ private static void ensureOrCondition(String name, ObjectNode criteria, String filters) { int orIndex = StrUtil.indexOfIgnoreCase(filters, " or ", 0); String orLeft = orIndex < 0 ? filters : StrUtil.subPre(filters, orIndex); ensureAndCondition(name, criteria, orLeft); // 有or条件 if(orIndex >= 0) { String orRight = StrUtil.subSuf(filters, orIndex + 4); ObjectNode node = criteria.putObject("$or"); // 右侧字符串继续递归处理 ensureOrCondition(name, node, orRight); } } /** * 从and条件中截取表达式 * @param criteria * @param filters */ private static void ensureAndCondition(String name, ObjectNode criteria, String filters) { int andIndex = StrUtil.indexOfIgnoreCase(filters, " and ", 0); String andLeft = andIndex < 0 ? filters : StrUtil.subPre(filters, andIndex); // 处理左侧条件 ensureAndExpress(name, criteria, andLeft); // 处理右侧条件 if(andIndex >= 0) { String andRight = StrUtil.subSuf(filters, andIndex+5); // 递归处理and ensureAndCondition(name, criteria, andRight); } } /** * 处理表达式 * @param criteria * @param express */ private static void ensureAndExpress(String name, ObjectNode criteria, String express) { String cond = StrUtil.getContainsStr(express, COND_STR); if(StrUtil.isBlank(cond)) { return; } int condIndex = StrUtil.indexOfIgnoreCase(express, cond, 0); String condLeft = StrUtil.subPre(express, condIndex).trim(); String condRight = StrUtil.subSuf(express, condIndex+cond.length()).trim(); addCondition(name, criteria, condLeft, cond.trim(), condRight); } /** * 拼接条件 * @param criteria * @param column * @param operator * @param value */ private static void addCondition(String name, ObjectNode criteria, String column, String operator, String value) { // 替换列名 column = replaceColumns(name, column); if("=".equals(operator)) { criteria.set(column, getJsonNode(criteria, value)); } else if("in".equals(operator)) { // 按,分隔 String[] splits = StrUtil.split(value, ","); if(ArrayUtil.isEmpty(splits)) { return; } ArrayNode node = criteria.putArray(column); for(String split:splits) { // 去掉所有的() 即为值 split = StrUtil.removeAll(split, '(',')'); node.add(getJsonNode(criteria, split.trim())); } } else if("isnull".equals(operator)) { ObjectNode node = criteria.putObject(column); node.put("$null", true); } else { ObjectNode node = criteria.putObject(column); node.set(OPERATOR_MAP.get(operator), getJsonNode(node, value)); } } /** * 取Json值对象 * @param criteria * @param value * @return */ private static JsonNode getJsonNode(ObjectNode criteria, String value) { if(StrUtil.isBlank(value)) { return criteria.nullNode(); } // 字符串 if(StrUtil.startWith(value, "'") && StrUtil.endWith(value, "'")) { return criteria.textNode(StrUtil.sub(value, 1, value.length()-1)); } // 数值 if (StrUtil.contains(value, ".")) { try { BigDecimal no = new BigDecimal(value); return criteria.numberNode(no); } catch (NumberFormatException e) { } } // 整型 try { Integer no = Integer.valueOf(value); return criteria.numberNode(no); } catch (NumberFormatException e) { } return criteria.nullNode(); } /** * 替换属性称名 * @param name * @param column * @return */ private static String replaceColumns(String name, String column) { Map fieldMap = getRenameFields(name); // 没有对照则使用原本的 if(MapUtil.isEmpty(fieldMap) || !fieldMap.containsKey(column)) { return column; } return fieldMap.get(column); } /** * 获取更名对照 * @param name * @return */ private static Map getRenameFields(String name) { // 获取通用对照 Map commonMap = getRenameMap().get("COMMON"); // 获取此类型的对照 Map nameMap = getRenameMap().get(name); if(MapUtil.isEmpty(nameMap)) { return commonMap; } Map rsMap = new HashMap<>(); rsMap.putAll(commonMap); rsMap.putAll(nameMap); return rsMap; } /** * 获取通用Map * @return */ private static Map> getRenameMap() { if(MapUtil.isEmpty(RENAME_MAP)) { // COMMON表示通用对照 Map commonMap = new HashMap<>(); commonMap.put("createTime", "creationTime"); commonMap.put("lastUpdate", "modifiedTime"); RENAME_MAP.put("COMMON", commonMap); } return RENAME_MAP; } }