javascript
你有没有觉得邮件发送人固定配置在yml文件中是不妥当的呢?SpringBoot 动态设置邮件发送人
明月當(dāng)天,不知道你有沒有思念的人
前言
之前其實(shí)已經(jīng)寫過SpringBoot異步發(fā)送郵件,但是今天在一個(gè)小項(xiàng)目中要用到發(fā)送郵件時(shí),我突然覺得郵件發(fā)送人只有一個(gè),并且固定寫在yml文件中,就是非常的不妥當(dāng),就想著怎么整成一個(gè)動(dòng)態(tài)的。
在寫之前已經(jīng)翻過很多博客了,該踩的坑都踩的差不多了,我是實(shí)現(xiàn)之后寫的文章,有問題大家可以一起交流。
小聲bb(對于CSDN我真的逐漸變得麻木了,簡稱CV大法現(xiàn)場,雖然我本人也是CSDN的一名小小博主,也是資深用戶,對于文章的這塊很多時(shí)候真的沒法說,除了能說加油也沒有了吧)。
于是就有了下面這篇文章啦…
一、需求分析
默認(rèn)大家都已經(jīng)會 SpringBoot 集成 郵件發(fā)送啦哈,不行的,點(diǎn)一下上文的鏈接啦。
我先說說我想要達(dá)到什么樣的效果:
思路其實(shí)蠻簡單的,就只要做到每次我們新添加或者修改郵件發(fā)送人配置的時(shí)候,對JavaSendMailImpl這個(gè)類重新初始化即可。這個(gè)地方?jīng)]啥可講的,就是不讓框架給我們自動(dòng)配置,我們手動(dòng)來即可。
二、詳細(xì)步驟
2.1、編碼
1)yml配置文件
spring: mail:host: smtp.163.comusername: nxxxxxx@163.compassword: IXXXXXXXXXN(開啟允許第三方登錄后的授權(quán)碼)default-encoding: utf-8protocol: smtpsproperties:mail:smtp:port: 465auth: truestarttls:enable: truerequired: true注意:關(guān)于郵件的協(xié)議protocol:smtps的配置,我最開始也是配置的smtp,我當(dāng)時(shí)報(bào)的錯(cuò)誤是一個(gè)no provider for smtp錯(cuò)誤,我之前也寫過一直用的是這個(gè)smtp協(xié)議,但是報(bào)了這個(gè)錯(cuò)誤,我就去搜索,然后找到有篇博客說,
SMTPS協(xié)議
SMTPS (SMTP-over-SSL)是SMTP協(xié)議基于SSL安全協(xié)議之上的一種變種協(xié)議,它繼承了SSL安全協(xié)議的非對稱加密的高度安全可靠性,可防止郵件泄露。SMTPS和SMTP協(xié)議一樣,也是用來發(fā)送郵件的,只是更安全些,防止郵件被黑客截取泄密,還可實(shí)現(xiàn)郵件發(fā)送者抗抵賴功能。防止發(fā)送者發(fā)送之后刪除已發(fā)郵件,拒不承認(rèn)發(fā)送過這樣一份郵件。端口465和587便是基于SMTPS協(xié)議開放的。
465端口(SMTPS)︰它是SMTPS協(xié)議服務(wù)所使用的其中一個(gè)端口,它在郵件的傳輸過程中是加密傳輸(SSL/TLS)的,相比于SMTP協(xié)議攻擊者無法獲得郵件內(nèi)容,郵件在一開始就被保護(hù)了起來。
所以實(shí)際上我們使用的配置應(yīng)該是stmps。
另外建個(gè)properties資源類 與 配置文件一一對應(yīng)
/*** @author crush*/ @Data @Component @ConfigurationProperties(prefix = "spring.mail") public class MailProperties {/** * 用戶名 */private String username;/** * 授權(quán)碼 */private String password;/** * host */private String host;/** * 端口 */private Integer port;/*** 協(xié)議 */private String protocol;/** * 默認(rèn)編碼*/private String defaultEncoding; }2.2、建表
根據(jù)yml文件,我們大致知道了要建立張什么樣的數(shù)據(jù)表了哈。
這些大家都可以自定義哈,根據(jù)自己需求來建哈。
根據(jù)數(shù)據(jù)表建一個(gè)pojo類。
/*** @Author: crush* @Date: 2021-11-26 18:28* version 1.0*/ @Data @Accessors(chain = true) @TableName("tb_email") public class MailPO {private String emailHost;private String emailUsername;private String emailPassword;private Integer emailPort=465;/** * 協(xié)議 */private String protocol="smtps";/** * 默認(rèn)編碼 */private String defaultEncoding="utf-8";/*** 使用狀態(tài),1:正在使用,2:禁用,3:停用* TODO 后期應(yīng)該更改為 枚舉類來進(jìn)行實(shí)現(xiàn)*/private Integer state=1;/** * 創(chuàng)建時(shí)間 */@TableField(fill = FieldFill.INSERT)private LocalDateTime createTime;/*** 修改時(shí)間 */@TableField(fill = FieldFill.INSERT_UPDATE)private LocalDateTime updateTime; }如果不是用mybatis-plus 可以把創(chuàng)建時(shí)間和修改時(shí)間去掉@TableField(fill = FieldFill.INSERT)是Mybatis-plus中的注解。另外我主鍵是設(shè)置了自增,所以就空了。至于返回的類我用的vo包下的。
2.3、mapper、service層
@Repository public interface MailMapper extends BaseMapper<MailPO> { }service
/*** @Author: crush* @Date: 2021-11-26 15:55* version 1.0*/ public interface MailService {void send(MailDTO mailDTO);boolean addMailPerson(MailPO mailPO); }impl
import cn.hutool.core.util.IdUtil; /*** @author crush* 郵箱發(fā)送實(shí)現(xiàn)類*/ @Service public class MailServiceImpl implements MailService {@AutowiredMailSenderConfig senderConfig;@AutowiredMailProperties mailProperties;@AutowiredMailMapper mailMapper;// 這里之前配置了一個(gè)線程池,上文的鏈接中有,就不說了哈// @Async("taskExecutor")@Overridepublic void send(MailDTO mailDTO) {String context = "<!DOCTYPE html>\n" +"<html lang=\"en\">\n" +"\n" +"<head>\n" +" <meta charset=\"UTF-8\" />\n" +" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n" +" <title>xxxx郵件</title>\n" +" <style>\n" +" body {\n" +" margin: 0;\n" +" padding: 0;\n" +" }\n" +" \n" +" .email {\n" +" position: relative;\n" +" width: 100%;\n" +" /* background-color: rgba(0, 0, 0, 1); */\n" +" }\n" +" \n" +" .main {\n" +" left: 0;\n" +" right: 0;\n" +" margin: auto;\n" +" width: 80%;\n" +" max-width: 800px;\n" +" box-sizing: content-box;\n" +" }\n" +" \n" +" .main .title {\n" +" /* color: white; */\n" +" display: inline-flex;\n" +" align-items: center;\n" +" }\n" +" \n" +" .main .title span {\n" +" margin: 0 10px;\n" +" }\n" +" \n" +" .main table {\n" +" width: 100%;\n" +" }\n" +" \n" +" .main table tbody td {\n" +" /* background-color: white; */\n" +" padding: 20px;\n" +" text-align: left;\n" +" border-bottom: 1px solid rgb(161, 161, 161);\n" +" }\n" +" \n" +" tfoot td p {\n" +" color: rgb(161, 161, 161);\n" +" font-size: 13px;\n" +" }\n" +" \n" +" a {\n" +" color: rgb(161, 161, 161);\n" +" text-decoration: none;\n" +" }\n" +" \n" +" a:hover {\n" +" border-bottom: 1px solid rgb(161, 161, 161);\n" +" }\n" +" </style>\n" +"</head>\n" +"\n" +"<body>\n" +" <div class=\"email\">\n" +" <div class=\"main\">\n" +" <table>\n" +" <thead>\n" +" <tr>\n" +" <td>\n" +" <h1 class=\"title\">\n" +" <img width=\"60\" src=\"xxxxx\" alt=\"\" />\n" +" <span>" + mailDTO.getTitle() + "</span>\n" +" </h1>\n" +" </td>\n" +" </tr>\n" +" </thead>\n" +" <tbody>\n" +" <tr>\n" +" <td>\n" +" " + mailDTO.getContent() + "\n" +" </td>\n" +" </tr>\n" +" </tbody>\n" +" <tfoot>\n" +" <tr>\n" +" <td>\n" +" <p>郵件由系統(tǒng)自動(dòng)發(fā)送,請勿直接回復(fù)。</p>\n" +" <p>官方網(wǎng)站:\n" +" <a href=\"https://blog.csdn.net/weixin_45821811?spm=1000.2115.3001.5343\">寧在春博客</a>\n" +" </p>\n" +" </td>\n" +" </tr>\n" +" </tfoot>\n" +" </table>\n" +" </div>\n" +" </div>\n" +"</body>\n" +"\n" +"</html>";JavaMailSenderImpl mailSender = senderConfig.getSender();//創(chuàng)建一個(gè)SimpleMailMessage對象MimeMessage mimeMessage = mailSender.createMimeMessage();//需要?jiǎng)?chuàng)建一個(gè)MimeMessageHelper對象,相關(guān)參數(shù)和簡單郵件類似try {MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);//發(fā)件人helper.setFrom(mailSender.getUsername());//收件人 這個(gè)收件人可以是數(shù)組的,只是我這只需要單個(gè) 就沒多做了。helper.setTo(mailDTO.getMail());helper.setSubject("驗(yàn)證碼");//將郵件內(nèi)容設(shè)置為html格式// 發(fā)送helper.setText( context, true);mailSender.send(mimeMessage);} catch (MessagingException e) {e.printStackTrace();}}// 添加就清空初始化的信息,重新初始化一遍即可。@Overridepublic boolean addMailPerson(MailPO mailPO) {if(mailMapper.insert(mailPO)>0){senderConfig.clear();senderConfig.buildMailSender();return true;}return false;} }用到的MailDto
/*** @author crush* 郵箱發(fā)送-前端傳輸參數(shù)*/ @Data public class MailDTO implements Serializable {/*** 接受郵箱賬戶*/private String mail;/*** 郵箱標(biāo)題*/private String title;/** * 要發(fā)送的內(nèi)容*/private String content; }2.4、MailSenderConfig 配置類
/*** @author crush*/ @Slf4j @Component @AllArgsConstructor public class MailSenderConfig {private final List<JavaMailSenderImpl> senderList;private final MailProperties mailProperties;private final MailMapper mailMapper;/*** 初始化 sender* PostConstruct注解用于需要在依賴注入完成后執(zhí)行任何初始化的方法。 必須在類投入使用之前調(diào)用此方法* 因?yàn)閯傞_始我覺得這種方式(@PostConstruct) 不合適,就是沒能做到修改了馬上就能用的那種感覺。* 但是后來寫完才發(fā)現(xiàn),其實(shí)只要每次添加新的郵件發(fā)送人時(shí),都重新初始化一次就可以了。* 后來我又用啟動(dòng)事件監(jiān)聽器。@PostConstruct 后來就沒去測試了。* 理論添加、修改完 調(diào)用這個(gè)初始化方法就可以了。*/ // @PostConstructpublic void buildMailSender() {log.info("初始化mailSender");List<MailPO> mails = mailMapper.selectList(new QueryWrapper<MailPO>().eq("state", 1));/*** 需求:原本就是打算做成一個(gè)動(dòng)態(tài)的郵件發(fā)送人,因?yàn)槿绻偸怯靡粋€(gè)郵件發(fā)送驗(yàn)證碼或者是那種打擾短信,速度一旦太過于頻繁,就會造成郵件發(fā)送錯(cuò)誤。* 思路:從數(shù)據(jù)庫中拿到所有可用的郵件發(fā)送人,然后封裝起來,之后發(fā)送郵件時(shí),再進(jìn)行隨機(jī)的選擇即可。* 另外一種方式就是這是動(dòng)態(tài)的。* 最后就是加個(gè)兜底的,如果數(shù)據(jù)庫中查詢不到郵件發(fā)送人,我們使用配置文件中的發(fā)送郵件的配置。*/if(mails!=null&&!mails.isEmpty()){mails.forEach(mail -> {JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();javaMailSender.setDefaultEncoding(mail.getDefaultEncoding());javaMailSender.setHost(mail.getEmailHost());javaMailSender.setPort(mail.getEmailPort());javaMailSender.setProtocol(mail.getProtocol());javaMailSender.setUsername(mail.getEmailUsername());javaMailSender.setPassword(mail.getEmailPassword());// 添加數(shù)據(jù)senderList.add(javaMailSender);});}else{JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();javaMailSender.setDefaultEncoding(mailProperties.getDefaultEncoding());javaMailSender.setHost(mailProperties.getHost());javaMailSender.setPort(mailProperties.getPort());javaMailSender.setProtocol(mailProperties.getProtocol());javaMailSender.setUsername(mailProperties.getUsername());javaMailSender.setPassword(mailProperties.getPassword());// 添加數(shù)據(jù)senderList.add(javaMailSender);}}/*** 獲取MailSender** @return CustomMailSender*/public JavaMailSenderImpl getSender() {if (senderList.isEmpty()) {buildMailSender();}// 隨機(jī)返回一個(gè)JavaMailSenderreturn senderList.get(new Random().nextInt(senderList.size()));}/*** 清理 sender*/public void clear() {senderList.clear();} }2.5、監(jiān)聽器
一兩句沒啥說的,可以直接通過idea進(jìn)去看源碼上的doc注解。下次再一起研究。
/*** 初始化操作* 目前只定義了動(dòng)態(tài)設(shè)置郵件發(fā)送人的操作* @Author: crush* @Date: 2021-11-26 19:51* version 1.0*/ @Slf4j @Configuration @Order(Ordered.HIGHEST_PRECEDENCE) public class StartListener implements ApplicationListener<ApplicationStartedEvent> {MailSenderConfig mailSenderConfig;public StartListener(MailSenderConfig mailSenderConfig) {this.mailSenderConfig = mailSenderConfig;}@SneakyThrows@Overridepublic void onApplicationEvent(@NotNull ApplicationStartedEvent event) {this.mailSenderConfig.buildMailSender();} }2.6、controller
/*** @Author: crush* @Date: 2021-11-26 16:10* version 1.0*/ @RestController @RequestMapping("/email") public class MailController {@Autowiredprivate MailService mailService;@PostMapping("/send")public String send(@RequestBody MailDTO mailDTO){mailService.send(mailDTO);return "發(fā)送成功!!!可能會稍有延遲,請查看郵箱信息!!";}@PostMapping("/addConfig")public String addMailPerson(@RequestBody MailPO mailPO){String message=mailService.addMailPerson(mailPO)?"添加成功!!!不過,請注意:可能會有延遲":"添加失敗,請稍后重試!!";return message;}}三、測試
模板大致就是如下狀態(tài)吧。
?
是添加進(jìn)去的
多點(diǎn)了一次哈。
我再點(diǎn)擊發(fā)送郵件,因?yàn)槭请S機(jī)數(shù)的方式,我們多測試幾次,總會用到這個(gè)錯(cuò)誤的郵件發(fā)送人的,用到了就表示我們已經(jīng)成功啦哈。
因?yàn)樘砑拥碾S便輸入的,肯定是失敗的哈。但是可以確定我們用到了我們項(xiàng)目啟動(dòng)后加入的郵件發(fā)送人啦。 你們可以填入爭取的試一試。
結(jié)束了結(jié)束啦。
沒寫小demo,沒啥源碼。
后語
大家一起加油!!!如若文章中有不足之處,請大家及時(shí)指出,在此鄭重感謝。
紙上得來終覺淺,絕知此事要躬行。
大家好,我是博主寧在春:主頁
一名喜歡文藝卻踏上編程這條道路的小青年。
希望:我們,待別日相見時(shí),都已有所成。
難得回到后端肝篇文,又拾起后端了,之后還會接著寫Vue的,肯定會把專欄寫完的。
總結(jié)
以上是生活随笔為你收集整理的你有没有觉得邮件发送人固定配置在yml文件中是不妥当的呢?SpringBoot 动态设置邮件发送人的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 「后端小伙伴来学前端了」Vue中学会使用
- 下一篇: 「后端小伙伴来学前端了」Vue-Rout