指标库:保存原子指标

This commit is contained in:
huangge1199 2025-08-07 17:13:40 +08:00
parent bec249ced3
commit 0a682ac155
9 changed files with 779 additions and 78 deletions

View File

@ -53,4 +53,11 @@ public class TargetController {
String result = targetService.getResult(params);
return R.ok(result);
}
@Operation(summary = "保存指标")
@PostMapping("/saveTarget")
public R<?> saveTarget(@RequestBody JSONObject params) {
targetService.saveTarget(params);
return R.ok();
}
}

View File

@ -83,7 +83,7 @@ public class Monitor {
* 目标值
*/
@TableField(value = "target")
private String target;
private Double target;
/**
*

View File

@ -1,8 +1,11 @@
package iet.ustb.sf.service;
import iet.ustb.sf.domain.Target;
import iet.ustb.sf.domain.TargetData;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.Map;
/**
* @author hyy
* @description 针对表mbgk_target_data的数据库操作Service
@ -10,4 +13,13 @@ import com.baomidou.mybatisplus.extension.service.IService;
*/
public interface TargetDataService extends IService<TargetData> {
/**
* 更新历史数据
*
* @param target 指标
* @param strArr xShow, cycle, setDate, start, end
* @param map 关联的指标数据
* @return 结果
*/
TargetData updateHistory(Target target, String[] strArr, Map<String, TargetData> map);
}

View File

@ -19,4 +19,6 @@ public interface TargetService extends IService<Target> {
List<String> searchColumn(JSONObject params);
String getResult(JSONObject params);
void saveTarget(JSONObject params);
}

View File

@ -0,0 +1,54 @@
package iet.ustb.sf.service;
import iet.ustb.sf.domain.Monitor;
import iet.ustb.sf.domain.Rule;
import iet.ustb.sf.domain.Target;
import iet.ustb.sf.domain.TargetData;
import java.util.Date;
/**
* UtilService
*
* @author huangge1199
* @since 2025/8/7 15:11:03
*/
public interface UtilService {
/**
* 获取指定周期的对应日期 xShow, cycle, setDate, start, end
*
* @param date 日期
* @param cycle 周期
* @return 结果
*/
String[] getCurrentCycleDataByCycle(Date date, String cycle);
/**
* 计算表达式结果
*
* @param expression 表达式
* @return 结果
*/
double getEvalResult(String expression);
/**
* 该规则是否触发
*
* @param rule 规则信息
* @param target 指标信息
* @param targetData 指标数据
* @return 结果
*/
boolean isWarn(Rule rule, Target target, TargetData targetData);
/**
* 获取初始化监控数据
*
* @param targetData 指标数据
* @param target 指标信息
* @param rule 规则信息
* @return 结果
*/
Monitor getInitMonitor(TargetData targetData, Target target, Rule rule);
}

View File

@ -1,11 +1,22 @@
package iet.ustb.sf.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import iet.ustb.sf.domain.TargetData;
import com.baomidou.mybatisplus.extension.toolkit.SqlRunner;
import iet.ustb.sf.domain.*;
import iet.ustb.sf.mapper.MonitorMapper;
import iet.ustb.sf.mapper.RuleMapper;
import iet.ustb.sf.mapper.TargetMapper;
import iet.ustb.sf.service.TargetDataService;
import iet.ustb.sf.mapper.TargetDataMapper;
import iet.ustb.sf.service.UtilService;
import iet.ustb.sf.util.CheckUtils;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* @author hyy
* @description 针对表mbgk_target_data的数据库操作Service实现
@ -15,6 +26,146 @@ import org.springframework.stereotype.Service;
public class TargetDataServiceImpl extends ServiceImpl<TargetDataMapper, TargetData>
implements TargetDataService {
@Resource
private TargetDataMapper targetDataMapper;
@Resource
private TargetMapper targetMapper;
@Resource
private UtilService utilService;
@Resource
private MonitorMapper monitorMapper;
@Resource
private RuleMapper ruleMapper;
@Override
public TargetData updateHistory(Target target, String[] strArr, Map<String, TargetData> map) {
String xShow = strArr[0];
QueryWrapper<TargetData> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("target_id", target.getId());
queryWrapper.eq("x_show", xShow);
TargetData targetData = targetDataMapper.selectOne(queryWrapper);
if (targetData != null && targetData.getId() != null) {
return targetData;
}
double result;
if (target.getType() < 2) {
List<Map<String, Object>> list = SqlRunner.db().selectList(target.getResultSql(), strArr[3], strArr[4]);
result = Double.parseDouble(list.get(0).get("result").toString());
} else {
String exprStr = target.getResultSql();
String[] expressionList = exprStr.split(",");
List<String> opList = Arrays.asList("+", "-", "*", "/", "(", ")");
List<String> idList = new ArrayList<>();
for (String expression : expressionList) {
if (!opList.contains(expression) && !idList.contains(expression)) {
idList.add(expression);
}
}
List<Target> targetList = targetMapper.selectByIds(idList);
exprStr = exprStr.replaceAll(",", "");
if (map == null) {
map = new HashMap<>();
}
for (Target child : targetList) {
double val;
if (map.containsKey(child.getId())) {
val = map.get(child.getId()).getVal();
} else {
TargetData tmp = updateHistory(child, strArr, map);
map.put(child.getId(), tmp);
val = tmp.getVal();
}
exprStr = exprStr.replaceAll(child.getId(), val + "");
}
result = utilService.getEvalResult(exprStr);
}
Date now = new Date();
try {
targetData = TargetData.builder()
.id(UUID.randomUUID().toString())
.targetId(target.getId())
.setDate(new SimpleDateFormat("yyyy-MM-dd").parse(strArr[2]))
.xShow(xShow)
.cycle(strArr[1])
.createTime(now)
.updateTime(now)
.val(CheckUtils.roundToDecimalPlaces(result, 6))
.targetCycle(target.getCycle())
.build();
targetDataMapper.insert(targetData);
} catch (Exception e) {
throw new RuntimeException(e);
}
saveMonitor(targetData);
return targetData;
}
/**
* 新的指标数据添加监控数据
*
* @param targetData 指标数据
*/
public void saveMonitor(TargetData targetData) {
double val = targetData.getVal();
String targetId = targetData.getTargetId();
Target target = targetMapper.selectById(targetId);
Date now = new Date();
QueryWrapper<Monitor> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("target_id", target.getId());
queryWrapper.eq("x_show", targetData.getXShow());
monitorMapper.delete(queryWrapper);
Monitor monitor = Monitor.builder()
.id(UUID.randomUUID().toString())
.targetId(targetId)
.name(target.getName())
.type(target.getType())
.topic(target.getTopic())
.organization(target.getOrganization())
.level(target.getLevel())
.unit(target.getUnit())
.val(val)
.warnLevel(999)
.setDate(targetData.getSetDate())
.xShow(targetData.getXShow())
.createTime(now)
.updateTime(now)
.build();
List<Rule> ruleList = ruleMapper.selectList(new QueryWrapper<Rule>().eq("target_id", target.getId()));
if (ruleList == null || ruleList.isEmpty()) {
monitorMapper.insert(monitor);
return;
}
List<Monitor> monitorList = new ArrayList<>();
monitorList.add(monitor);
boolean bl = false;
Rule oneRule = null;
for (Rule rule : ruleList) {
if (oneRule == null || oneRule.getWarnLevel() > rule.getWarnLevel()) {
oneRule = rule;
}
bl = utilService.isWarn(rule, target, targetData);
if (bl) {
monitorList.add(utilService.getInitMonitor(targetData, target, rule));
}
}
if (!bl) {
Monitor mbgkMonitor = utilService.getInitMonitor(targetData, target, oneRule);
mbgkMonitor.setWarnLevel(998);
monitorList.add(mbgkMonitor);
}
monitorMapper.insert(monitorList);
}
}

View File

@ -1,6 +1,5 @@
package iet.ustb.sf.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
@ -9,21 +8,22 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlRunner;
import iet.ustb.sf.domain.Category;
import iet.ustb.sf.domain.Target;
import iet.ustb.sf.domain.TargetData;
import iet.ustb.sf.domain.TargetOption;
import iet.ustb.sf.exception.ErrorCode;
import iet.ustb.sf.exception.ThrowUtils;
import iet.ustb.sf.mapper.CategoryMapper;
import iet.ustb.sf.mapper.TargetDataMapper;
import iet.ustb.sf.service.TargetDataService;
import iet.ustb.sf.service.TargetService;
import iet.ustb.sf.mapper.TargetMapper;
import iet.ustb.sf.service.UtilService;
import iet.ustb.sf.util.CheckUtils;
import jakarta.annotation.Resource;
import lombok.val;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
@ -42,6 +42,15 @@ public class TargetServiceImpl extends ServiceImpl<TargetMapper, Target>
@Resource
private CategoryMapper categoryMapper;
@Resource
private TargetDataMapper targetDataMapper;
@Resource
private TargetDataService targetDataService;
@Resource
private UtilService utilService;
@Override
public IPage<Target> getTargetsByCategory(JSONObject params) {
int pageIndex = Optional.ofNullable(params.getInteger("pageIndex")).orElse(1);
@ -94,6 +103,178 @@ public class TargetServiceImpl extends ServiceImpl<TargetMapper, Target>
return list.get(0).get(result.getColumnName()).toString();
}
@Override
@Transactional(rollbackFor = Exception.class)
public void saveTarget(JSONObject params) {
Target target = params.getJSONObject("target").toJavaObject(Target.class);
List<TargetOption> showList = params.getJSONArray("show").toJavaList(TargetOption.class);
List<TargetOption> searchList = params.getJSONArray("search").toJavaList(TargetOption.class);
TargetOption result = params.getJSONObject("result").toJavaObject(TargetOption.class);
checkTarget(target);
String columns = showList.stream().map(TargetOption::getColumnName).collect(Collectors.joining(","));
CheckUtils.checkColumns(columns, target.getTableName());
CheckUtils.checkSearchOption(searchList, target.getTableName());
CheckUtils.checkResultOption(result, target.getTableName());
Date now = new Date();
target.setSearchSql(getSearchSql(showList, searchList, target.getTableName()));
params.put("tableName", target.getTableName());
target.setResultSql(getResultSql(params));
target.setUpdateTime(now);
Map<String, List<TargetOption>> optionsMap = showList.stream()
.peek(option -> {
option.setTargetId(target.getId());
if (option.getCreateTime() == null) {
option.setCreateTime(now);
}
option.setUpdateTime(now);
})
.collect(Collectors.groupingBy(TargetOption::getColumnName));
String cycle = null;
for (TargetOption option : searchList) {
List<TargetOption> options = optionsMap.get(option.getColumnName());
if (options != null && !options.isEmpty()) {
TargetOption ori = options.get(0);
ori.setOp(ori.getOp() + "," + option.getOp());
ori.setFun(option.getFun());
ori.setVal(option.getVal());
if ("1".equals(option.getOp()) && option.getType() == 1) {
if (cycle == null) {
cycle = option.getFun();
continue;
}
ThrowUtils.throwIf(!cycle.equals(option.getFun()), ErrorCode.PARAMS_ERROR, "日期类型的周期不一致!");
}
}
}
ThrowUtils.throwIf(StringUtils.isEmpty(cycle), ErrorCode.PARAMS_ERROR, "缺少时间条件,无法保存!");
target.setCycle(cycle);
if (target.getId() == null) {
target.setId(UUID.randomUUID().toString());
target.setCreateTime(now);
if (!StringUtils.isEmpty(target.getCategoryId())) {
categoryDeal(null, target);
}
targetMapper.insert(target);
saveDate(target);
}
}
/**
* 指标变动后指标数据处理
*
* @param target 指标
*/
private void saveDate(Target target) {
targetDataMapper.delete(new QueryWrapper<TargetData>().eq("target_id", target.getId()));
String[] strArr = utilService.getCurrentCycleDataByCycle(new Date(), target.getCycle());
targetDataService.updateHistory(target, strArr, null);
}
/**
* 指标变动处理对应的分类
*
* @param oldTarget 旧指标
* @param newTarget 新指标
*/
@Transactional(rollbackFor = Exception.class)
public void categoryDeal(Target oldTarget, Target newTarget) {
if (oldTarget == null && newTarget == null) {
return;
}
Set<String> oldList = oldTarget == null ? new HashSet<>() : getOrganizationList(oldTarget.getOrganization());
Set<String> newList = newTarget == null ? new HashSet<>() : getOrganizationList(newTarget.getOrganization());
String tagetId = oldTarget == null ? newTarget.getId() : oldTarget.getId();
String categoryId = oldTarget == null ? newTarget.getCategoryId() : oldTarget.getCategoryId();
QueryWrapper<Target> query = new QueryWrapper<>();
query.eq("category_id", categoryId);
query.ne("id", tagetId);
List<Target> targetList = targetMapper.selectList(query);
Set<String> set = new HashSet<>();
for (Target target : targetList) {
set.addAll(getOrganizationList(target.getOrganization()));
}
Category category = categoryMapper.selectById(categoryId);
Set<String> organizationSet = getOrganizationList(category.getOrganization());
Iterator<String> iterator = newList.iterator();
while (iterator.hasNext()) {
String news = iterator.next();
if (!oldList.isEmpty() && oldList.contains(news)) {
oldList.remove(news);
iterator.remove();
continue;
}
if (!set.contains(news)) {
organizationSet.add(news);
}
}
for (String old : oldList) {
if (!set.contains(old)) {
organizationSet.remove(old);
}
}
category.setOrganization(String.join(",", organizationSet));
categoryMapper.insertOrUpdate(category);
}
/**
* 把用逗号拼接的组织字符串转为set集合
*
* @param organization 组织字符串
* @return set组织集合
*/
private Set<String> getOrganizationList(String organization) {
Set<String> set = new HashSet<>();
if (StringUtils.isEmpty(organization)) {
return set;
}
if (organization.contains(",")) {
set.addAll(Arrays.asList(organization.split(",")));
} else {
set.add(organization);
}
return set;
}
/**
* 拼接列表查询SQL
*
* @param showList 查询集合
* @param searchList 条件集合
* @param tableName 表名
* @return SQL
*/
private String getSearchSql(List<TargetOption> showList, List<TargetOption> searchList, String tableName) {
return "SELECT " + showList.stream().map(TargetOption::getColumnName).collect(Collectors.joining(","))
+ " FROM " + tableName + " WHERE " + getWhereSql(searchList);
}
/**
* 指标空值校验
*
* @param target 指标
*/
private void checkTarget(Target target) {
CheckUtils.checkEmpty(target.getName(), "指标名称");
QueryWrapper<Target> query = new QueryWrapper<>();
query.eq("name", target.getName());
Target nameCheck = targetMapper.selectOne(query);
boolean bl = nameCheck != null && (target.getId() == null || !nameCheck.getId().equals(target.getId()));
ThrowUtils.throwIf(bl, ErrorCode.PARAMS_ERROR, "指标名称不能重复!");
CheckUtils.checkEmpty(String.valueOf(target.getType()), "类型");
CheckUtils.checkEmpty(String.valueOf(target.getIsKey()), "是否启用");
CheckUtils.checkEmpty(target.getOrganization(), "组织");
CheckUtils.checkEmpty(target.getTopic(), "主题");
CheckUtils.checkTableName(target.getTableName());
}
/**
* 拼接结果sql
*
@ -107,8 +288,8 @@ public class TargetServiceImpl extends ServiceImpl<TargetMapper, Target>
CheckUtils.checkSearchOption(searchList, tableName);
TargetOption result = params.getJSONObject("result").toJavaObject(TargetOption.class);
CheckUtils.checkResultOption(result, tableName);
return "SELECT ROUND(" + result.getFun() + "(CAST(" + result.getColumnName() + " AS DOUBLE)), 6) AS " +
result.getColumnName() + " FROM " + tableName + " WHERE " + getWhereSql(searchList);
return "SELECT ROUND(" + result.getFun() + "(CAST(" + result.getColumnName() + " AS DOUBLE)), 6) AS result " +
"FROM " + tableName + " WHERE " + getWhereSql(searchList);
}
/**
@ -122,66 +303,8 @@ public class TargetServiceImpl extends ServiceImpl<TargetMapper, Target>
for (TargetOption option : searchList) {
int type = option.getType();
if (type == 1) {
String start, end;
LocalDate day = LocalDate.now();
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
switch (option.getFun()) {
case "yesterday":
end = day.format(dtf);
start = day.minusDays(1).format(dtf);
break;
case "week":
end = day.format(dtf);
start = day.minusDays(1).with(DayOfWeek.MONDAY).format(dtf);
break;
case "lastWeek":
day = day.minusDays(1).with(DayOfWeek.MONDAY);
start = day.minusDays(7).format(dtf);
end = day.format(dtf);
break;
case "nearlyWeek":
end = day.format(dtf);
start = day.minusDays(7).format(dtf);
break;
case "month":
end = day.format(dtf);
start = day.minusDays(1).withDayOfMonth(1).format(dtf);
break;
case "lastMonth":
day = day.withDayOfMonth(1);
end = day.format(dtf);
start = day.minusMonths(1).format(dtf);
break;
case "nearlyMonth":
end = day.format(dtf);
start = day.minusDays(30).format(dtf);
break;
case "product":
end = day.format(dtf);
day = day.minusDays(1);
if (day.getDayOfMonth() < 26) {
start = day.minusMonths(1).withDayOfMonth(26).format(dtf);
} else {
start = day.withDayOfMonth(26).format(dtf);
}
break;
case "lastProduct":
day = day.minusDays(1);
if (day.getDayOfMonth() < 26) {
day = day.minusMonths(1).withDayOfMonth(26);
} else {
day = day.withDayOfMonth(26);
}
end = day.format(dtf);
start = day.minusMonths(1).format(dtf);
break;
default:
start = "";
end = "";
break;
}
sql.append(option.getColumnName()).append(" >= '").append(start).append("' and ")
.append(option.getColumnName()).append(" < '").append(end).append("' and ");
sql.append(option.getColumnName()).append(" >= {0} and ")
.append(option.getColumnName()).append(" < {1} and ");
} else if (type == 2) {
sql.append(getIsNullSql(option));
} else {

View File

@ -0,0 +1,337 @@
package iet.ustb.sf.service.impl;
import iet.ustb.sf.domain.Monitor;
import iet.ustb.sf.domain.Rule;
import iet.ustb.sf.domain.Target;
import iet.ustb.sf.domain.TargetData;
import iet.ustb.sf.exception.ErrorCode;
import iet.ustb.sf.exception.MyException;
import iet.ustb.sf.service.UtilService;
import org.springframework.stereotype.Service;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.UUID;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* UtilServiceImpl
*
* @author huangge1199
* @since 2025/8/7 15:11:27
*/
@Service
public class UtilServiceImpl implements UtilService {
@Override
public String[] getCurrentCycleDataByCycle(Date date, String cycle) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String xShow, showCycle, setDate, start, end;
end = sdf.format(calendar.getTime());
switch (cycle) {
case "yesterday":
calendar.add(Calendar.DATE, -1);
xShow = sdf.format(calendar.getTime());
showCycle = "day";
setDate = sdf.format(calendar.getTime());
start = sdf.format(calendar.getTime());
break;
case "nearlyWeek":
calendar.add(Calendar.DATE, -1);
xShow = sdf.format(calendar.getTime());
showCycle = "day";
setDate = sdf.format(calendar.getTime());
calendar.add(Calendar.DATE, -6);
start = sdf.format(calendar.getTime());
break;
case "nearlyMonth":
calendar.add(Calendar.DATE, -1);
xShow = sdf.format(calendar.getTime());
showCycle = "day";
setDate = sdf.format(calendar.getTime());
calendar.add(Calendar.DATE, -29);
start = sdf.format(calendar.getTime());
break;
case "week":
case "lastWeek":
if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY) {
calendar.add(Calendar.DATE, -7);
} else {
if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
calendar.add(Calendar.DATE, -7);
}
calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
if ("lastWeek".equals(cycle)) {
end = sdf.format(calendar.getTime());
calendar.add(Calendar.DATE, -7);
}
}
setDate = sdf.format(calendar.getTime());
start = sdf.format(calendar.getTime());
if (calendar.get(Calendar.WEEK_OF_YEAR) == 1) {
calendar.add(Calendar.YEAR, 1);
}
xShow = calendar.get(Calendar.YEAR) + "-" + String.format("%02d", calendar.get(Calendar.WEEK_OF_YEAR));
showCycle = "week";
break;
case "month":
case "lastMonth":
if (calendar.get(Calendar.DAY_OF_MONTH) == 1) {
calendar.add(Calendar.MONTH, -1);
xShow = new SimpleDateFormat("yyyy-MM").format(calendar.getTime());
setDate = sdf.format(calendar.getTime());
start = sdf.format(calendar.getTime());
} else {
calendar.set(Calendar.DAY_OF_MONTH, 1);
if ("lastMonth".equals(cycle)) {
end = sdf.format(calendar.getTime());
calendar.add(Calendar.MONTH, -1);
}
xShow = new SimpleDateFormat("yyyy-MM").format(calendar.getTime());
setDate = sdf.format(calendar.getTime());
start = sdf.format(calendar.getTime());
}
showCycle = "month";
break;
case "product":
if (calendar.get(Calendar.DAY_OF_MONTH) <= 26) {
calendar.set(Calendar.DAY_OF_MONTH, 26);
xShow = new SimpleDateFormat("yyyy-MM").format(calendar.getTime());
calendar.add(Calendar.MONTH, -1);
setDate = sdf.format(calendar.getTime());
start = sdf.format(calendar.getTime());
} else {
calendar.set(Calendar.DAY_OF_MONTH, 26);
setDate = sdf.format(calendar.getTime());
start = sdf.format(calendar.getTime());
calendar.add(Calendar.MONTH, 1);
xShow = new SimpleDateFormat("yyyy-MM").format(calendar.getTime());
}
showCycle = "product";
break;
case "lastProduct":
if (calendar.get(Calendar.DAY_OF_MONTH) < 26) {
calendar.add(Calendar.MONTH, -1);
}
calendar.set(Calendar.DAY_OF_MONTH, 26);
xShow = new SimpleDateFormat("yyyy-MM").format(calendar.getTime());
end = sdf.format(calendar.getTime());
calendar.add(Calendar.MONTH, -1);
setDate = sdf.format(calendar.getTime());
start = sdf.format(calendar.getTime());
showCycle = "product";
break;
default:
xShow = null;
showCycle = null;
setDate = null;
start = null;
end = null;
break;
}
return new String[]{xShow, showCycle, setDate, start, end};
}
@Override
public double getEvalResult(String expression) {
expression = replaceFunction(expression, "SUM", this::sum);
expression = replaceFunction(expression, "AVG", this::avg);
expression = replaceFunction(expression, "MIN", this::min);
expression = replaceFunction(expression, "MAX", this::max);
expression = replaceFunction(expression, "COUNT", this::count);
expression = replaceFunction(expression, "MEDIAN", this::median);
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("javascript");
double result;
try {
result = Double.parseDouble(engine.eval(expression).toString());
} catch (ScriptException e) {
throw new MyException(ErrorCode.SYSTEM_ERROR, "表达式错误");
}
return result;
}
@Override
public boolean isWarn(Rule rule, Target target, TargetData targetData) {
double targetVal = rule.getTarget();
double val = targetData.getVal();
double rate = rule.getRate();
switch (rule.getOp()) {
case ">":
if (val > targetVal + targetVal * rate) {
return true;
}
break;
case "<":
if (val < targetVal - targetVal * rate) {
return true;
}
break;
case ">=":
if (val >= targetVal + targetVal * rate) {
return true;
}
break;
case "<=":
if (val <= targetVal - targetVal * rate) {
return true;
}
break;
case "=":
if (val == targetVal * rate) {
return true;
}
break;
case "!=":
if (val != targetVal * rate) {
return true;
}
break;
case "between":
if (val > targetVal - targetVal * rate && val < targetVal + targetVal * rate) {
return true;
}
break;
}
return false;
}
@Override
public Monitor getInitMonitor(TargetData targetData, Target target, Rule rule) {
Date now = new Date();
return Monitor.builder()
.id(UUID.randomUUID().toString())
.targetId(targetData.getTargetId())
.ruleId(rule.getId())
.name(target.getName())
.type(target.getType())
.topic(target.getTopic())
.organization(target.getOrganization())
.level(target.getLevel())
.cycle(rule.getCycle())
.unit(target.getUnit())
.target(rule.getTarget())
.val(targetData.getVal())
.warnLevel(rule.getWarnLevel())
.setDate(targetData.getSetDate())
.xShow(targetData.getXShow())
.createTime(now)
.updateTime(now)
.warnType(rule.getType())
.build();
}
/**
* 处理函数方法
*
* @param expression 字符串表达式
* @param functionName 方法名
* @param function 计数方法的值
* @return 结果
*/
private String replaceFunction(String expression, String functionName, Function<double[], Double> function) {
Pattern pattern = Pattern.compile(functionName + "\\(([^)]+)\\)");
Matcher matcher = pattern.matcher(expression);
StringBuilder sb = new StringBuilder();
while (matcher.find()) {
String numbers = matcher.group(1);
double result = function.apply(parseNumbers(numbers));
matcher.appendReplacement(sb, String.valueOf(result));
}
matcher.appendTail(sb);
return sb.toString();
}
/**
* 将以逗号分割的数字字符串转为数值数组
*
* @param numbers 以逗号分割的数字字符串
* @return 结果
*/
private double[] parseNumbers(String numbers) {
return Arrays.stream(numbers.split(",")).mapToDouble(Double::parseDouble).toArray();
}
/**
* 求和
*
* @param numbers 数字集合
* @return 结果
*/
private double sum(double[] numbers) {
return Arrays.stream(numbers).sum();
}
/**
* 平均值
*
* @param numbers 数字集合
* @return 结果
*/
private double avg(double[] numbers) {
return sum(numbers) / numbers.length;
}
/**
* 最小值
*
* @param numbers 数字集合
* @return 结果
*/
private double min(double[] numbers) {
return Arrays.stream(numbers).min().orElse(Double.NaN);
}
/**
* 最大值
*
* @param numbers 数字集合
* @return 结果
*/
private double max(double[] numbers) {
return Arrays.stream(numbers).max().orElse(Double.NaN);
}
/**
* 计数
*
* @param numbers 数字集合
* @return 结果
*/
private double count(double[] numbers) {
return numbers.length;
}
/**
* 中位数
*
* @param numbers 数字集合
* @return 结果
*/
private double median(double[] numbers) {
Arrays.sort(numbers);
int length = numbers.length;
if (length % 2 == 0) {
return (numbers[length / 2 - 1] + numbers[length / 2]) / 2.0;
} else {
return numbers[length / 2];
}
}
}

View File

@ -8,6 +8,8 @@ import iet.ustb.sf.exception.ThrowUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@ -151,4 +153,17 @@ public class CheckUtils {
ThrowUtils.throwIf(!funList.contains(fun), ErrorCode.PARAMS_ERROR, "方法错误!");
checkColumns(option.getColumnName(), tableName);
}
/**
* 保留指定位小数
*
* @param value 传入值
* @param round 保留位数
* @return 结果值
*/
public static double roundToDecimalPlaces(Double value, int round) {
BigDecimal bd = new BigDecimal(value);
bd = bd.setScale(round, RoundingMode.HALF_UP);
return bd.doubleValue();
}
}