SpringBoot3中Spel Expression Parser无法识别application.properties中的公式
问题解决:SpEL表达式从application.properties读取后解析失败
核心问题:表达式语法错误
你遇到的SpelParseException: EL1041E: After parsing a valid expression, there is still more data in the expression: 'comma(,)'错误,根源是application.properties中的SpEL表达式存在括号不匹配的语法问题:
Math.max的第一个参数外层多了一个多余的右括号),导致第一个参数提前闭合- 表达式末尾还多了一个多余的右括号
)
这两个错误直接导致SpEL解析器认为逗号,是多余的无效内容,触发解析失败。
修正后的正确表达式
将application.properties中的formula.expression替换为以下正确语法的表达式:
formula.expression=T(java.lang.Math).max(1.0 / (T(java.time.temporal.ChronoUnit).DAYS.between(T(java.time.LocalDate).now(), loan.getDueDate().toLocalDate()) + 1), T(java.time.temporal.ChronoUnit).DAYS.between(loan.getDueDate().toLocalDate(), T(java.time.LocalDate).now()))
语法修正点说明:
- 移除了
1.0 / (...) +1外层多余的右括号,确保Math.max的第一个参数是完整的1.0 / (天数差 +1) - 移除了表达式末尾多余的右括号,保证整个表达式的括号完全匹配
额外优化建议
避免重复计算当前日期:
在convertExpression方法中,将LocalDate.now()存入EvaluationContext变量,避免表达式中重复调用,同时保证计算时的日期一致性:private double convertExpression(String expression, Loan loan) { System.out.println("dueDate"+loan.getDueDate()); try { System.out.println("exp"+expression); ExpressionParser parser = new SpelExpressionParser(); StandardEvaluationContext evaluationContext = new StandardEvaluationContext(); evaluationContext.setVariable("loan", loan); // 添加当前日期变量 evaluationContext.setVariable("currentDate", LocalDate.now()); Expression exp = parser.parseExpression(expression); System.out.println(exp+"jhasbufwqfi"); Double evaluatedValue = exp.getValue(evaluationContext, Double.class); System.out.println("evaluated"+evaluatedValue); return evaluatedValue; } catch (Exception e) { throw new IllegalArgumentException("Error evaluating expression: " + expression, e); } }对应的application.properties表达式可以简化为:
formula.expression=T(java.lang.Math).max(1.0 / (T(java.time.temporal.ChronoUnit).DAYS.between(currentDate, loan.getDueDate().toLocalDate()) + 1), T(java.time.temporal.ChronoUnit).DAYS.between(loan.getDueDate().toLocalDate(), currentDate))空值与异常防护:
可以在表达式中添加空值判断,避免loan.getDueDate()为null时抛出异常,例如使用?:运算符:formula.expression=T(java.lang.Math).max(1.0 / (T(java.time.temporal.ChronoUnit).DAYS.between(currentDate, loan.getDueDate()?.toLocalDate() ?: currentDate) + 1), T(java.time.temporal.ChronoUnit).DAYS.between(loan.getDueDate()?.toLocalDate() ?: currentDate, currentDate))当
loan.getDueDate()为null时,默认使用当前日期计算,避免空指针异常。
验证步骤
- 先在代码中硬编码修正后的表达式,调用
convertExpression方法测试,确认能正确计算结果 - 将修正后的表达式写入application.properties,重启服务测试调度任务是否正常运行
内容的提问来源于stack exchange,提问作者Karthik KK
相关产品推荐
相关产品推荐

