Java系列--第四篇 基于Maven的SSME之发送邮件

系列第一篇中,使用的是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,修改后的源码我更新了,可以在这里下载到

原文地址:https://www.cnblogs.com/SLKnate/p/Java_Serial_SSME_SendEmail.html