在 SpEL 中,如果你想动态计算 #walk_speed * 0.8
并生成 JSON 字符串 {"speedExec": 8.0}
(假设 walk_speed = 10
),你可以使用以下方法:
方法 1:直接解析 JSON 字符串中的 SpEL 表达式
如果你的 JSON 字符串是固定的(如 "{\"speedExec\": #walk_speed*0.8}"
),你可以:
- 提取 SpEL 表达式 (
#walk_speed*0.8
)。 - 计算它的值 (
10 * 0.8 = 8.0
)。 - 替换回 JSON。
代码示例
java
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;
public class SpELJsonExample {
private static final ExpressionParser spelParser = new SpelExpressionParser();
public static void main(String[] args) {
Map<String, Object> variables = new HashMap<>();
variables.put("walk_speed", 10); // 假设 walk_speed = 10
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariables(variables);
String jsonTemplate = "{\"speedExec\": #walk_speed*0.8}";
// 提取 SpEL 表达式(#walk_speed*0.8)
String spelExpression = jsonTemplate.substring(
jsonTemplate.indexOf("#"),
jsonTemplate.indexOf("}") - 1
);
// 计算 SpEL 表达式的值
Expression exp = spelParser.parseExpression(spelExpression);
Double result = exp.getValue(context, Double.class);
// 替换 JSON 中的 SpEL 表达式为计算结果
String finalJson = jsonTemplate.replace(spelExpression, result.toString());
System.out.println(finalJson); // 输出: {"speedExec": 8.0}
}
}
输出
{"speedExec": 8.0}
方法 2:使用 SpEL 直接构造 JSON(推荐)
如果 JSON 结构较简单,可以直接用 SpEL 构造整个 JSON 字符串:
java
String spelJson = "{'speedExec': #walk_speed * 0.8}"; // 注意:SpEL 允许单引号
Expression exp = spelParser.parseExpression(spelJson);
Map<String, Object> result = exp.getValue(context, Map.class);
System.out.println(result); // 输出: {speedExec=8.0}
转换为标准 JSON 字符串
如果你想输出标准的 JSON 格式(如 {"speedExec": 8.0}
),可以借助 Jackson
或 Gson
:
java
import com.fasterxml.jackson.databind.ObjectMapper;
ObjectMapper mapper = new ObjectMapper();
String jsonOutput = mapper.writeValueAsString(result);
System.out.println(jsonOutput); // 输出: {"speedExec":8.0}
方法 3:动态替换 JSON 中的多个 SpEL 表达式
如果 JSON 中有多个 SpEL 表达式(如 {"a": #x, "b": #y+1}
),可以用正则匹配替换:
java
import java.util.regex.*;
private static String evaluateJson(String json, StandardEvaluationContext context) {
Pattern pattern = Pattern.compile("#([^\\s\"'}]+)");
Matcher matcher = pattern.matcher(json);
StringBuffer output = new StringBuffer();
while (matcher.find()) {
String expr = matcher.group(); // 如 "#walk_speed*0.8"
Object value = spelParser.parseExpression(expr).getValue(context);
matcher.appendReplacement(output, value.toString());
}
matcher.appendTail(output);
return output.toString();
}
使用示例
java
String json = "{\"speedExec\": #walk_speed*0.8, \"threshold\": #walk_speed/2}";
String result = evaluateJson(json, context);
System.out.println(result); // 输出: {"speedExec": 8.0, "threshold": 5.0}
总结
场景 | 推荐方法 |
---|---|
固定 JSON 结构 | 直接提取 SpEL 计算后替换(方法 1) |
动态构造 JSON | 用 SpEL 生成 Map 再转 JSON(方法 2) |
复杂 JSON 含多个 SpEL | 正则匹配替换(方法 3) |
完整示例
c
import com.alibaba.fastjson.JSONObject;
import com.hsrg.utils.utils.HsrgUtil;
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.Calendar;
import java.util.HashMap;
import java.util.Map;
public class SpELTest {
private static final ExpressionParser spelParser = new SpelExpressionParser();
public static void main(String[] args) {
Map report = new HashMap();
report.put("walk_distance",350); // 测试值在300-450之间
report.put("walk_speed",10);
report.put("id","id替换");
Calendar calendar = Calendar.getInstance();
String startTime = HsrgUtil.formatDateToStr(calendar.getTime());
report.put("startTime",startTime);
calendar.add(Calendar.DATE,7);
String endTime = HsrgUtil.formatDateToStr(calendar.getTime());
report.put("endTime",endTime);
report.put("patientId","patientId替换");
report.put("personId","personId替换");
report.put("org_root_name","org_root_name替换");
String json = "{\"speedExec\": #walk_speed*0.8}";
StandardEvaluationContext evalContext = new StandardEvaluationContext();
evalContext.setVariables(report);
// 验证条件1
System.out.println(evaluateCondition("#walk_distance < 450 && #walk_distance >= 300", evalContext));
String spelJson = "{\n" +
"\t\"businessId\": #id,\n" +
"\t\"endTime\": #end_time,\n" +
"\t\"extendParam\": {\n" +
"\t\t\"speedExec\": #walk_speed*0.8,\n" +
"\t\t\"targetRr\": 0,\n" +
"\t\t\"thrHight\": 0,\n" +
"\t\t\"thrLow\": 0,\n" +
"\t\t\"thrType\": 5,\n" +
"\t\t\"timeExec\": 20,\n" +
"\t\t\"timeReady\": 5,\n" +
"\t\t\"timeRecovery\": 5,\n" +
"\t\t\"trainingMode\": \"speedMode\",\n" +
"\t\t\"vegetable\": 0.0\n" +
"\t},\n" +
"\t\"frequency\": 3.0,\n" +
"\t\"frequencyUnit\": \"周\",\n" +
"\t\"item\": \"hurry\",\n" +
"\t\"itemName\": \"快走\",\n" +
"\t\"orgId\": #orgId,\n" +
"\t\"parentItem\": \"aerobics\",\n" +
"\t\"parentItemName\": \"有氧运动\",\n" +
"\t\"patientId\": #patientId,\n" +
"\t\"personId\": #personId,\n" +
"\t\"recipelCycle\": 1.0,\n" +
"\t\"recording\": 0,\n" +
"\t\"rootOrgId\": #org_root_name,\n" +
"\t\"source\": \"recipel\",\n" +
"\t\"startTime\": #start_time,\n" +
"\t\"status\": \"create\",\n" +
"\t\"times\": 3\n" +
"}"; // 注意:SpEL 允许单引号
Expression exp = spelParser.parseExpression(spelJson);
Map<String, Object> result = exp.getValue(evalContext, Map.class);
System.out.println(JSONObject.toJSONString(result)); // 输出: {speedExec=8.0}
}
private static boolean evaluateCondition(String condition, StandardEvaluationContext context) {
try {
Expression exp = spelParser.parseExpression(condition);
Boolean result = exp.getValue(context, Boolean.class);
return result != null && result;
} catch (Exception e) {
throw new RuntimeException("SpEL evaluation failed for condition: " + condition, e);
}
}
}
输出结果
c
true
{"businessId":"id替换","extendParam":{"speedExec":8.0,"targetRr":0,"thrHight":0,"thrLow":0,"thrType":5,"timeExec":20,"timeReady":5,"timeRecovery":5,"trainingMode":"speedMode","vegetable":0.0},"frequency":3.0,"frequencyUnit":"周","item":"hurry","itemName":"快走","orgId":"#orgId","parentItem":"aerobics","parentItemName":"有氧运动","patientId":"patientId替换","personId":"personId替换","recipelCycle":1.0,"recording":0,"rootOrgId":"org_root_name替换","source":"recipel","status":"create","times":3}
SpEL表达式高级用法示例
SpEL支持丰富的表达式语法(以下写法仅支持设置根对象,如果是setVariables()需要按照完整示例的做修改):
c
// 1. 基本运算
"walkDistance * walkSpeed > 1000"
// 2. 正则匹配
"orgId matches 'org\\d+'"
// 3. 集合操作
"someList.?[#this > 10]"
// 4. 安全导航
"someObject?.someProperty"
// 5. 调用方法
"T(java.lang.Math).random() * 100.0"
// 6. 复杂条件组合
"(walkDistance < 300 && walkSpeed > 4) || orgId == 'special'"
此语法需要修改,这种写法需要使用如下代码(设置根对象),此方法验证是失败的,或许我写的不对。
c
public static void main(String[] args) {
Map report = new HashMap();
report.put("walk_distance", 350);
StandardEvaluationContext evalContext = new StandardEvaluationContext(report); // 设置根对象
// 现在可以直接使用属性名访问
System.out.println(evaluateCondition("walk_distance < 450 && walk_distance >= 300", evalContext));
}