Spring Boot 发送邮件/短信验证码

Java
296
0
0
2023-07-24
标签   SpringBoot

发送邮件和短信都需要做好准备工作,本文的邮件使用了QQ邮箱作为发送者,要开启SMTP;短信用的是阿里云,要有创建好的签名和审核通过的短信模板,本文的主要内容的代码模块,这两个服务的准备工作就不多介绍了。

本来邮箱用的是163,但是163邮箱发送邮件一直提示554,不管怎么修改都不行,只好改用qq。

导入Maven依赖

 <!--发送邮件-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

<!--发送短信-->
<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>aliyun-java-sdk-core</artifactId>
    <version>.5.1</version>
</dependency>
<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
    <version>.1.0</version>
</dependency> 

然后是配置文件application:

 server:
  port:

spring:
  mail:
    host: smtp.qq.com  # 邮件服务地址
    username: 自己填  # 发送者邮箱
    password: 自己填  # 授权码
    default-encoding: UTF- # 默认的邮件编码为UTF-8
    properties:
      mail:
        smtp:
          auth: true
          # 如果是用 SSL 方式,需要配置如下属性,使用qq邮箱的话需要开启
          starttls:
            enable: true
            required: true

sms:
  accessKeyId: 自己填
  accessSecret: 自己填
  signName: 自己填
  templateCode: 自己填 

发送邮件

邮件有多种类型:普通的纯文本、html格式、带附件、内容带图片。

 package com.cc.service;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;
import java.util.Map;

/**
 * 邮件服务
 * @author cc
 * @date-12-07 10:37
 */@Service
public class MailService {
    private final JavaMailSender mailSender;

    @Value("${spring.mail.username}")
    private String SENDER;

    public MailService(JavaMailSender mailSender) {
        this.mailSender = mailSender;
    }

    // 发送普通邮件
    public void sendSimpleMailMessage(String to, String subject, String content) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(SENDER);
        message.setTo(to);
        message.setSubject(subject);
        message.setText(content);
        mailSender.send(message);
    }

    // 发送html邮件
    public void sendMimeMessage(String to, String subject, String content) throws MessagingException {
        MimeMessage message = mailSender.createMimeMessage();;
        // true表示需要创建一个multipart message
        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        helper.setFrom(SENDER);
        helper.setTo(to);
        helper.setSubject(subject);
        helper.setText(content, true);
        mailSender.send(message);
    }

    // 发送带附件的邮件
    public void sendMimeMessage(String to, String subject, String content, String filePath) throws MessagingException {
        MimeMessage message = mailSender.createMimeMessage();;
        // true表示需要创建一个multipart message
        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        helper.setFrom(SENDER);
        helper.setTo(to);
        helper.setSubject(subject);
        helper.setText(content, true);

        FileSystemResource file = new FileSystemResource(new File(filePath));
        String fileName = file.getFilename();
        helper.addAttachment(fileName, file);
        mailSender.send(message);
    }

    // 发送带静态文件的邮件
    public void sendMimeMessage(String to, String subject, String content, Map<String,String> rscIdMap) throws MessagingException {
        MimeMessage message = mailSender.createMimeMessage();
        // true表示需要创建一个multipart message
        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        helper.setFrom(SENDER);
        helper.setTo(to);
        helper.setSubject(subject);
        helper.setText(content, true);

        for (Map.Entry<String, String> entry : rscIdMap.entrySet()) {
            FileSystemResource file = new FileSystemResource(new File(entry.getValue()));
            helper.addInline(entry.getKey(), file);
        }
        mailSender.send(message);
    }
} 

发送短信

 package com.cc.service;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

/**
 * 短信服务
 *
 * @author cc
 * @date-12-07 9:50
 */@Service
public class SmsService {
    @Value("${sms.accessKeyId}")
    private String accessKeyId;

    @Value("${sms.accessSecret}")
    private String accessSecret;

    @Value("${sms.signName}")
    private String signName;

    @Value("${sms.templateCode}")
    private String templateCode;

    public void send(String phone, String code) throws ClientException {
        if (StringUtils.isEmpty(phone)) {
            throw new RuntimeException("手机号码不能为空");
        }
        if (StringUtils.isEmpty(code)) {
            throw new RuntimeException("验证码不能为空");
        }

        // 初始化acsClient,暂不支持region化
        IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou",
                accessKeyId, accessSecret);
        IAcsClient acsClient = new DefaultAcsClient(profile);
        // 组装请求对象-具体描述见控制台-文档部分内容
        SendSmsRequest request = new SendSmsRequest();
        // 必填:待发送手机号
        request.setPhoneNumbers(phone);
        // 必填:短信签名-可在短信控制台中找到
        request.setSignName(signName);
        // 必填:短信模板-可在短信控制台中找到
        request.setTemplateCode(templateCode);
        request.setTemplateParam("{\"code\":\"" + code + "\"}");

        SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
        if(sendSmsResponse.getCode()!= null && "OK".equals(sendSmsResponse.getCode())){
            System.out.println("短信发送成功!");
        }else {
            throw new RuntimeException("短信发送失败:" + sendSmsResponse.getMessage());
        }
    }
} 

生成验证码

 package com.cc.utils;

import java.util.Random;

/**
 * 验证码生成器
 * @author cc
 * @date-12-07 10:32
 */public class VerifyCodeGenerator {
    public static String make(int length) {
        if (length <=) {
            throw new RuntimeException("验证码长度不能小于");
        }
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i =; i < length; i++) {
            sb.append(random.nextInt());
        }
        return sb.toString();
    }
} 

测试一下

在使用邮件的附件功能时,要提前在resources中添加pic01.png、pic02.png和test.txt文件,方便测试

测试类:

 package com.cc;

import com.aliyuncs.exceptions.ClientException;
import com.cc.service.MailService;
import com.cc.service.SmsService;
import com.cc.utils.VerifyCodeGenerator;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.SpringRunner;
import org.springframework.util.ResourceUtils;

import javax.mail.MessagingException;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Map;

@SpringBootTest
@RunWith(SpringRunner.class)
public class ApplicationTest {
    // test中不能有有参构造函数
    @Autowired
    private MailService mailService;

    @Autowired
    private SmsService smsService;

    private static final String TO = "xxx@qq.com";
    private static final String SUBJECT = "出师表";
    private static final String CONTENT = "先帝创业未半而中道崩殂,今天下三分,益州疲弊,此诚危急存亡之秋也。然侍卫之臣不懈于内,忠志之士忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气,不宜妄自菲薄,引喻失义,以塞忠谏之路也。\n" +
            "宫中府中,俱为一体,陟罚臧否,不宜异同。若有作奸犯科及为忠善者,宜付有司论其刑赏,以昭陛下平明之理,不宜偏私,使内外异法也。";

    // 测试发送普通邮件
    @Test
    public void sendSimpleMailMessage() {
        mailService.sendSimpleMailMessage(TO, SUBJECT, CONTENT);
    }

    // 测试发送html邮件
    @Test
    public void sendHtmlMessage() throws MessagingException {
        String htmlStr = "<h>Test</h1>";
        mailService.sendMimeMessage(TO, SUBJECT, htmlStr);
    }

    // 测试发送带附件的邮件
    @Test
    public void sendAttachmentMessage() throws FileNotFoundException, MessagingException {
        File file = ResourceUtils.getFile("classpath:test.txt");
        System.out.println(file);
        String filePath = file.getAbsolutePath();
        mailService.sendMimeMessage(TO, SUBJECT, CONTENT, filePath);
    }

    // 测试发送带静态文件的邮件
    @Test
    public void sendStaticFileMessage() throws FileNotFoundException, MessagingException {
        String htmlStr = "<html><body>测试:图片 <br> <img src=\'cid:pic1\'/><br>图片2 <br> <img src=\'cid:pic2\'/></body></html>";
        Map<String, String> rscIdMap = new HashMap<>();
        rscIdMap.put("pic", ResourceUtils.getFile("classpath:pic01.png").getAbsolutePath());
        rscIdMap.put("pic", ResourceUtils.getFile("classpath:pic02.png").getAbsolutePath());
        mailService.sendMimeMessage(TO, SUBJECT, htmlStr, rscIdMap);
    }

    // 测试发送短信
    @Test
    public void sendSms() throws ClientException {
        smsService.send("your phone", VerifyCodeGenerator.make());
    }

    // 生成一段验证码
    @Test
    public void generatorVerifyCode() {
        System.out.println(VerifyCodeGenerator.make());
    }
} 

邮件和短信的发送还是很简单的,都是调调接口。

使用短信的话要留意是收费的,当前的价格是0.045分一条。