SpEl表达式使用示例

在 SpEL 中,如果你想动态计算 #walk_speed * 0.8 并生成 JSON 字符串 {"speedExec": 8.0}(假设 walk_speed = 10),你可以使用以下方法:


方法 1:直接解析 JSON 字符串中的 SpEL 表达式

如果你的 JSON 字符串是固定的(如 "{\"speedExec\": #walk_speed*0.8}"),你可以:

  1. 提取 SpEL 表达式#walk_speed*0.8)。
  2. 计算它的值10 * 0.8 = 8.0)。
  3. 替换回 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}),可以借助 JacksonGson

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));
}
相关推荐
独立开阀者_FwtCoder21 分钟前
狂收 33k+ star!全网精选的 MCP 一网打尽!!
java·前端·javascript
再路上121622 分钟前
direct_visual_lidar_calibration iridescence库问题
java·服务器·数据库
兔子蟹子1 小时前
Java 实现SpringContextUtils工具类,手动获取Bean
java·开发语言
jackson凌1 小时前
【Java学习方法】终止循环的关键字
java·笔记·学习方法
种时光的人1 小时前
Java多线程的暗号密码:5分钟掌握wait/notify
java·开发语言
我家领养了个白胖胖2 小时前
#和$符号使用场景 注意事项
java·后端·mybatis
Java中文社群2 小时前
大模型向量数据库去重的N种实现方案!
java·人工智能·后端
forestsea2 小时前
Maven 依赖坐标与BOM统一管理
java·maven
论迹2 小时前
【JavaEE】-- MyBatis操作数据库(1)
java·开发语言·数据库·java-ee·mybatis