SpEl表达式使用示例
在 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。
代码示例
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 = 10StandardEvaluationContext 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 字符串:
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
:
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}
),可以用正则匹配替换:
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();
}
使用示例
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) |
完整示例
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);// 验证条件1System.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);}}
}
输出结果
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()需要按照完整示例的做修改):
// 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'"
此语法需要修改,这种写法需要使用如下代码(设置根对象),此方法验证是失败的,或许我写的不对。
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));
}