Java中消息模板占位符使用与详解

在开发的过程中,可能遇到替换字符串的占位符的场景,如:消息系统中,消息模板的配置;日志系统中日志打印等场景中都会使用到占位符替换。在一些已经成熟的框架中也经常见到占位符替换的例子,如:log4j中的日志打印,Mybatis的sql预编译参数设置等。

那么我们在自研系统的时候,遇到以上提到的场景时,我们该如何去开发呢,接下来我将用两个示例介绍一下。

消息模板

在消息相关的系统开发过程中,我们通常会对用户提供消息模板的配置,如短信模板,通讯软件消息模板,邮件消息模板,站内信消息模板等,用户配置好模板后,可调用消息系统的api,传递消息参数,消息系统根据模板内容对占位符进行替换,发送消息。

  • 模板样例

尊敬的:${userName} 您好,您有${integralCount}积分未使用,现有${activityName}活动,大礼包为您准备好了!戳${activityUrl}参加吧!

freemarker

maven

<dependency>
   <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.30</version>
</dependency>

代码

@Test
public void test() {
    try {
        String templateName ="ActivityMessage";
        Template template = newTemplate(templateName, getTemplate(), new Configuration(newVersion("2.3.23")));
        StringWriter result = newStringWriter();
        template.process(getParams(),result);
       System.out.println(result.toString());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public Map<String, Object> getParams() {
    Map<String, Object> params =new HashMap<>(8);
    params.put("userName","fly");
    params.put("integralCount",100.3456);
    params.put("activityName","新用户活动");
    params.put("activityUrl","jd.com");
    return params;
}

public String getTemplate() {
    return "尊敬的:${userName} 您好,您有${integralCount?string(\"#.##\")}积分未使用,现有${activityName}活动,大礼包为您准备好了!戳${activityUrl}参加吧!";
}

commons-text

@Test
public void void() {
    StringSubstitutor strSubstitutor =new StringSubstitutor(getParams());
    String messageContent =strSubstitutor.replace(getTemplate());
    System.out.println(messageContent);
}

public Map<String, Object> getParams() {
    Map<String, Object> params =new HashMap<>(8);
    params.put("userName","fly");
    params.put("integralCount",100.3456);
    params.put("activityName","新用户活动");
    params.put("activityUrl","jd.com");
    return params;
}

public String getTemplate() {
    return "尊敬的:${userName} 您好,您有${integralCount}积分未使用,现有${activityName}活动,大礼包为您准备好了!戳${activityUrl}参加吧!";
}

日志打印模板

在日志系统的开发中,我们可能有类似于log4j的日志打印的开发需求(log.info("活动基本信息 → {}", JSON.toString(activityInfo))),使用"{}",作为占位符,将参数拼接打印在顺序的位置上,我们可以模仿mybatis的占位,代码如下。

public class LoggerParser {

    private LoggerParser() {
    }

    /**
     * 将字符串text中由openToken和closeToken组成的占位符依次替换为args数组中的值
     *
     * @param openToken  left
     * @param closeToken right
     * @param text       text
     * @param args       args
     * @return message
     */
    private static String parse(StringopenToken, String closeToken, String text, Object... args) {
        if (args == null || args.length<= 0) {
            return text;
        }
        int argsIndex = 0;
        if (text == null ||text.isEmpty()) {
            return "";
        }
        char[] src = text.toCharArray();
        int offset = 0;
        // search open token
        int start =text.indexOf(openToken, offset);
        if (start == -1) {
            return text;
        }
        final StringBuilder builder = newStringBuilder();
        StringBuilder expression = null;
        while (start > -1) {
            if (start > 0 &&src[start - 1] == '\\') {
                // this open token isescaped. remove the backslash and continue.
                builder.append(src,offset, start - offset - 1).append(openToken);
                offset = start +openToken.length();
            } else {
                // found open token.let's search close token.
                if (expression == null) {
                    expression = newStringBuilder();
                } else {
                   expression.setLength(0);
                }
                builder.append(src,offset, start - offset);
                offset = start +openToken.length();
                int end =text.indexOf(closeToken, offset);
                while (end > -1) {
                    if (end > offset&& src[end - 1] == '\\') {
                        // this closetoken is escaped. remove the backslash and continue.
                       expression.append(src, offset, end - offset - 1).append(closeToken);
                        offset = end +closeToken.length();
                        end =text.indexOf(closeToken, offset);
                    } else {
                       expression.append(src, offset, end - offset);
                        break;
                    }
                }
                if (end == -1) {
                    // close token wasnot found.
                    builder.append(src,start, src.length - start);
                    offset = src.length;
                } else {
                    ///仅仅修改了该else分支下的个别行代码
                    String value =(argsIndex <= args.length - 1) ?
                           (args[argsIndex] == null ? "" : args[argsIndex].toString()) :expression.toString();
                    builder.append(value);
                    offset = end +closeToken.length();
                    argsIndex++;

                }
            }
            start =text.indexOf(openToken, offset);
        }
        if (offset < src.length) {
            builder.append(src, offset,src.length - offset);
        }
        return builder.toString();
    }

    public static String parser(Stringformat, Object... args) {
        return parse("{","}", format, args);
    }
}

测试

@Test
public void test() {
    System.out.println(LoggerParser.parser("您好 -> {}, 欢迎参加 -> {} 活动", "fly", "618大促"));
}

总结

在模板类的展位符的场景下,通常使用相同名称参数替换的方式,我们可以采用freemarker或者commons-text,相对来讲commons-text使用起来代码更加简洁。

在一些类似日志打印场景下,通常使用参数按顺序进行替换,可以使用LoggerParser这种方式,进行格式化参数。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值