Commit a869a83a authored by liwenbin's avatar liwenbin

6.6

parent 279cd9c5
package com.quantgroup.asset.distribution.constant;
/**
* @author : Hyuk
* @description : RuleConstants
* @date : 2020/3/5 4:57 下午
*/
public class RuleConstants {
public static final String CONDITION = "conditions";
public static final String OPERATOR = "operator";
public static final String AND = "and";
public static final String OR = "or";
public static final String KEY = "key";
public static final String VAL = "value";
public static final String DEC_TABLE_RESULT = "result";
public static final String DEC_TABLE_ELSE = "else";
}
package com.quantgroup.asset.distribution.enums;
import com.quantgroup.asset.distribution.exception.QGException;
import com.quantgroup.asset.distribution.exception.QGExceptionType;
import com.quantgroup.asset.distribution.exception.QGPreconditions;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
/**
* @author : Hyuk
* @description : RuleOperator
* @date : 2020/3/5 5:08 下午
*/
@Slf4j
public enum RuleOperator {
GreaterThan(">", "大于"),
GreaterThanOrEqual(">=", "大于"),
LessThan("<", "小于"),
Equal("=", "等于"),
In("in", "包含"),
NotIn("exclude", "不包含"),
NotEqual("!=", "不等于"),
LessThanOrEqual("<=", "小于");
private String code;
private String description;
RuleOperator(String code, String description) {
this.code = code;
this.description = description;
}
public static RuleOperator fromCode(String code) {
QGPreconditions.checkArgument(StringUtils.isNoneBlank(code), QGExceptionType.COMMON_STRING_PARAM_IS_ALL_NULL, "操作");
for (RuleOperator ruleOperator : RuleOperator.values()) {
if (StringUtils.equalsAnyIgnoreCase(code, ruleOperator.code)) {
return ruleOperator;
}
}
log.error("枚举不存在,code={}", code);
throw new QGException(QGExceptionType.COMMON_ILLEGAL_PARAM);
}
}
package com.quantgroup.asset.distribution.enums;
import com.quantgroup.asset.distribution.exception.QGException;
import com.quantgroup.asset.distribution.exception.QGExceptionType;
import com.quantgroup.asset.distribution.exception.QGPreconditions;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
@Slf4j
public enum UnionType {
And("and", "而且"), Or("or", "或者");
private String code;
private String description;
UnionType(String code, String description) {
this.code = code;
this.description = description;
}
public static UnionType fromCode(String code) {
QGPreconditions.checkArgument(StringUtils.isNoneBlank(code), QGExceptionType.COMMON_STRING_PARAM_IS_ALL_NULL, "条件组类型");
for (UnionType unionType : UnionType.values()) {
if (StringUtils.equalsAnyIgnoreCase(code, unionType.code)) {
return unionType;
}
}
log.error("枚举不存在, code = {}", code);
throw new QGException(QGExceptionType.COMMON_ILLEGAL_PARAM);
}
}
...@@ -20,6 +20,7 @@ public enum QGExceptionType { ...@@ -20,6 +20,7 @@ public enum QGExceptionType {
COMMON_ILLEGAL_PARAM(1010, "参数异常"), COMMON_ILLEGAL_PARAM(1010, "参数异常"),
COMMON_THIRD_PARTY_TIMEOUT(1011, "第三方服务超时"), COMMON_THIRD_PARTY_TIMEOUT(1011, "第三方服务超时"),
COMMON_ENUM_NOT_EXIST(1012,"枚举不存在"), COMMON_ENUM_NOT_EXIST(1012,"枚举不存在"),
COMMON_STRING_PARAM_IS_ALL_NULL(1013, "参数不能为空", "%s不能为空"),
ASSET_IN_CODE_ERROR(2001, "资产入库code异常! uuid : %s, bizNo : %s, code : %s"), ASSET_IN_CODE_ERROR(2001, "资产入库code异常! uuid : %s, bizNo : %s, code : %s"),
GET_DEC_ATTRIBUTE_VALUE_ERROR(2002, "获取决策资产属性值异常, uuid : %s, keys : %s"), GET_DEC_ATTRIBUTE_VALUE_ERROR(2002, "获取决策资产属性值异常, uuid : %s, keys : %s"),
...@@ -32,6 +33,15 @@ public enum QGExceptionType { ...@@ -32,6 +33,15 @@ public enum QGExceptionType {
RULE_CALC_UNKNOW_RESULT(2024, "规则判断出现未知结果,请联系管理人员, expression : %s"), RULE_CALC_UNKNOW_RESULT(2024, "规则判断出现未知结果,请联系管理人员, expression : %s"),
UNKNOW_RULE_TYPE(2025, "未知的规则类型, %s"), UNKNOW_RULE_TYPE(2025, "未知的规则类型, %s"),
NO_DISTRIBUTE_NODE(2026, "未找到分发节点, uuid : %s, assetNo %s, records : %s"), NO_DISTRIBUTE_NODE(2026, "未找到分发节点, uuid : %s, assetNo %s, records : %s"),
RULE_EXPRESSION_IS_EMPTY(2027, "规则表达式未空"),
RULE_IS_NOT_JSON(2028, "规则不是json,解析失败"),
RULE_UNION_OPERATOR_NOT_EXIST(2029, "联合规则符不存在"),
DATA_NOT_EXIST_FOR_RULE(2030, "规则数据不存在,key:%s, operator:%s, value:%s"),
RULE_OPERATOR_IS_EMPTY(2031, "规则符为空"),
RULE_DATA_IS_EMPTY(2032, "规则数据为空,key:%s, operator:%s, value:%s"),
DATA_COMPARE_ERROR(2033, "数据比较出现错误"),
RULE_OPERATOR_NOT_EXIST(2034, "规则符不存在"),
NOTIFY_FUND_SERVER_ERROR(2041, "通知资金系统失败, uuid : %s, bizNo : %s, assetNo : %s"), NOTIFY_FUND_SERVER_ERROR(2041, "通知资金系统失败, uuid : %s, bizNo : %s, assetNo : %s"),
NOT_FOUND_FUND_SERVER_RESULT_BIZNO(2042, "未找到资金结果通知订单, bizNo : %s, status : %s"), NOT_FOUND_FUND_SERVER_RESULT_BIZNO(2042, "未找到资金结果通知订单, bizNo : %s, status : %s"),
......
package com.quantgroup.asset.distribution.model.entity.fund;
import lombok.Data;
import java.io.Serializable;
/**
* @author : Hyuk
* @description : ChannelFundConfigNew
* @date : 2020/3/5 3:49 下午
*/
@Data
public class ChannelFundConfigNew implements Serializable {
private static final long serialVersionUID = 1L;
private Integer fundId;
private Integer fundProductId;
private String fundName;
private String attentions;
private Limits limits;
private String rate;
private Integer feeType;
private Integer rateType;
private Integer priority;
@Data
public static class Limits implements Serializable{
private static final long serialVersionUID = 1L;
private String limitDetail;
private String limitTranslate;
}
}
...@@ -39,8 +39,6 @@ public class ApprovalLogServiceImpl implements IApprovalLogService{ ...@@ -39,8 +39,6 @@ public class ApprovalLogServiceImpl implements IApprovalLogService{
@Autowired @Autowired
private IApprovalLogRepository approvalLogRepository; private IApprovalLogRepository approvalLogRepository;
@Autowired @Autowired
private IFundModuleChannelFundConfigService fundModuleChannelFundConfigService;
@Autowired
private IFundModuleChannelFundConfigNewService fundModuleChannelFundConfigNewService; private IFundModuleChannelFundConfigNewService fundModuleChannelFundConfigNewService;
@Override @Override
...@@ -115,7 +113,6 @@ public class ApprovalLogServiceImpl implements IApprovalLogService{ ...@@ -115,7 +113,6 @@ public class ApprovalLogServiceImpl implements IApprovalLogService{
public void audit(ApprovalLog approvalLog, Integer auditStatus) { public void audit(ApprovalLog approvalLog, Integer auditStatus) {
if (auditStatus == AuditStatusEnum.PASS.getCode()) { if (auditStatus == AuditStatusEnum.PASS.getCode()) {
// 先更改审核记录, 这里返回的是新配置 // 先更改审核记录, 这里返回的是新配置
// FundModuleChannelFundConfig config = fundModuleChannelFundConfigService.auditPassConfig(approvalLog.getPreConfigId(), approvalLog.getAuditConfigId());
FundModuleChannelFundConfigNew config = fundModuleChannelFundConfigNewService.auditPassConfig(approvalLog.getPreConfigId(), approvalLog.getAuditConfigId()); FundModuleChannelFundConfigNew config = fundModuleChannelFundConfigNewService.auditPassConfig(approvalLog.getPreConfigId(), approvalLog.getAuditConfigId());
// 根据新配置清楚渠道缓存 // 根据新配置清楚渠道缓存
fundModuleChannelFundConfigNewService.clearChannelFundConfigCache(config.getBizChannel()); fundModuleChannelFundConfigNewService.clearChannelFundConfigCache(config.getBizChannel());
......
...@@ -10,6 +10,10 @@ import java.util.concurrent.ExecutorService; ...@@ -10,6 +10,10 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import com.quantgroup.asset.distribution.model.entity.fund.ChannelFundConfigNew;
import com.quantgroup.asset.distribution.service.funding.IFundModuleChannelFundConfigNewService;
import com.quantgroup.asset.distribution.service.jpa.entity.FundModuleChannelFundConfigNew;
import com.quantgroup.asset.distribution.service.rule.vo.IRuleVO;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
...@@ -64,7 +68,7 @@ public class AssetServiceImpl implements IAssetService{ ...@@ -64,7 +68,7 @@ public class AssetServiceImpl implements IAssetService{
@Autowired @Autowired
private IDistributeFailLogService distributeFailLogService; private IDistributeFailLogService distributeFailLogService;
@Autowired @Autowired
private IFundModuleChannelFundConfigService fundModuleCHannelFundConfigService; private IFundModuleChannelFundConfigNewService fundModuleChannelFundConfigNewService;
@Autowired @Autowired
private IRuleService ruleService; private IRuleService ruleService;
@Autowired @Autowired
...@@ -229,7 +233,7 @@ public class AssetServiceImpl implements IAssetService{ ...@@ -229,7 +233,7 @@ public class AssetServiceImpl implements IAssetService{
return null; return null;
} }
FundModuleChannelFundConfig config = fundModuleCHannelFundConfigService.findByBizChannel(assetForm.getBizChannel()); FundModuleChannelFundConfigNew config = fundModuleChannelFundConfigNewService.findByBizChannel(assetForm.getBizChannel());
if (config == null && (executeType == ExecuteType.TEST || !"true".equals(assetForm.getAuditResult()))) { if (config == null && (executeType == ExecuteType.TEST || !"true".equals(assetForm.getAuditResult()))) {
return null; return null;
} }
...@@ -237,28 +241,29 @@ public class AssetServiceImpl implements IAssetService{ ...@@ -237,28 +241,29 @@ public class AssetServiceImpl implements IAssetService{
JSONArray fundArray = new JSONArray(); JSONArray fundArray = new JSONArray();
// 资方去重, 可能存在多条件同一个资方 // 资方去重, 可能存在多条件同一个资方
Set<String> fundSet = new HashSet<>(); Set<String> fundSet = new HashSet<>();
List<ChannelFundConfig> fundConfigList = JSONArray.parseArray(config.getFunds(), ChannelFundConfig.class); List<ChannelFundConfigNew> fundConfigList = JSONArray.parseArray(config.getFunds(), ChannelFundConfigNew.class);
A : for (ChannelFundConfig channelFundConfig : fundConfigList) { A : for (ChannelFundConfigNew channelFundConfig : fundConfigList) {
List<ChannelFundConfig.Limit> limits = channelFundConfig.getLimits(); IRuleVO ruleVO = ruleService.getIRuleVo(channelFundConfig.getLimits());
// 是否配了审核条件 if (ruleVO != null) {
boolean hasAuditResultLimit = false; if (!ruleVO.valid(data)) {
if (CollectionUtils.isNotEmpty(limits)) { continue A;
for (ChannelFundConfig.Limit limit : limits) { }
String expression = limit.getLimit(); }
if (expression.contains("audit_result")) { // 如果参数为空,直接不满足
hasAuditResultLimit = true; Set<String> params = ruleVO.getParamNames();
} for (String key : params) {
if (!ruleService.valid(expression, data)) { if (!data.containsKey(key)) {
continue A; continue A;
} }
} }
// 是否配了审核条件
boolean hasAuditResultLimit = params.contains("audit_result");
if (!hasAuditResultLimit) { if (!hasAuditResultLimit) {
// 如果没配,自动过一层auditResult@true的条件 // 如果没配,自动过一层auditResult@true的条件
if (!ruleService.valid("audit_result==true", data)) { if (!ruleService.valid("audit_result==true", data)) {
continue A; continue A;
} }
} }
}
String key = channelFundConfig.getFundId() + "_" + channelFundConfig.getFundProductId() + "_" + channelFundConfig.getPriority(); String key = channelFundConfig.getFundId() + "_" + channelFundConfig.getFundProductId() + "_" + channelFundConfig.getPriority();
if (!fundSet.contains(key)) { if (!fundSet.contains(key)) {
// 创建并增加资方配置 // 创建并增加资方配置
......
package com.quantgroup.asset.distribution.service.rule; package com.quantgroup.asset.distribution.service.rule;
import com.quantgroup.asset.distribution.model.entity.fund.ChannelFundConfigNew;
import com.quantgroup.asset.distribution.service.rule.vo.IRuleVO;
import java.util.Map; import java.util.Map;
public interface IRuleService { public interface IRuleService {
...@@ -11,4 +14,19 @@ public interface IRuleService { ...@@ -11,4 +14,19 @@ public interface IRuleService {
* @return 返回true或者false * @return 返回true或者false
*/ */
public boolean valid(String expression, Map<String, Object> data); public boolean valid(String expression, Map<String, Object> data);
/**
* limitDetail表达式判断
* @param limits
* @param data
* @return
*/
public boolean validNew(ChannelFundConfigNew.Limits limits, Map<String, Object> data);
/**
* 获取IRuleVO规则对象
* @param limits
* @return
*/
public IRuleVO getIRuleVo(ChannelFundConfigNew.Limits limits);
} }
...@@ -3,6 +3,14 @@ package com.quantgroup.asset.distribution.service.rule.impl; ...@@ -3,6 +3,14 @@ package com.quantgroup.asset.distribution.service.rule.impl;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Map; import java.util.Map;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.quantgroup.asset.distribution.constant.RuleConstants;
import com.quantgroup.asset.distribution.enums.UnionType;
import com.quantgroup.asset.distribution.model.entity.fund.ChannelFundConfigNew;
import com.quantgroup.asset.distribution.service.rule.vo.BaseRuleVO;
import com.quantgroup.asset.distribution.service.rule.vo.IRuleVO;
import com.quantgroup.asset.distribution.service.rule.vo.UnionRuleVO;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
...@@ -15,6 +23,7 @@ import com.quantgroup.asset.distribution.util.calc.Expression; ...@@ -15,6 +23,7 @@ import com.quantgroup.asset.distribution.util.calc.Expression;
import com.quantgroup.asset.distribution.util.calc.Expression.ExpressionException; import com.quantgroup.asset.distribution.util.calc.Expression.ExpressionException;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
/** /**
* 规则判断 * 规则判断
...@@ -46,4 +55,91 @@ public class RuleServiceImpl implements IRuleService{ ...@@ -46,4 +55,91 @@ public class RuleServiceImpl implements IRuleService{
} }
} }
@Override
public boolean validNew(ChannelFundConfigNew.Limits limits, Map<String, Object> data) {
try {
if (StringUtils.isEmpty(limits.getLimitDetail())) { throw new QGException(QGExceptionType.RULE_EXPRESSION_IS_EMPTY); }
IRuleVO ruleVO = translateFromWebFrontJSON(limits.getLimitDetail());
return ruleVO.valid(data);
} catch (QGException qx) {
log.error("规则判断出现错误, limitDetail : {}, limitTranslate : {}, data : {}", limits.getLimitDetail(), limits.getLimitTranslate(), data);
throw qx;
} catch (Exception e) {
log.error("规则判断出现未知异常, limitDetail : {}, limitTranslate : {}, data : {}", limits.getLimitDetail(), limits.getLimitTranslate(), data);
throw new QGException(QGExceptionType.RULE_CALC_ERROR, limits.getLimitTranslate());
}
}
@Override
public IRuleVO getIRuleVo(ChannelFundConfigNew.Limits limits) {
if (StringUtils.isEmpty(limits.getLimitDetail())) { throw new QGException(QGExceptionType.RULE_EXPRESSION_IS_EMPTY); }
IRuleVO ruleVO = translateFromWebFrontJSON(limits.getLimitDetail());
return ruleVO;
}
/**
* JSON转IRuleVO
*
* @param json
* @return
*/
private IRuleVO translateFromWebFrontJSON(String json) {
try {
JSONObject jsonObject = JSON.parseObject(json);
if (!isUnionRule(jsonObject))
return jsonObject.toJavaObject(BaseRuleVO.class);
return translateUnionRuleVO(jsonObject);
} catch (Exception e) {
log.error("解析规则json出错,错误内容为 : {}", json, e);
throw new QGException(QGExceptionType.RULE_EXPRESSION_IS_EMPTY);
}
}
/**
* 检测是否组合规则
*
* @param jsonObject
* @return
*/
private boolean isUnionRule(JSONObject jsonObject) {
QGPreconditions.checkArgument(jsonObject != null, QGExceptionType.RULE_IS_NOT_JSON);
if (jsonObject.containsKey(RuleConstants.CONDITION)) {
checkUnionRule(jsonObject);
return true;
}
checkBaseRule(jsonObject);
return false;
}
/**
* JSON转UnionRuleVO
*
* @param jsonObject
* @return
*/
private UnionRuleVO translateUnionRuleVO(JSONObject jsonObject) {
JSONArray jsonArray = jsonObject.getJSONArray(RuleConstants.CONDITION);
UnionRuleVO unionRuleVO = new UnionRuleVO(UnionType.fromCode(jsonObject.getString(RuleConstants.OPERATOR)));
for (int i = 0; i < jsonArray.size(); i++) {
JSONObject child = jsonArray.getJSONObject(i);
if (!isUnionRule(child)) {
unionRuleVO.getBaseRules().add(child.toJavaObject(BaseRuleVO.class));
} else {
unionRuleVO.getUnionRules().add(translateUnionRuleVO(child));
}
}
return unionRuleVO;
}
private void checkUnionRule(JSONObject jsonObject) {
QGPreconditions.checkArgument(jsonObject.containsKey(RuleConstants.OPERATOR) && jsonObject.size() >= 2, QGExceptionType.RULE_IS_NOT_JSON);
QGPreconditions.checkArgument(!CollectionUtils.isEmpty(jsonObject.getJSONArray(RuleConstants.CONDITION)), QGExceptionType.RULE_IS_NOT_JSON);
QGPreconditions.checkArgument(StringUtils.equalsAnyIgnoreCase(jsonObject.getString(RuleConstants.OPERATOR), RuleConstants.AND, RuleConstants.OR), QGExceptionType.RULE_IS_NOT_JSON);
}
private void checkBaseRule(JSONObject jsonObject) {
QGPreconditions.checkArgument(jsonObject.containsKey(RuleConstants.OPERATOR) && jsonObject.size() >= 3, QGExceptionType.RULE_IS_NOT_JSON);
QGPreconditions.checkArgument(jsonObject.containsKey(RuleConstants.KEY), QGExceptionType.RULE_IS_NOT_JSON);
QGPreconditions.checkArgument(jsonObject.containsKey(RuleConstants.VAL), QGExceptionType.RULE_IS_NOT_JSON);
}
} }
package com.quantgroup.asset.distribution.service.rule.vo;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import com.google.common.primitives.Doubles;
import com.quantgroup.asset.distribution.enums.RuleOperator;
import com.quantgroup.asset.distribution.exception.QGException;
import com.quantgroup.asset.distribution.exception.QGExceptionType;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
@Data
@AllArgsConstructor
@NoArgsConstructor
@JSONType(typeName = "base", serialzeFeatures = SerializerFeature.WriteEnumUsingToString)
@Slf4j
public class BaseRuleVO implements IRuleVO, Serializable {
private static final long serialVersionUID = -1L;
public static final String IN_FORMAT = "%s in (%s)";
public static final String NOT_IN_FORMAT = "%s not in (%s)";
private String key;
private String operator;
@JSONField(name = "value")
private String value;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BaseRuleVO that = (BaseRuleVO) o;
return Objects.equal(key, that.key) &&
Objects.equal(operator, that.operator) &&
Objects.equal(value, that.value);
}
@Override
public String format() {
switch (RuleOperator.fromCode(operator)) {
case In:
return String.format(IN_FORMAT, key, value);
case NotIn:
return String.format(NOT_IN_FORMAT, key, value);
default:
return key + operator + value;
}
}
@Override
public boolean valid(Map<String, Object> data) {
if(data == null || !data.containsKey(key)){
log.info("规则数据不存在,key:{},operator:{},value:{}",key,operator,value);
throw new QGException(QGExceptionType.DATA_NOT_EXIST_FOR_RULE,key,operator,value);
}
if(operator == null){
log.info("规则符为空,key:{},value:{}",key,value);
throw new QGException(QGExceptionType.RULE_OPERATOR_IS_EMPTY);
}
Object object = data.get(key);
if(object == null){
log.info("规则数据为空,key:{},operator:{},value:{}",key,operator,value);
throw new QGException(QGExceptionType.RULE_DATA_IS_EMPTY,key,operator,value);
}
return compareCommon(object);
}
@Override
public Map<String, Boolean> valid2(Map<String, Object> data) {
return ImmutableMap.of(this.format(),compareCommon(data.get(key)));
}
/**
* 比较
* @param object
* @return
*/
private boolean compareCommon(Object object){
try {
if (object instanceof Integer)
return Doubles.tryParse(value) == null ? operateInt((Integer) object) : operateBigDecimal(BigDecimal.valueOf(((Integer) object)));
if (object instanceof Float)
return operateBigDecimal(BigDecimal.valueOf(((Float) object)));
if (object instanceof Double)
return operateBigDecimal(BigDecimal.valueOf(((Double) object)));
if (object instanceof BigDecimal)
return operateBigDecimal((BigDecimal) object);
//防止 仿真把数字传成字符串
try {
return operateBigDecimal(BigDecimal.valueOf((Double.parseDouble(String.valueOf(object)))));
} catch (NumberFormatException e) {
return operateString(String.valueOf(object));
}
} catch (Exception e) {
log.error("数据比较出现错误,key:{}, 配置数据:{}, 待比较的数据:{}", key, value, object, e);
throw new QGException(QGExceptionType.DATA_COMPARE_ERROR);
}
}
@Override
public String getId() {
return null;
}
private boolean operateInt(int data) {
switch (RuleOperator.fromCode(operator)) {
case Equal:
return Integer.parseInt(value) == data;
case In:
return Arrays.stream(StringUtils.split(value, ',')).filter(StringUtils::isNumeric).map(Integer::parseInt).anyMatch(i -> data == i);
case NotIn:
return Arrays.stream(StringUtils.split(value, ',')).filter(StringUtils::isNumeric).map(Integer::parseInt).noneMatch(i -> data == i);
case LessThan:
return data < Integer.parseInt(value);
case NotEqual:
return data != Integer.parseInt(value);
case GreaterThan:
return data > Integer.parseInt(value);
case LessThanOrEqual:
return data <= Integer.parseInt(value);
case GreaterThanOrEqual:
return data >= Integer.parseInt(value);
default:
throw new QGException(QGExceptionType.RULE_OPERATOR_NOT_EXIST);
}
}
private boolean operateBigDecimal(BigDecimal data) {
switch (RuleOperator.fromCode(operator)) {
case Equal:
return new BigDecimal(value).compareTo(data) == 0;
case In:
return Arrays.stream(StringUtils.split(value, ',')).filter(StringUtils::isNumeric).map(BigDecimal::new).anyMatch(o -> o.compareTo(data) == 0);
case NotIn:
return Arrays.stream(StringUtils.split(value, ',')).filter(StringUtils::isNumeric).map(BigDecimal::new).noneMatch(o -> o.compareTo(data) == 0);
case LessThan:
return new BigDecimal(value).compareTo(data) > 0;
case NotEqual:
return new BigDecimal(value).compareTo(data) != 0;
case GreaterThan:
return new BigDecimal(value).compareTo(data) < 0;
case LessThanOrEqual:
return new BigDecimal(value).compareTo(data) >= 0;
case GreaterThanOrEqual:
return new BigDecimal(value).compareTo(data) <= 0;
default:
throw new QGException(QGExceptionType.RULE_OPERATOR_NOT_EXIST);
}
}
private boolean operateString(String data) {
switch (RuleOperator.fromCode(operator)) {
case Equal:
return StringUtils.equals(StringUtils.replaceAll(value, "\"", ""), data);
case In:
return Arrays.stream(StringUtils.split(StringUtils.replaceAll(value, "\"", ""), ',')).anyMatch(data::equals);
case NotIn:
return Arrays.stream(StringUtils.split(StringUtils.replaceAll(value, "\"", ""), ',')).noneMatch(data::equals);
case LessThan:
return StringUtils.compare(data, StringUtils.replaceAll(value, "\"", "")) < 0;
case NotEqual:
return !StringUtils.equals(data, StringUtils.replaceAll(value, "\"", ""));
case GreaterThan:
return StringUtils.compare(data, StringUtils.replaceAll(value, "\"", "")) > 0;
case LessThanOrEqual:
return StringUtils.compare(data, StringUtils.replaceAll(value, "\"", "")) <= 0;
case GreaterThanOrEqual:
return StringUtils.compare(data, StringUtils.replaceAll(value, "\"", "")) >= 0;
default:
throw new QGException(QGExceptionType.RULE_OPERATOR_NOT_EXIST);
}
}
@Override
public void checkParams() {
}
@Override
public Set<String> getParamNames() {
return Sets.newHashSet(key);
}
}
\ No newline at end of file
package com.quantgroup.asset.distribution.service.rule.vo;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONType;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import java.util.Map;
import java.util.Set;
/**
* @author : Hyuk
* @description : IRuleVO
* @date : 2020/3/5 4:50 下午
*/
//支持fastjson
@JSONType(seeAlso = {BaseRuleVO.class, UnionRuleVO.class})
//支持jackson
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "@type")
@JsonSubTypes({
@JsonSubTypes.Type(value = BaseRuleVO.class, name = "base"),
@JsonSubTypes.Type(value = UnionRuleVO.class, name = "union")})
public interface IRuleVO {
boolean valid(Map<String, Object> data);
/**
* 记录拒绝规则 二次校验
*
* @param data
* @return
*/
Map<String, Boolean> valid2(Map<String, Object> data);
String getId();
void checkParams();
Set<String> getParamNames();
String format();
default String toJSONString() {
return JSON.toJSONString(this, SerializerFeature.WriteClassName, SerializerFeature.WriteEnumUsingName);
}
}
package com.quantgroup.asset.distribution.service.rule.vo;
import com.alibaba.fastjson.annotation.JSONType;
import com.google.common.base.Joiner;
import com.google.common.base.Objects;
import com.google.common.collect.Lists;
import com.quantgroup.asset.distribution.enums.UnionType;
import com.quantgroup.asset.distribution.exception.QGException;
import com.quantgroup.asset.distribution.exception.QGExceptionType;
import com.quantgroup.asset.distribution.exception.QGPreconditions;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.collections.MapUtils;
import org.springframework.util.CollectionUtils;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* {condition:[
* {key:’v5’, operator:’<‘, value:’0.2’},
* {key:’v4’, operator:’in‘, value:’100,200,4900’},
* {condition:[{key:’v5’, operator:’<‘, value:’0.2’},{key:’v4’, operator:’<‘, value:’100’}], operator:’or’}
* ], operator:’and’}
* <p>
* v5<0.2 && v4<100 && (v5<0.2 || v4<100)
* <p>
* {condition:[{key:’v5’,operator:’<‘,value:’0.2’},{key:’v4’,operator:’<‘,value:’100’}],operator:’and’}
*/
@Data
@NoArgsConstructor
@JSONType(typeName = "union")
public class UnionRuleVO implements IRuleVO, Serializable {
private static final long serialVersionUID = -1L;
private UnionType unionType;
private List<UnionRuleVO> unionRules = Lists.newArrayList();
private List<BaseRuleVO> baseRules = Lists.newArrayList();
public UnionRuleVO(UnionType unionType) {
this.unionType = unionType;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UnionRuleVO that = (UnionRuleVO) o;
return unionType == that.unionType &&
Objects.equal(unionRules, that.unionRules) &&
Objects.equal(baseRules, that.baseRules);
}
@Override
public boolean valid(Map<String, Object> data) {
QGPreconditions.checkArgument(!(CollectionUtils.isEmpty(baseRules) && CollectionUtils.isEmpty(unionRules)), QGExceptionType.RULE_IS_NOT_JSON);
switch (unionType) {
case Or:
return unionRules.stream().anyMatch(r -> r.valid(data))
|| baseRules.stream().anyMatch(r -> r.valid(data));
case And:
return unionRules.stream().allMatch(r -> r.valid(data))
&& baseRules.stream().allMatch(r -> r.valid(data));
default:
throw new QGException(QGExceptionType.RULE_UNION_OPERATOR_NOT_EXIST);
}
}
@Override
public Map<String, Boolean> valid2(Map<String, Object> data) {
Map<String,Boolean> maps = new HashMap<>();
Map<String, Boolean> umap = unionRules.parallelStream().collect(Collectors.toMap(k -> k.format(), v -> v.valid(data)));
Map<String, Boolean> bmap = baseRules.parallelStream().collect(Collectors.toMap(k -> k.format(), v -> v.valid(data)));
if(MapUtils.isNotEmpty(umap))
maps.putAll(umap);
if(MapUtils.isNotEmpty(bmap))
maps.putAll(bmap);
return maps;
}
@Override
public String format() {
StringBuilder stringBuilder = new StringBuilder();
String operator = unionType == UnionType.And ? "&&" : "||";
stringBuilder.append(Joiner.on(operator).join(baseRules.parallelStream().map(BaseRuleVO::format).collect(Collectors.toList())));
if (!CollectionUtils.isEmpty(unionRules)) {
if (!CollectionUtils.isEmpty(baseRules))
stringBuilder.append(operator);
stringBuilder.append(Joiner.on(operator).join(unionRules.parallelStream().map(r -> "(" + r.format() + ")").collect(Collectors.toList())));
}
return stringBuilder.toString();
}
@Override
public String getId() {
return null;
}
@Override
public void checkParams() {
}
@Override
public Set<String> getParamNames() {
Set<String> keys = baseRules.parallelStream().map(BaseRuleVO::getKey).collect(Collectors.toSet());
if (!CollectionUtils.isEmpty(unionRules))
unionRules.parallelStream().forEach(unionRuleVO -> keys.addAll(unionRuleVO.getParamNames()));
return keys;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment