[原创]牛刀小试-重构并实现邮件内容生成功能

案例

近期团队中多个项目均有邮件发送功能,邮件内容采用html格式,各项目独立开发,无统一实现方案。

举例:

某类型EmailSendService

类型拥有多个String字段 content1、content2 ... content7,均为html文本

生成邮件内容直接使用字符串连接

context1 + userName + content2 + inviteCode +
content3 + money + content4 + year +
content5 + month + content6 + day +
content7

整体不足200来行的代码文件,html字符串就占去了100多行

我对这段代码的评价无疑是 负分 滚出~

 

存在的问题及改进点

1、Html代码混杂在java代码中,且被拆分,邮件内容及样式不易更改

2、邮件内容发送变化,则代码需要重写(正常的项目,邮件模板会发送变更是显而易见的实事)

 

重构

目标

1、Html模板存放于Html文件资源中,java代码以资源文件路径指定模板

2、模板支持参数替换功能,参数可以命名

半小时后重构完成,形成如下类型

文本模板类型

支持参数批量替换,以"${argName}"格式指定参数

public class TextTemplate {
    private String template;

    public TextTemplate() {
        setTemplate("");
    }

    public TextTemplate(String template) {
        setTemplate(template);
    }

    public void setTemplate(String template) {
        this.template = template;
    }

    // 填充指定模板,返回结果字符串
    // 模板参数替换 ${key} 替换为对应 value
    public String fillTemplate(LinkedHashMap<String, String> kvs) {
        List<String> searchList = new ArrayList<>();
        List<String> replacementList = new ArrayList<>();

        for (Map.Entry<String, String> entry : kvs.entrySet()) {
            searchList.add("${" + entry.getKey() + "}");
            replacementList.add(entry.getValue());
        }
        int size = searchList.size();
        return StringUtils.replaceEachRepeatedly(template, searchList.toArray(new String[size]),
                                                        replacementList.toArray(new String[size]));
    }
}

这里使用的org.apache.commons.lang包中的StringUtils工具类,其方法replaceEachRepeatedly可以快速完成字符串替换

资源文件加载工具类

提供工具方法接受资源文件相对路径,返回资源文本

public class ResourceUtility {
    public static String getResourceFullText(String path) {
        return getResourceFullText(path, "UTF-8");
    }

    public static String getResourceFullText(String path, String encoding) {
        ClassPathResource resource = new ClassPathResource(path);
        StringWriter writer = new StringWriter();

        try {
            IOUtils.copy(resource.getInputStream(), writer, encoding);
        } catch (IOException e) {
            throw new RuntimeException("cannot load resource data", e);
        }
        return writer.toString();
    }
}

Email内容生成器类型

public class EmailHtmlContentGenerator {
    private TextTemplate textTemplate;

    public EmailHtmlContentGenerator(String resourcePath) {
        textTemplate = new TextTemplate(ResourceUtility.getResourceFullText(resourcePath));
    }

    public String generateContent(LinkedHashMap<String, String> properties) {
        return textTemplate.fillTemplate(properties);
    }
}

重构上层类型EmailSendService

1、抽取所有Html代码至独立的Html文件中,放置与resources目录下,可采用路径如 emailTemplates/welcome.html

2、所有表示Html代码的字符串字段删除

3、删除邮件Html代码合成逻辑,替代如下代码,独立至一个方法中

    public String generateEmailContent(String userName, String invitationCode, String amount, int year, int month,
                                       int day) {
        LinkedHashMap<String, String> properties = new LinkedHashMap<>();
        properties.put("userName", userName);
        properties.put("amount", amount);
        properties.put("year", String.valueOf(year));
        properties.put("month", String.valueOf(month));
        properties.put("day", String.valueOf(day));
        return emailHtmlContentGenerator.generateContent(properties);
    }

 

单元测试

对TextTemplate类型进行单元测试

public class TextTemplateTests {
    @Test
    public void testFillTemplateWithNoParams() {
        TextTemplate textTemplate = new TextTemplate("Hello World");
        assertEquals("Hello World", textTemplate.fillTemplate(new LinkedHashMap<String, String>()));
    }

    @Test
    public void testFillTemplateWithOneParam() {
        TextTemplate textTemplate = new TextTemplate("Hello ${name}");
        LinkedHashMap<String, String> properties = new LinkedHashMap<>();
        properties.put("name", "Ant");
        assertEquals("Hello Ant", textTemplate.fillTemplate(properties));

        properties.put("name", "Man");
        assertEquals("Hello Man", textTemplate.fillTemplate(properties));
    }

    @Test
    public void testFillTemplateWithMultiParams() {
        TextTemplate textTemplate = new TextTemplate("===== ${greet} ${name} =====");
        LinkedHashMap<String, String> properties = new LinkedHashMap<>();
        properties.put("greet", "Hello");
        properties.put("name", "Ant");
        assertEquals("===== Hello Ant =====", textTemplate.fillTemplate(properties));
    }
}

对EmailSendService类型新增方法进行单元测试

    @Test
    public void testGenerateEmailContent() {
        String emailContent = emailSendService.generateEmailContent("Ant", "999.99", 2015, 2, 4);
        assertTrue(emailContent.contains("尊敬的Ant"));
        assertTrue(emailContent.contains("充值999.99元。"));
        assertTrue(emailContent.contains("2015年2月4日"));
    }

 

转载于:https://www.cnblogs.com/gods/p/4273135.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值