SpringBoot 引入 SPEL 模板字符串替换的两种方式

Spring 表达式语言 (SpEL)

官方文档:https://docs.spring.io/spring-framework/docs/6.0.x/reference/html/core.html#expressions

模板占位符 替换 {$name}

import org.springframework.context.expression.MapAccessor;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.PropertyPlaceholderHelper;

import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
/**
 * 内容占位符 替换
 * <p>
 * 模板占位符格式{$name}
 */
public class ContentHolderUtil {

    /**
     * 占位符前缀
     */
    private static final String PLACE_HOLDER_PREFIX = "{$";

    /**
     * 占位符后缀
     */
    private static final String PLACE_HOLDER_SUFFIX = "}";

    private static final StandardEvaluationContext EVALUATION_CONTEXT;

    private static final PropertyPlaceholderHelper PROPERTY_PLACEHOLDER_HELPER = new PropertyPlaceholderHelper(
            PLACE_HOLDER_PREFIX, PLACE_HOLDER_SUFFIX);

    static {
        EVALUATION_CONTEXT = new StandardEvaluationContext();
        EVALUATION_CONTEXT.addPropertyAccessor(new MapAccessor());
    }

    public static String replacePlaceHolder(final String template, final Map<String, String> paramMap) {
        String replacedPushContent = PROPERTY_PLACEHOLDER_HELPER.replacePlaceholders(template,
                new CustomPlaceholderResolver(template, paramMap));
        return replacedPushContent;
    }

    private static class CustomPlaceholderResolver implements PropertyPlaceholderHelper.PlaceholderResolver {
        private final String template;
        private final Map<String, String> paramMap;

        public CustomPlaceholderResolver(String template, Map<String, String> paramMap) {
            super();
            this.template = template;
            this.paramMap = paramMap;
        }

        @Override
        public String resolvePlaceholder(String placeholderName) {
            String value = paramMap.get(placeholderName);
            if (null == value) {
                String errorStr = MessageFormat.format("template:{0} require param:{1},but not exist! paramMap:{2}",
                        template, placeholderName, paramMap.toString());
                throw new IllegalArgumentException(errorStr);
            }
            return value;
        }
    }

    public static void main(String[] args) {
        Map<String,String> map = new HashMap<>();
        map.put("name","张三");
        map.put("age","12");
        // 注意:{$}内不能有空格
        final String s = replacePlaceHolder("我叫 {$name}, 我今年 {$age} 岁了。", map);
        System.out.println(s);
    }
}

common-text 方式:模板字符转替换 ${}

  1. 添加依赖

    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-text</artifactId>
        <version>1.10.0</version>
    </dependency>
    
    <!-- lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    
  2. 测试

    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.text.StringSubstitutor;
    import org.springframework.util.CollectionUtils;
    import org.springframework.util.StringUtils;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.stream.Collectors;
    
    @Slf4j
    public class CommonTextUtil {
        // 占位符前缀
        private static final String prefix = "${";
        // 占位符后缀
        private static final String suffix = "}";
    
        /*
         * commons-text
         * */
        public static String replaceVar(Map<String, Object> vars, String template) {
            if (!StringUtils.hasLength(template)) {
                log.info(String.format("调用%s方法失败,模板字符串替换失败,模板字符串不能为空",
                        Thread.currentThread().getStackTrace()[1].getMethodName()));
                return null;
            }
            if (CollectionUtils.isEmpty(vars)) {
                log.info(String.format("调用%s方法失败,模板字符串替换失败,map不能为空",
                        Thread.currentThread().getStackTrace()[1].getMethodName()));
                return null;
            }
            List<String> tempStrs = vars.keySet().stream().map(s -> prefix + s + suffix).
                    collect(Collectors.toList());
            tempStrs.forEach(t -> {
                if (!template.contains(t)) {
                    throw new RuntimeException(String.format("调用%s方法失败,模板字符串替换失败,map的key必须存在于模板字符串中",
                            Thread.currentThread().getStackTrace()[1].getMethodName()));
                }
            });
            StringSubstitutor stringSubstitutor = new StringSubstitutor(vars);
            return stringSubstitutor.replace(template);
        }
    
        public static void main(String[] args) {
            /*
             * 错误的场景:比如${变量},{}内不能含有空格等等
             * System.out.println(replaceVar(vals, "我叫${ name},今年${age }岁."));
             * System.out.println(replaceVar(new HashMap<>(), temp));
             * System.out.println(replaceVar(vals, "我叫张三"));
             * System.out.println(replaceVar(vals, "我叫${name},今年${age1}岁."));
             * */
            Map<String, Object> vals = new HashMap<>();
            vals.put("name", "张三");
            vals.put("age", "20");
            String temp = "我叫${name},今年${age}岁.";
            System.out.println(replaceVar(vals, temp));
        }
    }
    
### Spring Boot 中 `${}` 的用法及常见问题 #### 1. `${}` 的基本概念 `${}` 是一种占位符语法,在 Spring Boot 和其他基于 Spring 的框架中广泛用于属性替换。它的主要作用是从配置文件(如 `application.properties` 或 `application.yml`)或其他环境中读取变量值,并将其注入到代码或模板中[^4]。 #### 2. 基本使用示例 假设有一个名为 `application.properties` 的配置文件,其中定义了一个键值对: ```properties app.name=MyApp ``` 可以通过 `${}` 占位符在代码中访问该值: ```java import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component public class AppProperties { @Value("${app.name}") private String appName; public void displayAppName() { System.out.println("Application Name: " + appName); } } ``` 如果运行上述代码,则会打印出 `"Application Name: MyApp"`。 #### 3. 默认值设置 当某个属性可能不存在时,可以为其指定默认值。例如: ```properties server.port=${PORT:8080} ``` 在此例子中,如果没有环境变量 `PORT` 存在,则服务器端口将被设置为 `8080`。 #### 4. 动态表达式支持 Spring Boot 支持 SpELSpring Expression Language),允许在 `${}` 中嵌入复杂的逻辑运算。例如: ```properties app.enabled=${ENV_ENABLED:true} and true ``` 这里 `ENV_ENABLED` 可能是一个布尔类型的环境变量,默认值为 `true`。最终的结果取决于两个条件的逻辑与运算结果。 #### 5. 属性覆盖优先级 Spring Boot 提供了多种方式加载配置属性,不同来源之间的优先级如下(从高到低): - 命令行参数 - 系统环境变量 - JVM 系统属性 - 配置文件 (`application.properties`, `application.yml`) - 默认属性 (Default Properties) 这意味着如果同一个属性名存在于多个地方,较高优先级的源会覆盖较低优先级的值。 #### 6. 解决常见的问题 ##### (1)无法解析占位符 如果遇到类似 `Could not resolve placeholder 'xxx' in value "${xxx}"` 的错误提示,通常是因为缺少对应的配置项或者未正确引入依赖库。确保目标属性已正确定义于任何可用的配置资源中。 ##### (2)SpEL 表达式不生效 对于复杂表达式的处理失败情况,请确认是否启用了必要的上下文支持以及是否存在语法错误。另外注意区分单引号 `'` 和双引号 `"` 对字符串的影响。 --- ### 示例代码展示 下面给出一段完整的程序片段来演示如何利用 `${}` 实现灵活的功能定制化需求: ```java @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @Bean public CommandLineRunner commandLineRunner(@Value("${greeting.message}") String message, @Value("${server.port}") int port) { return args -> { System.out.println("Greeting Message: " + message); System.out.println("Server Port: " + port); }; } } // application.properties 文件内容 greeting.message=Hello from ${HOSTNAME:-Unknown Host} server.port=9090 ``` 在这个案例里,“${HOSTNAME:-Unknown Host}”尝试获取当前主机名称;假如找不到对应值则回退显示 “Unknown Host”。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

师小师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值