7.5 消费方应用接入方式
在UDM中消费方(规则调用方)应用接入方式通常有2种:(1)Http rest方式直接请求规则管理端http服务,(2)SDK方式通过java api调用并执行规则包。
7.5.1 Http rest方式
启用规则包Http服务
启用当前规则包对外的Http Rest服务功能,用于控制第三方消费者是否允许调用指定的rest服务接口

调用示例
- RuleApp规则包在线模拟测试
{
"empVar": {
"age": 27,
"sex": "男"
}
}

- 三方http测试工具模拟测试

7.5.2 SDK方式
消费方应用程序须依赖udm-core组件
<dependency>
<groupId>com.bstek.udm</groupId>
<artifactId>udm-core</artifactId>
<version>${udm-core.version}</version>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.github.classgraph</groupId>
<artifactId>classgraph</artifactId>
<version>${classgraph.version}</version>
</dependency>
调用java api接口执行决策
- 获取规则包字节流
String base64ZipTestFileContent=null; // TODO 开发者自行实现,规则包从哪儿获取到:数据库udm_ruleapp_version中 / 缓存中
- 构建规则执行会话对象
byte[] decodedBytes = Base64.getDecoder().decode(base64ZipTestFileContent);
InputStream inputStream = new ByteArrayInputStream(decodedBytes);
KnowledgeArchive knowledgeArchive =new InputStreamKnowledgeArchive(inputStream, new Date().getTime());
KnowledgeSession knowledgeSession = KnowledgeService.INSTANCE.newSession(knowledgeArchive);
Map<String, ObjectValue> inputDataMap = (Map<String, ObjectValue>) buildInputData(map);
- 构建输入数据
Map<String, Object> empVarMap = new HashMap<>();
// FIXME 请开发者修改成实际业务数据
empVarMap.put("age",20);
// 处理输入数据
Map<String, ObjectValue> inputDataMap = KnowledgeHelper.buildInputData(empVarMap, knowledgeSession);
// 以下3个方为固定写法,直接复制即可
public static Map<String, ObjectValue> buildInputData(Map<String, Object> map, KnowledgeSession knowledgeSession) {
ClassLoader classLoader = knowledgeSession.getKnowledgeClassLoader();
Map<String, Variable> inputVariables = knowledgeSession.getKnowledgeInputVariables();
Map<String, ObjectValue> inputDataMap = new HashMap<>();
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = "'" + entry.getKey() + "'";
if (!inputVariables.containsKey(key)) {
//当前当前输入的变量不在当前关联的知识包中的输入变量中,那么就直接忽略
continue;
}
Object value = entry.getValue();
Variable variable = inputVariables.get(key);
String datatype = variable.getType();
Class<?> clazz = ReflectionUtils.loadTargetClass(datatype, classLoader);
//先判断当前clazz是否为简单类型
if (ClassUtils.isSimpleType(clazz)) {
//当前clazz为简单类型,那么就直接构建出当前的ObjectValue
value = ReflectionUtils.buildValueByType(value, clazz);
ObjectValue objectValue = new ObjectValue(value, clazz.getName());
inputDataMap.put(key, objectValue);
} else {
Object obj = newInstanceByClass(clazz);
Map<String, Object> mapValue = (Map<String, Object>) value;
buildObject(mapValue, obj);
ObjectValue objectValue = new ObjectValue(obj, clazz.getName());
inputDataMap.put(key, objectValue);
}
}
return inputDataMap;
}
@SuppressWarnings("unchecked")
private static void buildObject(Map<String, Object> mapValue, Object obj) {
for (Map.Entry<String, Object> entry : mapValue.entrySet()) {
String fieldName = entry.getKey();
if (fieldName.equals(DATATYPE_KEY)) {
//当前字段为客户端提交上来的标识类型的字段,那么就直接忽略
continue;
}
Object fieldValue = entry.getValue();
//获取当前对象对应的字段属性类型
Class<?> propertyTypeClass = ReflectionUtils.getPropertyType(fieldName, obj.getClass());
if (ClassUtils.isSimpleType(propertyTypeClass)) {
//当前属性为简单类型,那么就根据类型转换一下当前的fieldValue
Object newValue = ReflectionUtils.buildValueByType(fieldValue, propertyTypeClass);
//将转换后的值设置到当前的对象中
ReflectionUtils.setObjectPropertyValue(obj, fieldName, newValue);
} else if (List.class.isAssignableFrom(propertyTypeClass)) {
//当前属性为列表类型,那么就递归调用buildObject方法
List<Object> list = new ArrayList<>();
//尝试从属性类型里获取泛型类型
Class<?> genericTypeClass = propertyTypeClass.getComponentType();
if (genericTypeClass == null) {
//如果当前列表类型没有指定泛型类型,那么就直接忽略
continue;
}
if (fieldValue instanceof List) {
//如果当前值为列表类型,那么就循环取出列表中的每个元素的值
for (Object item : (List<Object>) fieldValue) {
//判断泛型类型是否为简单类型,如果是则直接转换当前值为简单类型
Object value = item;
if (ClassUtils.isSimpleType(genericTypeClass)) {
value = ReflectionUtils.buildValueByType(value, genericTypeClass);
list.add(value);
} else if (item instanceof Map) {
//如果当前项目为Map类型,那么就递归调用buildObject方法
Object subObject = newInstanceByClass(genericTypeClass);
buildObject((Map<String, Object>) item, subObject);
list.add(subObject);
}
}
} else {
//当前值不是列表,那么就需要根据泛型类型创建一个新的对象
Object value = ReflectionUtils.buildValueByType(fieldValue, genericTypeClass);
list.add(value);
}
ReflectionUtils.setObjectPropertyValue(obj, fieldName, list);
} else {
//当前属性为复杂对象类型,那么就递归调用buildObject方法
Object subObject = newInstanceByClass(propertyTypeClass);
buildObject((Map<String, Object>) fieldValue, subObject);
ReflectionUtils.setObjectPropertyValue(obj, fieldName, subObject);
}
}
}
private static Object newInstanceByClass(Class<?> clazz) {
if (clazz.isInterface()) {
//如果当前clazz是一个接口类,那么就尝试扫描对应的实现类
try (ScanResult scanResult = new ClassGraph().enableAllInfo().scan()) {
List<Class<?>> classes = scanResult.getSubclasses(clazz.getName()).loadClasses();
Class<?> targetClazz = null;
for (Class<?> c : classes) {
//找到一个非接口非抽象类的类
if (!c.isInterface() && !Modifier.isAbstract(c.getModifiers())) {
targetClazz = c;
break;
}
}
if (targetClazz != null) {
//如果存在实现类,那么就取第一个实现类
clazz = targetClazz;
} else {
throw new RuleException("接口类" + clazz.getName() + "不存在对应的实现类");
}
} catch (Exception e) {
//对应的类型不存在,那么就直接抛出异常
throw new RuleException(e);
}
}
try {
return clazz.newInstance();
} catch (Exception e) {
throw new RuleException(e);
}
}
- 执行规则匹配,返回决策结果
// 执行匹配
ExecutionConfiguration configuration = new ExecutionConfiguration(true);
CollectionLogListener collectionLogListener = new CollectionLogListener();
configuration.addListener(collectionLogListener);
KnowledgeSessionResponse response = knowledgeSession.execute(inputDataMap, configuration);
// 读取匹配结果
Map<String, Object> outputParameters = response.getOutputParameters();
Map<String, Object> resultMap = new HashMap<>();// 重新包装规则匹配结果
resultMap.put("log", collectionLogListener.getRootLog());
resultMap.put("output", outputParameters);
resultMap.put("elapse", response.getExecutionDuration());