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

案例

近期团队中多个项目均有邮件发送功能,邮件内容采用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日"));

    }

 

你可能感兴趣的:(邮件)