那先来说说邮件发送。按照按接口编程的习惯,当然先要定义一个邮件发送的接口,再实现其接口,完成邮件发送Service层的代码。这个顺序我想大家没什么反对意见吧。
首先咱们先定义一个消息发送接口,它是邮件发送与短信发送的上层接口。
- /**
- * 功能: 系统消息发送服务 <p>
- * 用法:
- * @version 1.0
- */
- public interface MessageService {
- /**
- * 根据消息模板表中的消息编号取得消息模板,填充,发送
- *
- * @param bmtCode 消息模板表中的消息编号
- * @param params 填充模板内容的参数
- * @param to 消息的接收人
- * @throws CheckException 模板不存在,或是发送消息出现异常
- */
- public void sendMessage(String bmtCode,Map params, String... to) throws CheckException;
- }
再来定义一下邮件发送器接口,由于我这里是通过velocity模板发送邮件的,所以如下定义了接口:
- /**
- * 邮件发送器
- * @usage
- */
- public interface TempletEmailSender {
- /**
- * @param from 发件人邮箱
- * @param to 收件人邮箱
- * @param subject 邮件主题
- * @param templet 模板
- * @param paramMap 模板参数信息
- * @throws CheckException
- */
- public void sendEmailByTemplet(String from, String to, String subject,String templet, Map<String, Object> paramMap) throws CheckException;
- /**
- * @param from 发件人邮箱
- * @param to 收件人邮箱(多个)
- * @param subject 邮件主题
- * @param templet 模板
- * @param paramMap 模板参数信息
- * @throws CheckException
- */
- public void sendEmailByTemplet(String from, String[] to, String subject,String templet, Map<String, Object> paramMap) throws CheckException;
- /**
- * @param mail 邮件对象
- * @param templet 模板
- * @param paramMap 模板参数信息
- * @throws CheckException
- */
- public void sendEmailByTemplet(Mail mail,String templet, Map<String, Object> paramMap) throws CheckException;
- }
接着实现邮件发送的接口:
- /**
- * 邮件发送器默认实现
- */
- public class TempletEmailSenderImpl implements TempletEmailSender{
- @Autowired
- @Qualifier("emailSenderImpl_commons")
- private EmailSender emailSender;
- @Override
- public void sendEmailByTemplet(String from, String to,String subject, String templet, Map<String, Object> paramMap) throws CheckException {
- sendEmailByTemplet(from, new String[]{to}, subject, templet, paramMap);
- }
- @Override
- public void sendEmailByTemplet(String from, String[] to, String subject, String templet, Map<String, Object> paramMap) throws CheckException {
- // 解析模板
- String content ;
- try {
- content = VelocityParserUtil.getInstance().parseVelocityTemplate(templet, paramMap);
- } catch (Throwable t) {
- throw new CheckException(t);
- }
- emailSender.sendEmail(from, to, subject, content);
- }
大家看到了上面的实现里注入了EmailSender,它也是一个接口,它的实现里注入了JavaMail提供的邮件发送接口。定义了两层是为了区分有模板的发送和无模板的发送。我们来看看它是什么样的:
- /**
- * 邮件发送器
- * @usage
- */
- public interface EmailSender {
- /**
- * 发送邮件
- * @param from 发件人
- * @param to 收件人
- * @param subject 邮件主题
- * @param mailBody 邮件内容
- * @throws CheckException 参数校验失败或发送邮件失败时,抛出此异常
- */
- void sendEmail(String from, String to, String subject, String mailBody) throws CheckException;
- /**
- * 发送邮件
- * @param from 发件人
- * @param to 多个收件人
- * @param subject 邮件主题
- * @param mailBody 邮件内容
- * @throws CheckException 参数校验失败或发送邮件失败时,抛出此异常
- */
- void sendEmail(String from, String[] to, String subject, String mailBody) throws CheckException;
- /**
- * 发送邮件
- * @param mail 邮件
- * @throws CheckException 参数校验失败或发送邮件失败时,抛出此异常
- */
- void sendEmail(Mail mail) throws CheckException;
- }
接着实现这个EmailSender接口:
- **
- * JAVA MAIL实现
- */
- public class EmailSenderImpl implements EmailSender,InitializingBean{
- /**
- * Logger for this class
- */
- private static final Logger logger = Logger.getLogger(EmailSenderImpl.class);
- @Autowired
- private ConfigService configService;
- private JavaMailSenderImpl sender; // 实际的发送实现
- @Override
- public void sendEmail(String from, String to, String subject, String mailBody) throws CheckException {
- sendEmail(from, new String[]{to}, subject, mailBody);
- }
- @Override
- public void sendEmail(String from, String[] to, String subject, String mailBody) throws CheckException {
- // 构造MAIL对象
- Mail mail = new Mail();
- mail.setFrom(from);
- mail.setTo(to);
- mail.setSubject(subject);
- mail.setContent(mailBody);
- sendEmail(mail);
- }
- @Override
- public void sendEmail(Mail mail) throws CheckException {
- // 检查必要参数
- if (mail == null ){
- throw new CheckException("mail can not be null.");
- }
- if (ArrayUtils.isEmpty(mail.getTo())){
- throw new CheckException("收件人不能为空");
- }
- MimeMessageHelper helper = null;
- try {
- helper = new MimeMessageHelper(sender.createMimeMessage(), true, "UTF-8");
- // 发件人
- if (mail.getFrom() != null) {
- if (mail.getFromName() == null) {
- helper.setFrom(mail.getFrom());
- } else {
- helper.setFrom(mail.getFrom(), mail.getFromName());
- }
- }
- // 收件人
- helper.setTo(mail.getTo());
- // 抄送人
- if (mail.getCc() != null) {
- helper.setCc(mail.getCc());
- }
- // 密送人
- if (mail.getBcc() != null) {
- helper.setBcc(mail.getBcc());
- }
- // 邮件主题
- helper.setSubject(mail.getSubject());
- // 邮件内容
- helper.setText(mail.getContent(), mail.isHtmlFormat());
- // 附件
- if (mail.getAttachments() != null) {
- for ( MailAttachment attachment : mail.getAttachments()) {
- helper.addAttachment(attachment.getFileName(),attachment.getFile());
- }
- }
- // 发送时间
- helper.setSentDate(new Date());
- } catch (UnsupportedEncodingException e) {
- logger.error("sendEmail(Mail)", e);
- throw new CheckException(e) ;
- } catch (MessagingException e) {
- logger.error("sendEmail(Mail)", e);
- throw new CheckException(e) ;
- }
- // 发送
- try {
- sender.send(helper.getMimeMessage());
- } catch (MailException e) {
- logger.error("sendEmail(Mail)", e);
- throw new CheckException(e) ;
- }
- }
- @Override
- public void afterPropertiesSet() throws Exception {
- sender = new JavaMailSenderImpl();
- // configService读出参数
- Properties pros = new Properties();
- pros.setProperty("mail.smtp.user", configService.getConfig(BasePropertyID.MAIL_SMTP_USER_ID));
- pros.setProperty("mail.smtp.host", configService.getConfig(BasePropertyID.MAIL_SMTP_HOST_ID));
- pros.setProperty("mail.smtp.port", configService.getConfig(BasePropertyID.MAIL_SMTP_PORT_ID));
- pros.setProperty("mail.smtp.connectiontimeout", configService.getConfig(BasePropertyID.MAIL_SMTP_CONNECTIONTIMEOUT_ID));
- pros.setProperty("mail.smtp.timeout", configService.getConfig(BasePropertyID.MAIL_SMTP_TIMEOUT_ID));
- pros.setProperty("mail.smtp.from", configService.getConfig(BasePropertyID.MAIL_SMTP_FROM_ID));
- pros.setProperty("mail.smtp.auth", configService.getConfig(BasePropertyID.MAIL_SMTP_AUTH_ID));
- sender.setJavaMailProperties(pros);
- sender.setPassword(configService.getConfig(BasePropertyID.MAIL_SMTP_PASSWORD_ID));
- }
- public ConfigService getConfigService() {
- return configService;
- }
- public void setConfigService(ConfigService configService) {
- this.configService = configService;
- }
O(∩_∩)O~大家又注意到了 这个接口实现里又注入了一个接口ConfigService 它是去读取邮件发送的相关配置信息,如上所示:
// configService读出参数
Properties pros = new Properties();
pros.setProperty("mail.smtp.user", configService.getConfig(BasePropertyID.MAIL_SMTP_USER_ID));
pros.setProperty("mail.smtp.host", configService.getConfig(BasePropertyID.MAIL_SMTP_HOST_ID));
pros.setProperty("mail.smtp.port", configService.getConfig(BasePropertyID.MAIL_SMTP_PORT_ID));
pros.setProperty("mail.smtp.connectiontimeout", configService.getConfig(BasePropertyID.MAIL_SMTP_CONNECTIONTIMEOUT_ID));
pros.setProperty("mail.smtp.timeout", configService.getConfig(BasePropertyID.MAIL_SMTP_TIMEOUT_ID));
pros.setProperty("mail.smtp.from", configService.getConfig(BasePropertyID.MAIL_SMTP_FROM_ID));
pros.setProperty("mail.smtp.auth", configService.getConfig(BasePropertyID.MAIL_SMTP_AUTH_ID));
sender.setJavaMailProperties(pros);
sender.setPassword(configService.getConfig(BasePropertyID.MAIL_SMTP_PASSWORD_ID));
而且由于涉及到参数的数据成员较多,就将他们一起封装到了Mail类:
- /**
- * 功能: 封装邮件对象 <p>
- * 用法:
- * @version 1.0
- */
- public class Mail {
- /**
- * 发件人
- */
- private String from;
- /**
- * 发件人(显示)
- */
- private String fromName;
- /**
- * 收件人
- */
- private String[] to;
- /**
- * 抄送
- */
- private String[] cc;
- /**
- * 秘密抄送
- */
- private String[] bcc;
- /**
- * 邮件主题
- */
- private String subject;
- /**
- * 邮件内容
- */
- private String content;
- /**
- * 附件
- */
- private MailAttachment[] attachments;
- /**
- * 是否以HTML格式发送
- */
- boolean isHtmlFormat = true;
- //getter与setter方法省略
- }
好了 整个接口都实现了,其实排除了你发送邮件提供给邮件发送接口的几个参数,剩下的也就是调用java提供的邮件发送的API和一些邮件发送必备的配置信息,必不是很难懂吧。大家肯定注意到了邮件发送接口的velocity模板解析方法:
content = VelocityParserUtil.getInstance().parseVelocityTemplate(templet, paramMap);
它具体的实现如下所示:
- /**
- * 功能:解析velocity模板
- * <p>
- * 用法:
- *
- * @version 1.0
- */
- public class VelocityParserUtil {
- /**
- * Logger for this class
- */
- private static final Logger logger = Logger.getLogger(VelocityParserUtil.class);
- private static VelocityParserUtil instance = new VelocityParserUtil();
- private VelocityEngine engine = null;
- private VelocityParserUtil() {
- // init engine
- engine = new VelocityEngine();
- try {
- engine.init();
- } catch (Exception e) {
- logger.warn("VelocityParserUtil() - exception ignored", e); //$NON-NLS-1$
- }
- }
- /**
- * 返回VelocityParserUtil实例
- * @return
- */
- public static VelocityParserUtil getInstance() {
- return instance;
- }
- /**
- * 解析velocity模板
- * @param vtl
- * @param model
- * @return String
- * @throws ParseErrorException
- * @throws MethodInvocationException
- * @throws ResourceNotFoundException
- * @throws IOException
- */
- public String parseVelocityTemplate(String vtl, Map model)
- throws ParseErrorException, MethodInvocationException,
- ResourceNotFoundException, IOException {
- if (logger.isDebugEnabled()) {
- logger.debug("parseVelocityTemplate(String, Map) - start"); //$NON-NLS-1$
- }
- VelocityContext velocityContext = new VelocityContext(model);
- StringWriter result = new StringWriter();
- engine.evaluate(velocityContext, result, null, vtl);
- String returnString = result.toString();
- if (logger.isDebugEnabled()) {
- logger.debug("parseVelocityTemplate(String, Map) - end"); //$NON-NLS-1$
- }
- return returnString;
- }
- }
我们会在其他的Service中去调用邮件发送的接口,只需要在业务层里构造好邮件发送的接口所需参数,我们的邮件就可以发送出去了。还有一点请大家注意,我这里主要强调的是运用velocity模板发送邮件,接口所需要的参数templat大家不要误解为velocity模板的文件名,它其实velocity文件的文件流,是一个已经被读入的字符串。大家可以参考一下测试用例,大致可以明白是怎么回事了。
- public class TempletEmailSenderTest extends BaseTestBaseForJUnit4{
- @Autowired
- @Qualifier("templetEmailSenderImpl_commons")
- private TempletEmailSender sender;
- // @Test
- public void sendEmailByTemplet() throws CheckException{
- String templet = "$!{user}提醒您付款$!{amount}元";
- Map paramMap = new HashMap();
- paramMap.put("user", "吴欣");
- paramMap.put("amount", "99.9");
- sender.sendEmailByTemplet("wuxin.wystan@snda.com", "wuxin.wystan@snda.com", "模板邮件", templet, paramMap);
- }
整个邮件的发送大家是否明了了呢,呵呵!
后面我们会将这个接口向上抽象,为了实现我们短信发送的实现,下一篇敬请期待哦