当前位置:   article > 正文

邮件发送功能(springBoot之自定义启动器)手把手教你制作邮箱_spring-boot-starter-mail

spring-boot-starter-mail

目录

一、介绍stater

        1、stater的理念:

        2、stater的实现:

        3、stater的原理图:

二、 java操作邮件(邮件的使用)

         步骤:

                     1、导入依赖

                     2、重写yml资源文件

                     3、写好测试类

                     4、进行测试

三、邮箱的制作(自定义启动器)

步骤:

1、先导入依赖

2、创建yml文件

获取授权码链接:什么是授权码,它又是如何设置?_QQ邮箱帮助中心

3、创建实体类资源文件

4、定义一个发送接口,并且实现接口

5、进行测试

四、使用邮箱

        1、提高邮箱使用灵活性

                 步骤:

                          1、导入yml文件注入依赖

                          2、在resource文件下添加文件

        2、将整个项目打包成jar包

        3、到之前的项目中导入邮箱依赖(必须使用同一个本地仓库)

        4、在测试类中加入注解

        5、进行测试:运行成功

五、结合redis实现操作

          1、步骤

                     1、导入操作redis的依赖

                     2、在applicaion.yml资源文件中加入redis资源

                     3、将帮助类写入到项目中

                     4、新建一个实体类和控制类

​​          2、优化邮箱使用

                    解决方法:

                    步骤:


一、介绍stater

        1、stater的理念:

starter会把所有用到的依赖都给包含进来,避免了开发者自己去引入依赖所带来的麻烦。 需要注意的是不同的starter是为了解决不同的依赖,所以它们内部的实现可能会有很大的差异,例如jpa的starter和Redis的starter可能实现就不一样,这是因为starter的本质在于synthesize, 这是一层在逻辑层面的抽象,也许这种理念有点类似于Docker,因为它们都是在做一个“包装”的操作。

        2、stater的实现:

虽然不同的starter实现起来各有差异, 但是他们基本上都会使用到两个相同的内容:ConfigurationProperties和AutoConfiguration。 因为SpringBoot坚信“约定大于配置”这一理念,所以我们使用ConfigurationProperties来保存我们的配置, 并且这些配置都可以有一个默认值,即在我们没有主动覆写原始配置的情况下,默认值就会生效,这在很多情况下是非常有用的。除此之外,starter的ConfigurationProperties还使得所有的配置属性被聚集到一个文件中 (一般在resources目录下的application.properties),这样我们就告别了Spring项目中XML地狱。

        3、stater的原理图:

注意:其中最关键的是配置文件,用户可以自定义配置文件将自己的邮箱地址写入,以便提高邮箱灵活性

二、 java操作邮件(邮件的使用)

         步骤:

                     1、导入依赖

  1. <dependency>  
  2. <groupId>org.springframework.boot</groupId>  
  3. <artifactId>spring-boot-starter-mail</artifactId>
  4. </dependency>

                     2、重写yml资源文件

spring:
  application:
    name: springBoot_06
  mail:
    host: smtp.qq.com
    username: 自己qq@qq.com
    password: exgdllmxqrhrieae
    properties:
     mail:
      smtp:
       auth: true
       starttls:
        enable: true
        required: true

                     3、写好测试类

  1. package com.zj.code;
  2. import org.junit.jupiter.api.Test;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.boot.test.context.SpringBootTest;
  5. import org.springframework.mail.SimpleMailMessage;
  6. import org.springframework.mail.javamail.JavaMailSender;
  7. @SpringBootTest
  8. class SpringBoot06ApplicationTests {
  9. @Autowired
  10. JavaMailSender mailSender;
  11. @Test
  12. void contextLoads() {
  13. SimpleMailMessage message = new SimpleMailMessage();
  14. message.setFrom("1551506470@qq.com");
  15. message.setTo("1551506470@qq.com");
  16. message.setSubject("主题:简单邮件");
  17. message.setText("测试邮件内容");
  18. mailSender.send(message);
  19. }
  20. }

注意:在测试类中特别要注意的地方就是要将以下注解打上

@Autowired
JavaMailSender mailSender;

                     4、进行测试

测试成功

三、邮箱的制作(自定义启动器)

步骤:

1、先导入依赖

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-mail</artifactId>
  4. </dependency>

2、创建yml文件

注意:在yml文件中四个属性的意思分别是

email:
 enable: true  --是否开启邮箱验证
 host: smtp.qq.com  --主机
 username:自己qq@qq.com --账号(发送方)
 password: uqoimlnpljuqihdd  --密码(注意,此处这里是授权码,而不是密码)

获取授权码链接:什么是授权码,它又是如何设置?_QQ邮箱帮助中心

3、创建实体类资源文件

EmailProperties:
  1. package com.yzm.yzmspringbootstarter;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.boot.context.properties.ConfigurationProperties;
  7. import org.springframework.stereotype.Component;
  8. /**
  9. * @author T440s
  10. */
  11. @NoArgsConstructor
  12. @AllArgsConstructor
  13. @Data
  14. @ConfigurationProperties(prefix= "email")
  15. public class EmailProperties {
  16. private String host;
  17. private String username;
  18. private String password;
  19. private String enable;
  20. }

关于四个注解的说明:

@NoArgsConstructor:无参构造
@AllArgsConstructor:有参构造
@Data:get和set方法
@ConfigurationProperties(prefix= "email")作用:根据属性完成yml注入(需要bean对象被spring容器管理)

4、定义一个发送接口,并且实现接口

接口:EmailSender:
  1. package com.yzm.yzmspringbootstarter;
  2. public interface EmailSender {
  3. String sendText(String receiver);
  4. }

接口实现类:

EmailSenderImpl:
  1. package com.yzm.yzmspringbootstarter;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
  5. import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  6. import org.springframework.boot.context.properties.EnableConfigurationProperties;
  7. import org.springframework.context.annotation.Configuration;
  8. import org.springframework.mail.SimpleMailMessage;
  9. import org.springframework.mail.javamail.JavaMailSenderImpl;
  10. import java.util.Properties;
  11. @Configuration
  12. @Slf4j
  13. @EnableConfigurationProperties(value = EmailProperties.class)
  14. @ConditionalOnProperty(prefix = "email", value = "enable", havingValue = "true")
  15. public class EmailSenderImpl implements EmailSender {
  16. private final EmailProperties emailProperties;
  17. private final JavaMailSenderImpl mailSender;
  18. @Autowired
  19. public EmailSenderImpl(EmailProperties emailProperties) {
  20. this.emailProperties = emailProperties;
  21. mailSender = new JavaMailSenderImpl();
  22. mailSender.setHost(emailProperties.getHost());
  23. mailSender.setUsername(emailProperties.getUsername());
  24. mailSender.setPassword(emailProperties.getPassword());
  25. mailSender.setDefaultEncoding("Utf-8");
  26. Properties p = new Properties();
  27. p.setProperty("mail.smtp.auth", "true");
  28. p.setProperty("mail.smtp.starttl .enable", "true");
  29. p.setProperty("mail.smtp.starttls.required", "true");
  30. mailSender.setJavaMailProperties(p);
  31. }
  32. @Override//此方法是发送验证码,并且是要显示接受方
  33. public String sendText(String receiver) {
  34. SimpleMailMessage message = new SimpleMailMessage();
  35. message.setFrom(emailProperties.getUsername());
  36. message.setTo(receiver);
  37. message.setSubject("网站验证码");
  38. message.setText("aabb");
  39. mailSender.send(message);
  40. return "aabb";
  41. }
  42. }

关于此类四个注解的说明:

@Configuration:将此类声明为组件,并且交给spring进行管理
@Slf4j:日志输出
@EnableConfigurationProperties(value = EmailProperties.class)完成对应元素组件化
@ConditionalOnProperty(prefix = "email", value = "enable", havingValue = "true")

控制邮件功能是否可用

5、进行测试

测试类:

  1. package com.yzm.yzmspringbootstarter;
  2. import org.junit.jupiter.api.Test;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.boot.test.context.SpringBootTest;
  5. @SpringBootTest
  6. class YzmSpringBootStarterApplicationTests {
  7. @Autowired
  8. private EmailSender sender;
  9. @Test
  10. void contextLoads() {
  11. sender.sendText("1551506470@qq.com");
  12. }
  13. }

测试成功

注意:在制作邮箱的过程中需要注意两个问题:

1、在yml文件中的email中的格式要规范(中间要空一格)

()()email:
 enable: true
 host: smtp.qq.com
 username: 自己qq@qq.com
 password: uqoimlnpljuqihdd

2、账号以及收件方的都是写qq号码+qq.com,而不是创建邮箱时的账号

username: 自己qq@qq.com

四、使用邮箱

        1、提高邮箱使用灵活性

由于每个人的邮箱都不一样,不可能将发送和收件人的邮箱以及是否启用邮箱都固定,所以要将yml中的内容进行更改,提高邮箱使用灵活性。

                 步骤:

                          1、导入yml文件注入依赖

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-configuration-processor</artifactId>
  4. <optional>true</optional>
  5. </dependency>
  6. <plugin>
  7. <groupId>org.springframework.boot</groupId>
  8. <artifactId>spring-boot-maven-plugin</artifactId>
  9. <version>2.4.1</version>
  10. <configuration><classifier>exec</classifier></configuration>
  11. </plugin>

                          2、在resource文件下添加文件

META-INF > spring.factories

文件内容:

org.springframework.boot.autoconfigure.

EnableAutoConfiguration=com.yzm.yzmspringbootstarter.EmailSenderImpl

此段代码的说明:当整个项目运行时,对应类就会随着运行

查看是否添加文件成功:

        2、将整个项目打包成jar包

最后到本地仓库中查看有没有yzm这个文件夹(这个名字就是自己命名的)可以在pom文件中查看

<modelVersion>4.0.0</modelVersion>
<groupId>com.yzm</groupId>
<artifactId>yzm-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>yzm-spring-boot-starter</name>
<description>yzm-spring-boot-starter</description>

 打包成功。

        3、到之前的项目中导入邮箱依赖(必须使用同一个本地仓库)

<dependency>
    <groupId>com.yzm</groupId>
    <artifactId>yzm-spring-boot-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

        4、在测试类中加入注解

@Autowired
private EmailSender emailSender;

导入此注解时会进行报错,原因:没有配置资源文件

spring:
  application:
    name: springBoot_06
email:
  host: smtp.qq.com
  username: 自己qq@qq.com
  password: exgdllmxqrhrieae

 加了基本配置文件后,还是报错(原因:没有开启邮箱,有提示说明导入依赖成功)

 导入成功

        5、进行测试:运行成功

五、结合redis实现操作

       由于现在数据繁多,不可能每次都会进入到数据库拿取数据,这时候就会运用缓存来提高程序运行速度。   

          1、步骤

                     1、导入操作redis的依赖

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-data-redis</artifactId>
  4. </dependency>

                     2、在applicaion.yml资源文件中加入redis资源

  1. redis:
  2. database: 0 #数据库索引
  3. host: 127.0.0.1 #主机位置
  4. port: 6379 #端口
  5. password: #密码
  6. jedis:
  7. pool:
  8. max-active: 8 #最大连接数
  9. max-wait: -1 #最大阻塞等待时间(负数表示没限制)
  10. max-idle: 8 #最大空闲
  11. min-idle: 0 #最小空闲
  12. timeout: 10000 #连接超时时间

                     3、将帮助类写入到项目中

conf--->CrossConfiguration

  1. package com.zj.code.conf;
  2. import org.springframework.context.annotation.Configuration;
  3. import org.springframework.web.servlet.config.annotation.CorsRegistry;
  4. import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
  5. /**
  6. * @author 银喾
  7. */
  8. @Configuration
  9. public class CrossConfiguration extends WebMvcConfigurerAdapter {
  10. @Override
  11. public void addCorsMappings(CorsRegistry registry) {
  12. registry
  13. /*可以跨域的路径*/
  14. .addMapping("/**")
  15. /*可以跨域的ip*/
  16. .allowedOrigins("*")
  17. /*可以跨域的方法*/
  18. .allowedMethods("*")
  19. /*设置预检请求多就失效*/
  20. .maxAge(6000)
  21. /*允许携带的头部*/
  22. .allowedHeaders("*");
  23. }
  24. }
conf--->RedisConfiguration
  1. package com.zj.code.conf;
  2. import org.springframework.cache.CacheManager;
  3. import org.springframework.cache.annotation.CachingConfigurerSupport;
  4. import org.springframework.cache.annotation.EnableCaching;
  5. import org.springframework.cache.interceptor.KeyGenerator;
  6. import org.springframework.context.annotation.Bean;
  7. import org.springframework.context.annotation.Configuration;
  8. import org.springframework.context.annotation.Primary;
  9. import org.springframework.data.redis.cache.RedisCacheConfiguration;
  10. import org.springframework.data.redis.cache.RedisCacheManager;
  11. import org.springframework.data.redis.connection.RedisConnectionFactory;
  12. import org.springframework.data.redis.core.RedisTemplate;
  13. import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
  14. import org.springframework.data.redis.serializer.RedisSerializationContext;
  15. import org.springframework.data.redis.serializer.RedisSerializer;
  16. import org.springframework.data.redis.serializer.StringRedisSerializer;
  17. import org.springframework.util.ClassUtils;
  18. import java.lang.reflect.Array;
  19. import java.lang.reflect.Method;
  20. import java.time.Duration;
  21. /**
  22. * @author 银喾
  23. */
  24. @Configuration
  25. @EnableCaching
  26. public class RedisConfiguration extends CachingConfigurerSupport {
  27. @Bean
  28. @Primary
  29. CacheManager cacheManager(RedisConnectionFactory factory) {
  30. RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
  31. .computePrefixWith(cacheName -> cacheName + ":-cache-:")
  32. /*设置缓存过期时间*/
  33. .entryTtl(Duration.ofHours(1))
  34. /*禁用缓存空值,不缓存null校验*/
  35. .disableCachingNullValues()
  36. /*设置CacheManager的值序列化方式为json序列化,可使用加入@Class属性*/
  37. .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(
  38. new GenericJackson2JsonRedisSerializer()
  39. ));
  40. /*使用RedisCacheConfiguration创建RedisCacheManager*/
  41. RedisCacheManager manager = RedisCacheManager.builder(factory)
  42. .cacheDefaults(cacheConfiguration)
  43. .build();
  44. return manager;
  45. }
  46. @Bean
  47. @Primary
  48. public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
  49. RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
  50. redisTemplate.setConnectionFactory(factory);
  51. RedisSerializer stringSerializer = new StringRedisSerializer();
  52. /* key序列化 */
  53. redisTemplate.setKeySerializer(stringSerializer);
  54. /* value序列化 */
  55. redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
  56. /* Hash key序列化 */
  57. redisTemplate.setHashKeySerializer(stringSerializer);
  58. /* Hash value序列化 */
  59. redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
  60. redisTemplate.afterPropertiesSet();
  61. return redisTemplate;
  62. }
  63. @Bean
  64. @Primary
  65. @Override
  66. public KeyGenerator keyGenerator() {
  67. return (Object target, Method method, Object... params) -> {
  68. final int NO_PARAM_KEY = 0;
  69. final int NULL_PARAM_KEY = 53;
  70. StringBuilder key = new StringBuilder();
  71. /* Class.Method: */
  72. key.append(target.getClass().getSimpleName())
  73. .append(".")
  74. .append(method.getName())
  75. .append(":");
  76. if (params.length == 0) {
  77. return key.append(NO_PARAM_KEY).toString();
  78. }
  79. int count = 0;
  80. for (Object param : params) {
  81. /* 参数之间用,进行分隔 */
  82. if (0 != count) {
  83. key.append(',');
  84. }
  85. if (param == null) {
  86. key.append(NULL_PARAM_KEY);
  87. } else if (ClassUtils.isPrimitiveArray(param.getClass())) {
  88. int length = Array.getLength(param);
  89. for (int i = 0; i < length; i++) {
  90. key.append(Array.get(param, i));
  91. key.append(',');
  92. }
  93. } else if (ClassUtils.isPrimitiveOrWrapper(param.getClass()) || param instanceof String) {
  94. key.append(param);
  95. } else {
  96. /*JavaBean一定要重写hashCode和equals*/
  97. key.append(param.hashCode());
  98. }
  99. count++;
  100. }
  101. return key.toString();
  102. };
  103. }
  104. }

util-->RedisUtil(由于内容过长,这个类在上一篇博客中有,建议到上篇博客摘要)

https://blog.csdn.net/m0_53151031/article/details/122831095?spm=1001.2014.3001.5501

                     4、新建一个实体类和控制类

pojo:

  1. package com.zj.code.pojo;
  2. import lombok.Data;
  3. @Data
  4. public class User {
  5. private String account;
  6. }
UserController:
  1. package com.zj.code.controller;
  2. import com.yzm.yzmspringbootstarter.EmailSender;
  3. import com.zj.code.pojo.User;
  4. import com.zj.code.util.RedisUtil;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.cache.annotation.CacheEvict;
  7. import org.springframework.cache.annotation.CachePut;
  8. import org.springframework.cache.annotation.Cacheable;
  9. import org.springframework.web.bind.annotation.GetMapping;
  10. import org.springframework.web.bind.annotation.RequestMapping;
  11. import org.springframework.web.bind.annotation.RestController;
  12. import java.util.concurrent.TimeUnit;
  13. @RestController
  14. @RequestMapping("/user")
  15. public class UserController {
  16. private EmailSender sender;
  17. @GetMapping("/register")
  18. public String register(User user) {
  19. if (user.getAccount().length() < 5) {
  20. return "不符合规则";
  21. }
  22. String yzm = RedisUtil.StringOps.get(user.getAccount());
  23. if (yzm == null) {
  24. yzm = sender.sendText(user.getAccount());
  25. RedisUtil.StringOps.setEx(user.getAccount(), yzm, 1, TimeUnit.MINUTES);
  26. return "验证码已发送";
  27. }
  28. return "验证码还是有效期";
  29. }
  30. /**
  31. * 判断当前验证码与缓存中的验证码一致
  32. * @param user 用户
  33. * @param yzm 当前验证码
  34. * @return 当前验证码与该用户在缓存中的验证是否是一致的
  35. */
  36. @GetMapping("/verify")
  37. public String verify(User user,String yzm) {
  38. String code = RedisUtil.StringOps.get(user.getAccount());
  39. if(code==null){
  40. return "验证码无效";
  41. }
  42. return code.equals(yzm)?"yes":"no";
  43. }
  44. }

运行之后出现一个错误:

 原因是没有打上自动注入注解

 运行成功

          2、优化邮箱使用

前言:在我们注册一个邮箱时,往往会出现注册缓慢,理想状态应该为先出现注册成功,在之后出现邮箱发送成功

                    解决方法:

1、消息队列

2、异步操作

 通常采取第二种方法,使用异步操作

                    步骤:

                                1、创建一个task类,专用来发送验证码

  1. package com.zj.code.util;
  2. import com.yzm.yzmspringbootstarter.EmailSender;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.scheduling.annotation.Async;
  5. import org.springframework.stereotype.Component;
  6. import java.util.concurrent.TimeUnit;
  7. @Component
  8. public class Task {
  9. @Autowired
  10. private EmailSender sender;
  11. @Async
  12. public void sendYzm(String account){
  13. String yzm = sender.sendText(account);
  14. RedisUtil.StringOps.setEx(account, yzm, 1, TimeUnit.MINUTES);
  15. }
  16. }

注意点:

一定要注入注解,不然会报错

其中

@Component(将此类声明为bean对象交给spring进行管理)

@Autowired(将其他类注入进来)

@Async(异步注解)这三个注解尤为重要

                                2、在启动类中注入开启异步注解

@EnableAsync

                                3、在controller类中注入task注解,

@Autowired
private Task task;

  1. package com.zj.code.controller;
  2. import com.yzm.yzmspringbootstarter.EmailSender;
  3. import com.zj.code.pojo.User;
  4. import com.zj.code.util.RedisUtil;
  5. import com.zj.code.util.Task;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.cache.annotation.CacheEvict;
  8. import org.springframework.cache.annotation.CachePut;
  9. import org.springframework.cache.annotation.Cacheable;
  10. import org.springframework.web.bind.annotation.GetMapping;
  11. import org.springframework.web.bind.annotation.RequestMapping;
  12. import org.springframework.web.bind.annotation.RestController;
  13. import java.util.concurrent.TimeUnit;
  14. @RestController
  15. @RequestMapping("/user")
  16. public class UserController {
  17. @Autowired
  18. private Task task;
  19. @GetMapping("/register")
  20. public String register(User user) {
  21. if (user.getAccount().length() < 5) {
  22. return "不符合规则";
  23. }
  24. String yzm = RedisUtil.StringOps.get(user.getAccount());
  25. if (yzm == null) {
  26. task.sendYzm(user.getAccount());
  27. return "验证码已发送";
  28. }
  29. return "验证码还是有效期";
  30. }
  31. /**
  32. * 判断当前验证码与缓存中的验证码一致
  33. * @param user 用户
  34. * @param yzm 当前验证码
  35. * @return 当前验证码与该用户在缓存中的验证是否是一致的
  36. */
  37. @GetMapping("/verify")
  38. public String verify(User user,String yzm) {
  39. String code = RedisUtil.StringOps.get(user.getAccount());
  40. if(code==null){
  41. return "验证码无效";
  42. }
  43. return code.equals(yzm)?"yes":"no";
  44. }
  45. }

                                4、进行测试

很明显和之前的运行结果进行比较得出,使用异步操作可以提高程序运行速度,对于此上,真正的验证码还没有发送。

今天的知识就分享到这了,希望能够帮助到大家,制作不易,点赞则是对我最大的鼓励。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/95375
推荐阅读
相关标签
  

闽ICP备14008679号