系列第一篇中,使用的是mybatis得到了一个小小的项目,而该项目的用户对象是有邮件地址的,如果按照邮件地址给对方去一封邮件会不会更能体现针对性呢,所以,我在这篇准备加入发送邮件的功能,利用的就是spring 自带的JavaMail.

1, 更新pom.xml. 添加velocity,javax.mail1.5能及spring-context-support.

<dependency>
<groupId>velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.5</version>
</dependency>

velocity1.5

<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.5.0</version>
</dependency>

javax.mail1.5.0

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>3.2.4.RELEASE</version>
</dependency>

spring-context-support3.2.4-RELEASE

2, 新建emailtemplates文件夹,包含vm和jpg文件。因为我的邮件要包含logo的。邮件里面要包含图片显示,vm模板必须写成<img src="cid:图片服务器端全地址,如本例中使用logoName"/>,发送时

org.springframework.core.io.Resource img = new ClassPathResource(logoName);
message.addInline("logoName", img);

3, config.properties中加入

com.vanceinfo.emailtemplate/myEmail=emailtemplates/myEmail.vm
com.vanceinfo.emailtemplate/myEmaillogo=emailtemplates/FlyingBird.jpg

4,spring-mvc.xml中加入

<!-- spring mail send configuration -->
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="smtp.gmail.com" />
<property name="port" value="587" />
<property name="username" value="kingnaliu@gmail.com" />
<property name="password" value="you real password" />
<property name="javaMailProperties">
<props>
<prop key="mail.smtp.starttls.enable">true</prop>
</props>
</property>
</bean> <bean id="restTemplate" class="org.springframework.web.client.RestTemplate" /> <bean id="velocityEngine"
class="org.springframework.ui.velocity.VelocityEngineFactoryBean">
<property name="velocityProperties">
<value>
resource.loader=class
class.resource.loader.class=org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
</value>
</property>
</bean>

spring mail send configuration

5,然后就是Java代码,分别定义一个接口,接品实现类及一个辅助实现的Helper类。这里有一个设计上的缺陷就是为了写单元测试,新开线程时写了一个实名的Runnable的类,本来用Java匿名类来实现是很优雅的一件事情,偏偏为了追求单元测试的覆盖率而白白增加这个Runnable类,而且还要在里面注入所需的参数和service名称。感觉有点搞。所以,我还是贴出我最原始的Helper类的源码吧。

package com.vanceinfo.javaserial.services;

import javax.mail.MessagingException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import com.vanceinfo.javaserial.model.EmailInfo;
import com.vanceinfo.javaserial.model.User; @Service("sendEmailHelper")
public class SendEmailHelper { @Autowired
private ISendEmail sendEmailService; public void sendVMLogoEmail(final User user) {
/*
* SendVMLogoEmailRunnable runnable = new SendVMLogoEmailRunnable();
* runnable.setSendEmailService(sendEmailService);
* runnable.setUser(user); Thread sendEmailThread = new
* Thread(runnable); sendEmailThread.start();
*/
new Thread(new Runnable() {
public void run() {
try {
EmailInfo email = new EmailInfo();
email.setFrom("jinliangliu@163.com");
email.setTo(new String[] { user.getEmail() });
email.setSubject("Test");
email.setEmailPlaceHolder(user);
email.setTempleteName("emailtemplates/myEmail.vm");
sendEmailService.sendEmailWithTemplate(email);
} catch (MessagingException e) { } catch (Exception e) { } }
}).start();
}
}

SendEmailHelper

6,最后,我是在userService里面调用Helper,让Helper调用实现类完成发送邮件功能。为什么要用Helper,因为如果你还要发送其也类型的邮件,只需在这里加入方法即可完成。

7, 上面提到的单元测试覆盖率,我们项目使用的是EclEmma,这个插件可以直接以EclEmma在Eclipse市场查找到,安装完之后,即可使用,其写方网址是:http://www.eclemma.org/

8,添加单元测试。这次我准备用一个tokenHandler来完成这次单元测试。因为要自定义Token的tag,所以先引入javax.servlet.jsp-api

<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
</dependency>

javax.servlet.jsp-api2.3.1

作这个token的作用,是我不想每次按F5或Ctrl+F5的时候,重新发送请求,也就是常说的二次提交问题的避免。中心思想来源于Struts2的token就是说当用户加载这个页面时,这个token生成了一个Guid,分别保存进session和hidden两个地方。提交之前对这两个进行比较,内容完全一致则认为是一致的,提交上去,然后remove掉session里面的Guid,这样子话,如果用户再次提交,就会因为session里面为空,而hidden里面还有值而不一致,跳转页面不让提交。

在spring-mvc.xml中加入声明:

<mvc:interceptors>
<!-- use Token to void multi post when user press F5 or Ctrol+F5 -->
<mvc:interceptor>
<mvc:mapping path="/index.do" />
<bean
class="com.vanceinfo.javaserial.handlerinterceptors.TokenHandlerInterceptor" />
</mvc:interceptor>
</mvc:interceptors>

mvc:interceptor

由于我更改了spring-mvc.xml里面对模型视图的解析,由原来的

<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/" p:suffix=".jsp" />

变成了如下:

<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/jsp/" />
<property name="suffix" value=".jsp" />
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
</bean>

对模型视图名称的解析

所以还要加上jstl-api1.2.1

<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>javax.servlet.jsp.jstl-api</artifactId>
<version>1.2.1</version>
</dependency>

javax.servlet.jsp.jstl-api1.2.1

如果不知道如何自定义jsp标签的话,可以参考这里,我这里的步骤:a,定义tag类,让其扩展TagSupport类. b,在WEB-INF下面创建标签库描述文件.tld(Tag Library Description). c,在web.xml里面定义

<jsp-config>
<taglib>
<taglib-uri>/mytaglib</taglib-uri>
<taglib-location>/WEB-INF/tlds/Token.tld</taglib-location>
</taglib>
</jsp-config>

配置自定义标签

d,在需引用的jsp里声明:

<%@ taglib uri="/mytaglib" prefix="ck"%>

并写上

<ck:token/>

即可。

值得一提的是这次的单元测试,还是使用的是参数化单元测试的,当写到这里的时候,我想还是另开一篇专门讲这一小节的好了。请点击这里

9,修改后的源码我更新了,可以在这里下载到

Java系列--第四篇 基于Maven的SSME之发送邮件的更多相关文章

  1. Java系列--第五篇 基于Maven的SSME之Token及Parameterized单元测试

    本来在第四篇要说完的,但是写着写着,我觉得内容有点多起来了,所以就另开这篇,在这里专门讲述Token的定义,JSP自定义标签以及如何用Parameterized的来做单元测试. 1,新建包com.va ...

  2. Java系列--第八篇 基于Maven的SSME之定时邮件发送

    关于ssme这个我的小示例项目,想做到麻雀虽小,五脏俱全,看到很多一些web都有定时发送邮件的功能,想我ssme也加入一下这种功能,经查询相关文档,发现spring本身自带了一个调度器quartz,下 ...

  3. Java系列--第六篇 基于Maven的SSME之多国语言实现

    如果你的网站足够强大,以致冲出了国门,走向了国际的话,你就需要考虑做多国语言了,不过,未雨绸缪,向来是我辈程序人员的优秀品质,谁知道那天,我们的网站被国外大公司看中收购,从而飞上枝头变凤凰.不扯这么多 ...

  4. Java系列--第三篇 基于Maven的Android开发CAIO

    学习要打好基础,这里用一个项目来学习一下Android的组件,参考网址为这个但不限于这个.有些东西的学习,理解三遍理论还不如一遍操作,所谓理论来自实践,实践是检验真理的唯一标准.所以,虽然看懂了那篇文 ...

  5. Java系列--第七篇 基于Maven的Android开发实战项目

    本篇是基于<Android应用案例开发大全,吴亚峰等著>的项目开发实例源码,其中有些图片,我做了一些修改,用于个人学习,请勿用于商业. 1, 日程管理专家 mvn archetype:ge ...

  6. 深入理解javascript作用域系列第四篇——块作用域

    × 目录 [1]let [2]const [3]try 前面的话 尽管函数作用域是最常见的作用域单元,也是现行大多数javascript最普遍的设计方法,但其他类型的作用域单元也是存在的,并且通过使用 ...

  7. 前端工程师技能之photoshop巧用系列第四篇——图片格式

    × 目录 [1]图片格式 [2]保存设置 前面的话 对于前端来说,图片格式是需要重要掌握的知识.本文是photoshop巧用系列第四篇——图片格式 图片格式 目前在前端的开发中常用的图片格式有jpg. ...

  8. 深入理解javascript作用域系列第四篇

    前面的话 尽管函数作用域是最常见的作用域单元,也是现行大多数javascript最普遍的设计方法,但其他类型的作用域单元也是存在的,并且通过使用其他类型的作用域单元甚至可以实现维护起来更加优秀.简洁的 ...

  9. Java系列--第二篇 基于Maven的Android开发HelloAndroidWorld

    曾经写过一篇Android环境配置的随笔,个人感觉特繁琐,既然有Maven,何不尝试用用Maven呢,经网上搜索这篇文章但不限于这些,而做了一个基于Maven的Android版的Hello Andro ...

随机推荐

  1. Visual Studio调试之断点进阶篇

    Visual Studio调试之断点进阶篇 在上一篇文章Visual Studio调试之断点基础篇里面介绍了什么是断点,INT 是Intel系列CPU的一个指令,可以让程序产生一个中断或者异常.程序中 ...

  2. MyBatis错误--Invalid bound statement (not found)

    今天在开发项目的时候使用MyBatis发生错误:Invalid bound statement (not found) 具体错误信息: org.springframework.beans.factor ...

  3. the smallest positive number

    2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any rema ...

  4. Building Web Apps with SignalR, Part 1

    Building Web Apps with SignalR, Part 1 In the first installment of app-building with SignalR, learn ...

  5. mysql连接的空闲时间超过8小时后 MySQL自动断开该连接解决方案

    在连接字符串中  添加设置节点 ConnectionLifeTime(计量单位为 秒).超过设定的连接会话 会被杀死! Connection Lifetime, ConnectionLifeTime ...

  6. Stack Overflow requires external JavaScript from another domain, which is blocked or failed to load.

    出现以上问题,只是说明stackoverflow前端库用到google的API来,所以stackoverflow躺枪.查阅后,是因为调用jquery的问题. 详情请看: 解决方案有好几种: 1.将ht ...

  7. Yii数据库

    http://www.yiiframework.com/doc/guide/1.1/zh_cn/database.ar http://zhengdl126.iteye.com/blog/1460779 ...

  8. pydev package包中__init__.py作用

    Eclipse用pydev,新建一个pydev package时,总会自动地生成一个空的__init__.py文件. 原来在python模块的每一个包中,都有一个__init__.py文件(这个文件定 ...

  9. MFC断点无效

    方法1: 将出问题的CPP文件用系统记事本notepad打开,然后另存时选择unicode编码保存,覆盖掉原来的文件即可.一般这种方法一般会解决VS断点无法设定的80%问题.没有办法才请出第2种方法. ...

  10. Java Hibernate 之 Session 状态

    Session接口是Hibernate向程序提供操纵数据库的最主要接口,是单线程对象,它提供了基本的保存.更新.删除和查询方法.它有一个缓存,保存了持久化对象,当清理缓存时,按照这些持久化对象同步更新 ...