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

案例

近期团队中多个项目均有邮件发送功能,邮件内容采用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日"));
    }
时间: 2024-09-29 05:23:50

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

使用Razor视图引擎来生成邮件内容

邮件的内容其实是就HTML,传统的做法都是通过在程序中拼接字符串来生成邮件的内容,生成困难,维护也困难.Razor是MVC里面使用的视图引擎,用来生成HTML非常方便,ZKEACMS中就是使用了Razor视图引擎,用cshtml作为邮件模板来生成邮件内容.这样很方便维护和修改. 定义接口 IViewRenderService 接口中定义了两个方法,第一个是视图中没有使用ViewModel,直接传入视图路径就可以了.第二个是视图中有作用ViewModel,传入视图路径和ViewModel对象就可以

使用T4模板动态生成邮件内容并储存到任意位置

一.基础概念介绍 T4模板是扩展名为 .tt 的文本文件. 他分为设计时模板 和运行时模板.主要区别在于在vs中右键点击文件,打开“属性”,在“自定义工具”一栏中的值分别如下: 设计时模板: TextTemplatingFileGenerator 运行时模板:TextTemplatingFilePreprocessor 二.模板转换 当然设计时模板可以转为运行时模板,只要将该文件的“自定义工具”属性设置为 TextTemplatingFilePreprocessor即可. 但是运行时模板很多情况

:after伪类+content内容生成经典应用举例——张鑫旭

一.简单说说content内容生成 content内容生成就是通过content属性生成内容,content属性早在CSS2.1的时候就被引入了,可以使用:before以及:after伪元素生成内容.此特性目前已被大部分的浏览器支持: (Firefox 1.5+, Safari 3.5+, IE 8+, Opera 9.2+, Chrome 0.2+).另外,目前Opera 9.5+ 和 Safari 4已经支持所有元素的content属性,而不仅仅是:before和:after伪元素. 例如下

JavaMail解析邮件内容(经典收藏)

import java.io.*; import java.text.*; import java.util.*; import javax.mail.*; import javax.mail.internet.*; /** * 有一封邮件就需要建立一个ReciveMail对象 */ public class ReciveOneMail { private MimeMessage mimeMessage = null; private String saveAttachPath = ""

第七讲:解析邮件内容

一.JavaMail解析邮件内容的流程 二.解析邮件内容 2.1 解析普通邮件内容 如果Message.getContentType方法返回的MIME类型为"text/*"则表示邮件内容为文本内容,此时直接调用Message.getContent方法把邮件内容保存了一个String对象中输出给浏览器即可.但是现实邮件中会有HTML格式的邮件内容时,邮件发送程序为了防止有些邮件阅读软件不能显示处理HTML格式的数据,通常都会用两类型分别为"text/plain"和&q

邮件内容加密方法-如何让你的邮件隐密邮

早期邮件在互联网上都是以明文传输的,很容易就被窃取,后来邮件通讯使用了SSL通道才保证了邮件在链路上的安全,但是邮件在邮件服务器上的安全一直以来都很难解决,即使是今天依然有***可以将用户的邮件从服务器上窃取出来.所以邮件内容的安全目前是邮件安全的重点,既然是内容安全就要使用加密技术了,如果邮件再服务器上是密文存储的那么即使邮件被窃取下来也不用太担心,前提是你使用的加密技术够强.那么目前都有哪些常用的加密技术用于邮件中呢? 第一种:利用对称加密算法加密邮件 对称加密算法是应用较早的加密算法,技术

Python3读取邮件内容

Python3读取邮件内容 前言 邮件的收取主要有pop(主要用于客户端远程管理服务器上的邮件)和imap(交互式邮件访问协议),相应的Python中提供了相关的模块poplib和imaplib.POP3尽管得到广泛的支持,但其已经过时,而且POP3服务器的实现差异很大,大多数进行较差,所以如果我们的邮件服务器支持IMAP,那么最好使用imaplib.IMAP4,因为IMAP服务器往往会更好的实现.基本上主流的邮箱都会支持imap协议,如qq.163.gmail.outlook等等.因此我们选择

上网行为管理软件如何监控客户端方式收发的邮件内容?

客户端邮件是指用邮件客户端来收发邮件. 邮件客户端一般采用SMTP.POP3和IMAP协议,随着SSL加密的广泛应用,后来又发展了SSL加密的邮件收发. 配置客户端时,如果勾选了"此链接需要SSL加密"或者"STARTTLS"的传输方式,都意外着该链接已经被加密.目前,SSL加密邮件已经得到了广泛的应用. 在"WFilter上网行为管理软件"中,无需配置即可监控到不加密的客户端邮件. 1. 在"所有在线"中点击"邮件

更改邮件发送语言为英语,解决编码为UTF8邮箱注册账号,邮件内容乱码问题

Change email English language, code for UTF8 mailbox registered account, email content garbled. 1. code analysis 乱码分析 通过对中文编码的邮件服务器使用原来的系统(GB2312) The original system used by the mail server encoding for the Chinese code (GB2312) 我使用outlook.com的邮箱(UT