增加PB计算公式转JAVA计算表达式工具类CalcUtils,以及入参转换方法

This commit is contained in:
tangw 2025-08-12 18:18:24 +08:00
parent 17e75c4c52
commit a55aef8b48
6 changed files with 346 additions and 23 deletions

View File

@ -15,7 +15,7 @@ public class ComOptionUtils {
* 设置字典缓存
*
* @param key 参数键
* @param dictDatas 字典数据列表
* @param optDatas 字典数据列表
*/
public static void setOptCache(String key, List<ComOpt> optDatas) {
//先清除该key的所有缓存,然后再重新设置该key的缓存

View File

@ -0,0 +1,236 @@
package com.czlis.interfaceCommon.utils;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CalcUtils {
/**
* 工具类,计算公式计算,使用PB的计算公式加入参得出结果值
* @param CalcExpression PB原始计算公式
* @param variableMap 入参MAP
* @return
*/
public static String getValueFromCalc(String CalcExpression,Map<String,String> variableMap){
// 创建SpEL解析器
ExpressionParser parser = new SpelExpressionParser();
// 创建评估上下文
StandardEvaluationContext context = new StandardEvaluationContext();
// 循环遍历Map,将键值对添加到上下文
for (Map.Entry<String, String> entry : variableMap.entrySet()) {
// 键作为变量名,值作为变量值
String str = entry.getValue();
if(isNumber(str)){
context.setVariable(entry.getKey(), Double.parseDouble(str));
}else {
context.setVariable(entry.getKey(), entry.getValue());
}
}
// 测试表达式:使用多个变量进行判断"#score >= 60 ? #name + '的' + #subject + '成绩及格' : #name + '的' + #subject + '成绩不及格'"
String expression = getCalc(CalcExpression);
Expression exp = parser.parseExpression(expression);
// 执行表达式(传入上下文)
try {
String result = exp.getValue(context, String.class);
//System.out.println(result); // 输出:张三的数学成绩及格
return result;
} catch (Exception e) {
// 意外错误时返回null
return null;
}
}
public static boolean getBooleanFromCalc(String CalcExpression,Map<String,String> variableMap){
ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
for (Map.Entry<String, String> entry : variableMap.entrySet()) {
context.setVariable(entry.getKey(), entry.getValue());
}
String expression = getCalc(CalcExpression);
Expression exp = parser.parseExpression(expression);
boolean result = exp.getValue(context, Boolean.class);
return result;
}
/**
* 此方法把PB的计算公式转换为SpEL表达式
* @param CalcExpression
* @return
*/
public static String getCalc(String CalcExpression){
// 1. 替换逻辑运算符:and→&&,or→||
String processed = CalcExpression.replaceAll("\\band\\b", "&&").replaceAll("\\bor\\b", "||");
processed = processed.replaceAll("\\bAND\\b", "&&").replaceAll("\\bOR\\b", "||");
// 2. 替换变量格式:[a] → #a
processed = processed.replaceAll("\\[(\\w+)\\]", "#$1");
// 3. 替换len()函数为length()方法:len(xxx) → xxx.length()
processed = replaceLenFunction(processed);
//5.case表达式暂时不处理,后期看需要扩展
//4. 递归处理if结构:if(cond, trueExpr, falseExpr) → cond?trueExpr:falseExpr
return processIf(processed);
}
/**
* 递归解析并替换if表达式
*/
private static String processIf(String expr) {
int start = expr.indexOf("if(");
if (start == -1) {
return expr;
}
int end = findIfEnd(expr, start);
if (end == -1) {
return expr;
}
String inner = expr.substring(start + 3, end);
String[] parts = splitIfParts(inner);
if (parts.length != 3) {
return expr;
}
String condition = parts[0].trim();
String trueExpr = parts[1].trim();
String falseExpr = parts[2].trim();
// 递归处理分支,确保嵌套表达式被正确包裹
String processedTrue = processIf(trueExpr);
String processedFalse = processIf(falseExpr);
// 关键修复:为分支表达式添加括号,尤其是嵌套情况
// 判断分支是否包含三元运算符,如果是则添加括号
String wrappedTrue = needsParentheses(processedTrue) ? "(" + processedTrue + ")" : processedTrue;
String wrappedFalse = needsParentheses(processedFalse) ? "(" + processedFalse + ")" : processedFalse;
// 拼接三元表达式
String ternary = condition + "?" + wrappedTrue + ":" + wrappedFalse;
String before = expr.substring(0, start);
String after = expr.substring(end + 1);
return processIf(before + ternary + after);
}
// 判断表达式是否需要添加括号(包含三元运算符时)
private static boolean needsParentheses(String expr) {
// 统计三元运算符的数量,排除括号内的情况
int colonCount = 0;
int questionCount = 0;
Stack<Character> stack = new Stack<>();
for (char c : expr.toCharArray()) {
if (c == '(') {
stack.push('(');
} else if (c == ')') {
if (!stack.isEmpty()) stack.pop();
} else if (stack.isEmpty()) {
if (c == '?') questionCount++;
if (c == ':') colonCount++;
}
}
// 存在完整的三元运算符(?和:数量相等且至少一个)
return questionCount > 0 && colonCount > 0 && questionCount == colonCount;
}
private static int findIfEnd(String expr, int start) {
Stack<Character> stack = new Stack<>();
stack.push('(');
int pos = start + 3;
while (pos < expr.length()) {
char c = expr.charAt(pos);
if (c == '(') {
stack.push('(');
} else if (c == ')') {
stack.pop();
if (stack.isEmpty()) {
return pos;
}
}
pos++;
}
return -1;
}
private static String[] splitIfParts(String inner) {
Stack<Character> stack = new Stack<>();
int partIndex = 0;
StringBuilder[] parts = new StringBuilder[3];
for (int i = 0; i < 3; i++) {
parts[i] = new StringBuilder();
}
for (char c : inner.toCharArray()) {
if (c == ',' && stack.isEmpty()) {
partIndex++;
if (partIndex >= 3) {
break;
}
} else {
if (c == '(') {
stack.push('(');
} else if (c == ')') {
if (!stack.isEmpty()) {
stack.pop();
}
}
parts[partIndex].append(c);
}
}
return new String[]{
parts[0].toString(),
parts[1].toString(),
parts[2].toString()
};
}
/**
* 替换len(表达式)为表达式.length()
* 支持处理嵌套的len函数,如len(len(#a))
*/
private static String replaceLenFunction(String expr) {
// 正则匹配len(...)结构,处理括号嵌套
Pattern pattern = Pattern.compile("len\\(([^()]+|\\([^()]*\\))*\\)");
Matcher matcher = pattern.matcher(expr);
StringBuffer result = new StringBuffer();
while (matcher.find()) {
String match = matcher.group();
// 提取括号内的内容(去掉len(和最后的))
String inner = match.substring(4, match.length() - 1);
// 递归处理嵌套的len函数
String processedInner = replaceLenFunction(inner);
// 替换为xxx.length()
matcher.appendReplacement(result, processedInner + ".length()");
}
matcher.appendTail(result);
return result.toString();
}
/**
* 使用正则表达式判断字符串是否为数字
* 支持:整数(123)、小数(123.45)、正负号(-123、+45.6)
*/
public static boolean isNumber(String str) {
if (str == null || str.trim().isEmpty()) {
return false;
}
// 正则表达式:匹配正负整数、正负小数
String regex = "^[+-]?([0-9]+(\\.[0-9]*)?|\\.[0-9]+)$";
return str.matches(regex);
}
// 测试
public static void main(String[] args) {
Map<String, String> variables = new HashMap<>();
variables.put("ALB", "4.0"); // 示例值
// variables.put("TP", "6.0");
String testCalc = "[ALB] /( [TP] - [ALB] )";
//System.out.println(getCalc(testCalc));
System.out.println(getValueFromCalc(testCalc,variables));
}
}

View File

@ -1,14 +1,17 @@
package com.czlis.liswork.mapper;
import com.czlis.liswork.pojo.DTO.ResultCalcDTO;
import org.apache.ibatis.annotations.Param;
import java.util.Date;
import java.util.List;
import java.util.Map;
public interface LisWorkOperMapper {
Long checkReqClass(@Param("sqh") String sqh,@Param("yq") String yq);
String selectsqxmdh(String sqh);
String selectyqdl(String yq);
String selectSqxmdh(String sqh);
String selectYqdl(String yq);
void sp_setrefs(Map<String,Object> map);
void updatelabresultsqxmdhall(@Param("jyrq") Date jyrq,@Param("yq") String yq,@Param("ybh") String ybh,@Param("sqxmdh") String sqxmdh);
void updatelabresultsqxmdh(@Param("jyrq") Date jyrq,@Param("yq") String yq,@Param("ybh") String ybh,@Param("sqh") String sqh);
List<ResultCalcDTO> getResultCalc(@Param("jyrq") Date jyrq, @Param("yq") String yq, @Param("ybh") String ybh);
}

View File

@ -0,0 +1,16 @@
package com.czlis.liswork.pojo.DTO;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ResultCalcDTO {
private String jsxm;
private String xmdh;
private String csjg;
private String jsgs;
}

View File

@ -11,19 +11,18 @@ import com.czlis.interfaceCommon.mapper.LabReqmainMapper;
import com.czlis.interfaceCommon.pojo.inter.DayMessage;
import com.czlis.interfaceCommon.pojo.inter.GetReqInterface;
import com.czlis.interfaceCommon.pojo.inter.SetReqStatus;
import com.czlis.interfaceCommon.utils.AgeUtils;
import com.czlis.interfaceCommon.utils.CommonUtil;
import com.czlis.interfaceCommon.utils.LisInterfaceUtil;
import com.czlis.interfaceCommon.utils.LisUtil;
import com.czlis.interfaceCommon.utils.*;
import com.czlis.liswork.mapper.LisWorkOperMapper;
import com.czlis.liswork.mapper.dict.LabInstrvsreqclassMapper;
import com.czlis.liswork.pojo.DTO.ResultCalcDTO;
import com.czlis.liswork.service.LisWorkOperService;
import com.czlis.liswork.utils.LisWorkUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import java.util.*;
import java.util.stream.Collectors;
@ -265,7 +264,10 @@ public class LisWorkOperServiceImpl implements LisWorkOperService {
}
}
String yqdl=lisWorkOperMapper.selectyqdl(yq);
LabPat labPat=commonUtil.getLabPatOne(jyrq, yq, ybh);
//计算项目更新
calcsample(jyrq, yq, ybh, labPat);
String yqdl=lisWorkOperMapper.selectYqdl(yq);
if(!"细菌仪".equals(yqdl)) {
Map<String, Object> map = new HashMap<>();
map.put("jyrq", jyrq);
@ -278,10 +280,14 @@ public class LisWorkOperServiceImpl implements LisWorkOperService {
String retCode = String.valueOf(map.get("retcode"));
String retMsg = String.valueOf(map.get("retmsg"));
log.info("调用存储过程{}返回值:{},{}", "sp_setrefs", retCode, retMsg);
if (retCode == null || "".equals(retCode) || "-1".equals(retCode))
return new Result("-1", "保存常规参考值失败!");
if (retCode == null || "".equals(retCode) || "-1".equals(retCode)) return new Result("-1", "保存常规参考值失败!");
int wjz=saverefs(jyrq, yq, ybh, labPat);
if(wjz==1){
//危急值处理过程
}
setItemSqxmdh(jyrq, yq, ybh);
}
String sqh=labPat.getSqh();
setItemSqxmdh(jyrq, yq, ybh,sqh);
return new Result("0","保存成功!");
}
@ -293,25 +299,78 @@ public class LisWorkOperServiceImpl implements LisWorkOperService {
*/
public void setItemSqxmdh(Date jyrq, String yq, String ybh){
String sqh=commonUtil.getSqhByKey(jyrq,yq,ybh);
if (sqh==null || "".equals(sqh)) {}else{
setItemSqxmdh(jyrq, yq, ybh,sqh);
}
}
//内部使用
private void setItemSqxmdh(Date jyrq, String yq, String ybh, String sqh){
if (sqh==null || "".equals(sqh)) {}else{
int sl=labReqdetailMapper.getCountByKey(sqh);
if(sl==1){
String sqxmdh=lisWorkOperMapper.selectsqxmdh(sqh);
String sqxmdh=lisWorkOperMapper.selectSqxmdh(sqh);
lisWorkOperMapper.updatelabresultsqxmdhall(jyrq,yq,ybh,sqxmdh);
}else{
lisWorkOperMapper.updatelabresultsqxmdh(jyrq,yq,ybh,sqh);
}
}
}
/**
* 计算项目增加及重新计算
* @param jyrq
* @param yq
* @param ybh
*/
public void calcsample(Date jyrq, String yq, String ybh){
public Result calcsample(Date jyrq, String yq, String ybh){
LabPat labPat=commonUtil.getLabPatOne(jyrq, yq, ybh);
calcsample(jyrq, yq, ybh, labPat);
return new Result("0","保存成功!");
}
//内部使用
private void calcsample(Date jyrq, String yq, String ybh,LabPat labPat){
List<ResultCalcDTO> resultCalcDTO=lisWorkOperMapper.getResultCalc(jyrq,yq,ybh);
String xmdhold="";
for (ResultCalcDTO resultCalc : resultCalcDTO) {
String jsgs=resultCalc.getJsgs();
String xmdh= resultCalc.getJsxm();
if(!xmdhold.equals(xmdh)) {
xmdhold = xmdh;
String sex=labPat.getBrxb().trim();
if( "1".equals(sex))sex="男";
if( "2".equals(sex))sex="女";
double age = AgeUtils.getDecimalAge(AgeUtils.getBirthDateByAge(labPat.getNl(), labPat.getNldw()));
Map<String, String> variables = new HashMap<>();
variables.put("SEX", sex); // 示例值
variables.put("AGE", String.valueOf(age));
String result=CalcUtils.getValueFromCalc(jsgs,variables);
if (result != null && !result.trim().isEmpty()) {
//插入结果值
}
}
}
}
/**
* 计算项目参考值结果异常标志
* @param jyrq
* @param yq
* @param ybh
*/
public Result saverefs(Date jyrq, String yq, String ybh){
LabPat labPat=commonUtil.getLabPatOne(jyrq, yq, ybh);
saverefs(jyrq, yq, ybh, labPat);
return new Result("0","保存成功!");
}
/**
* 计算项目参考值结果异常标志(内部使用)
* @param jyrq
* @param yq
* @param ybh
* @param labPat
* @return 返回值0正常,1有危急值明细存在
*/
private int saverefs(Date jyrq, String yq, String ybh,LabPat labPat){
return 0;
}

View File

@ -8,10 +8,10 @@
where lab_reqdetail.sqxmdh=xm_feeinstr.sfxmdh
and lab_reqdetail.sqh=#{sqh} and xm_feeinstr.yq=#{yq};
</select>
<select id="selectsqxmdh" resultType="String">
<select id="selectSqxmdh" resultType="String">
select sqxmdh from lab_reqdetail where lab_reqdetail.sqh=#{sqh}
</select>
<select id="selectyqdl" resultType="String">
<select id="selectYqdl" resultType="String">
select yqdl from lab_instr where lab_instr.yq=#{yq}
</select>
<update id="updatelabresultsqxmdhall">
@ -31,4 +31,13 @@
#{retcode,mode=OUT,jdbcType=INTEGER})
}
</select>
<select id="getResultCalc" resultType="com.czlis.liswork.pojo.DTO.ResultCalcDTO">
SELECT DISTINCT xm_calc.jsxm ,lab_result.xmdh ,lab_result.csjg ,xm_calc.jsgs
FROM lab_result ,xm_calc WHERE ( lab_result.yq = xm_calc.yq ) and
( lab_result.xmdh = xm_calc.xmdh ) and
( ( lab_result.jyrq = #{jyrq} ) And
( lab_result.yq =#{yq}) And
( lab_result.ybh = #{ybh}) )
</select>
</mapper>