Java-自定义占位符替换工具类

技术重点

  • MessageFormat:提供了一种以语言中立的方式产生串联消息的方法。使用它可以构造为最终用户显示的消息。
  • Matcher:Matcher解析器,根据Pattern正则表达式,对字符序列执行匹配操作。

实现代码

maven依赖

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.12.0</version>
</dependency>

工具类

package com.tangsm.util;

import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 自定义占位符替换工具类
 *
 * @author tangyb
 */
public class PlaceholderUtils {

    /**
     * 占位符正则表达式:$+花括号
     * <p>占位符示例:{@code ${xxx}}</p>
     */
    public static final Pattern PATTERN_BRACE = Pattern.compile("\\$\\{(.*?)}");

    /**
     * 占位符正则表达式:$+尖括号
     * <p>占位符示例:{@code $<xxx>}</p>
     */
    public static final Pattern PATTERN_ANGLE = Pattern.compile("\\$<(.*?)>");

    /**
     * 匹配器
     */
    private static Matcher matcher;

    /**
     * 替换字符串占位符,可变参数,字符串中使用{0}{1}...{*}顺序下标,表示占位符
     *
     * @param source 需要匹配的字符串,示例:"名字:{0},年龄:{1},学校:{2}"
     * @param params 可变参数,动态参数
     * @return 替换后的字符串
     */
    public static String replaceWithVarargs(String source, Object... params) {
        return MessageFormat.format(source, params);
    }

    /**
     * 替换字符串占位符,Map传参,字符串中使用${key}表示占位符
     *
     * @param source 需要匹配的字符串,示例:"名字:${name},年龄:${age},学校:${school}"
     * @param params 参数集,Map类型
     * @return 替换后的字符串
     */
    public static String replaceWithMap(String source, Map<String, Object> params) {
        if (StringUtils.isBlank(source) || CollectionUtils.isEmpty(params)) {
            return source;
        }
        String targetString = source;
        matcher = PATTERN_BRACE.matcher(source);
        while (matcher.find()) {
            try {
                String key = matcher.group();
                //如果占位符是{} 这里就是key.substring(1, key.length() - 1).trim()
                String keyClone = key.substring(2, key.length() - 1).trim();
                Object value = params.get(keyClone);
                if (value != null) {
                    targetString = targetString.replace(key, value.toString());
                }
            } catch (Exception e) {
                throw new RuntimeException("字符串格式化程序失败", e);
            }
        }
        return targetString;
    }

    /**
     * 替换字符串占位符,POJO传参,字符串中使用${key}表示占位符
     *
     * <p>注:利用反射,自动获取对象属性值 (必须有get方法) </p>
     *
     * @param source 需要匹配的字符串
     * @param params 参数实体
     * @return 替换后的字符串
     */
    public static String replaceWithObject(String source, Object params) {
        if (StringUtils.isBlank(source) || ObjectUtils.isEmpty(params)) {
            return source;
        }

        String targetString = source;

        PropertyDescriptor pd;
        Method getMethod;

        // 匹配${}中间的内容 包括括号
        matcher = PATTERN_BRACE.matcher(source);
        while (matcher.find()) {
            String key = matcher.group();
            String holderName = key.substring(2, key.length() - 1).trim();
            try {
                pd = new PropertyDescriptor(holderName, params.getClass());
                // 获得get方法
                getMethod = pd.getReadMethod();
                Object value = getMethod.invoke(params);
                if (value != null) {
                    targetString = targetString.replace(key, value.toString());
                }
            } catch (Exception e) {
                throw new RuntimeException("字符串格式化程序失败", e);
            }
        }
        return targetString;
    }

    /**
     * 获取String中的占位符keys
     * <p>示例:名字:${name},年龄:${age},学校:${school},返回:Set[name,age,school]</p>
     *
     * @param source  源字符串
     * @param pattern 正则表达式,pattern示例:<pre> {@code
     *                // 尖括号:<placeHolder> 表示为占位符
     *                Pattern pattern = Pattern.compile("\\$<(.*?)>");
     *
     *                // 大括号:{placeHolder} 表示为占位符, 上面的示例中就使用{}作为占位符
     *                Pattern pattern = Pattern.compile("\\$\\{(.*?)}");
     *                } </pre>
     * @return Set集合
     */
    public static Set<String> getPlaceholderKeys(String source, Pattern pattern) {
        Set<String> placeHolderSet = new HashSet<>();

        // 参数有误返回空集合
        if (StringUtils.isBlank(source) || ObjectUtils.isEmpty(pattern)) {
            return placeHolderSet;
        }

        // 根据正则表达式初始匹配器
        matcher = pattern.matcher(source);
        while (matcher.find()) {
            //示例: {name}
            String key = matcher.group();
            //示例: name
            String placeHolder = key.substring(2, key.length() - 1).trim();
            placeHolderSet.add(placeHolder);
        }

        return placeHolderSet;
    }
}

实体

package com.tangsm.domain;

/**
 * 用户信息
 *
 * @author tangsm
 */
public class UserInfo {
    /**
     * 姓名
     */
    private String name;

    /**
     * 年龄
     */
    private Integer age;

    /**
     * 学校
     */
    private String school;

    /**
     * 无参构造
     */
    public UserInfo() {
    }

    /**
     * 全参构造
     *
     * @param name   名称
     * @param age    年龄
     * @param school 学校
     */
    public UserInfo(String name, Integer age, String school) {
        this.name = name;
        this.age = age;
        this.school = school;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getSchool() {
        return school;
    }

    public void setSchool(String school) {
        this.school = school;
    }
}

测试类

package com.tangsm.util;

import com.tangsm.domain.UserInfo;
import com.tangsm.util.PlaceholderUtils;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;

/**
 * 自定义占位符替换工具类测试类
 *
 * @author tangsm
 */
public class PlaceholderUtilsTest {
    private final Logger log = LoggerFactory.getLogger(PlaceholderUtilsTest.class);

    private static final String SOURCE0 = "名字:{0},年龄:{1},学校:{2}";
    private static final String SOURCE1 = "名字:${name},年龄:${age},学校:${school}";
    private static final String SOURCE2 = "名字:$<name>,年龄:$<age>,学校:$<school>";

    /**
     * 替换字符串占位符,动态参数,字符串中使用{0}{1}...{*}顺序下标,表示占位符,测试方法
     */
    @Test
    void replaceWithVarargs() {
        log.info("replaceWithVarargs,处理结果:{}", PlaceholderUtils.replaceWithVarargs(SOURCE0, "小美", 18, "女高一中"));
    }

    /**
     * 替换字符串占位符,Map传参,字符串中使用${key}表示占位符,测试方法
     */
    @Test
    void replaceWithMap() {
        HashMap<String, Object> params = new HashMap<>();
        params.put("name", "小美");
        params.put("age", 18);
        params.put("school", "女高一中");
        log.info("replaceWithMap,处理结果:{}", PlaceholderUtils.replaceWithMap(SOURCE1, params));
    }

    /**
     * 替换字符串占位符,POJO传参,字符串中使用${key}表示占位符,测试方法
     */
    @Test
    void replaceWithObject() {
        UserInfo userInfo = new UserInfo("小美", 18, "女高一中");
        log.info("replaceWithObject,处理结果:{}", PlaceholderUtils.replaceWithObject(SOURCE1, userInfo));
    }

    /**
     * 获取String中的占位符keys
     */
    @Test
    void getPlaceholderKeys() {
        log.info("getPlaceholderKeys-PATTERN_BRACE,处理结果:{}", PlaceholderUtils.getPlaceholderKeys(SOURCE1, PlaceholderUtils.PATTERN_BRACE));
        log.info("getPlaceholderKeys-PATTERN_ANGLE,处理结果:{}", PlaceholderUtils.getPlaceholderKeys(SOURCE2, PlaceholderUtils.PATTERN_ANGLE));
    }
}

测试结果

PlaceholderUtilsTest - replaceWithObject,处理结果:名字:小美,年龄:18,学校:女高一中
PlaceholderUtilsTest - getPlaceholderKeys-PATTERN_BRACE,处理结果:[school, name, age]
PlaceholderUtilsTest - getPlaceholderKeys-PATTERN_ANGLE,处理结果:[school, name, age]
PlaceholderUtilsTest - replaceWithVarargs,处理结果:名字:小美,年龄:18,学校:女高一中
PlaceholderUtilsTest - replaceWithMap,处理结果:名字:小美,年龄:18,学校:女高一中

参考

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值