邮件发送功能(springBoot之自定义启动器)手把手教你制作邮箱
目录
一、介绍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、导入依赖
org.springframework.boot
spring-boot-starter-mail
2、重写yml资源文件
spring:application:name: springBoot_06mail:host: smtp.qq.comusername: 自己qq@qq.compassword: exgdllmxqrhrieaeproperties:mail:smtp:auth: truestarttls:enable: truerequired: true
3、写好测试类
package com.zj.code;import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;@SpringBootTest
class SpringBoot06ApplicationTests {@AutowiredJavaMailSender mailSender;@Testvoid contextLoads() {SimpleMailMessage message = new SimpleMailMessage();message.setFrom("1551506470@qq.com");message.setTo("1551506470@qq.com");message.setSubject("主题:简单邮件");message.setText("测试邮件内容");mailSender.send(message);}
}
注意:在测试类中特别要注意的地方就是要将以下注解打上
@Autowired JavaMailSender mailSender;
4、进行测试

测试成功
三、邮箱的制作(自定义启动器)
步骤:
1、先导入依赖
org.springframework.boot spring-boot-starter-mail
2、创建yml文件
注意:在yml文件中四个属性的意思分别是
email:enable: true --是否开启邮箱验证host: smtp.qq.com --主机username:自己qq@qq.com --账号(发送方)password: uqoimlnpljuqihdd --密码(注意,此处这里是授权码,而不是密码)
获取授权码链接:什么是授权码,它又是如何设置?_QQ邮箱帮助中心
3、创建实体类资源文件
EmailProperties:
package com.yzm.yzmspringbootstarter;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;/*** @author T440s*/@NoArgsConstructor
@AllArgsConstructor
@Data
@ConfigurationProperties(prefix= "email")
public class EmailProperties {private String host;private String username;private String password;private String enable;}
关于四个注解的说明:
@NoArgsConstructor:无参构造
@AllArgsConstructor:有参构造
@Data:get和set方法
@ConfigurationProperties(prefix= "email")作用:根据属性完成yml注入(需要bean对象被spring容器管理)
4、定义一个发送接口,并且实现接口
接口:EmailSender:
package com.yzm.yzmspringbootstarter;public interface EmailSender {String sendText(String receiver);
}
接口实现类:
EmailSenderImpl:
package com.yzm.yzmspringbootstarter;import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;import java.util.Properties;@Configuration
@Slf4j
@EnableConfigurationProperties(value = EmailProperties.class)
@ConditionalOnProperty(prefix = "email", value = "enable", havingValue = "true")
public class EmailSenderImpl implements EmailSender {private final EmailProperties emailProperties;private final JavaMailSenderImpl mailSender;@Autowiredpublic EmailSenderImpl(EmailProperties emailProperties) {this.emailProperties = emailProperties;mailSender = new JavaMailSenderImpl();mailSender.setHost(emailProperties.getHost());mailSender.setUsername(emailProperties.getUsername());mailSender.setPassword(emailProperties.getPassword());mailSender.setDefaultEncoding("Utf-8");Properties p = new Properties();p.setProperty("mail.smtp.auth", "true");p.setProperty("mail.smtp.starttl .enable", "true");p.setProperty("mail.smtp.starttls.required", "true");mailSender.setJavaMailProperties(p);}@Override//此方法是发送验证码,并且是要显示接受方public String sendText(String receiver) {SimpleMailMessage message = new SimpleMailMessage();message.setFrom(emailProperties.getUsername());message.setTo(receiver);message.setSubject("网站验证码");message.setText("aabb");mailSender.send(message);return "aabb";}}
关于此类四个注解的说明:
@Configuration:将此类声明为组件,并且交给spring进行管理
@Slf4j:日志输出
@EnableConfigurationProperties(value = EmailProperties.class)完成对应元素组件化
@ConditionalOnProperty(prefix = "email", value = "enable", havingValue = "true")控制邮件功能是否可用
5、进行测试
测试类:
package com.yzm.yzmspringbootstarter;import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
class YzmSpringBootStarterApplicationTests {@Autowiredprivate EmailSender sender;@Testvoid contextLoads() {sender.sendText("1551506470@qq.com");}
}

测试成功
注意:在制作邮箱的过程中需要注意两个问题:
1、在yml文件中的email中的格式要规范(中间要空一格)
()()email:enable: truehost: smtp.qq.comusername: 自己qq@qq.compassword: uqoimlnpljuqihdd
2、账号以及收件方的都是写qq号码+qq.com,而不是创建邮箱时的账号
username: 自己qq@qq.com
四、使用邮箱
1、提高邮箱使用灵活性
由于每个人的邮箱都不一样,不可能将发送和收件人的邮箱以及是否启用邮箱都固定,所以要将yml中的内容进行更改,提高邮箱使用灵活性。
步骤:
1、导入yml文件注入依赖
org.springframework.boot spring-boot-configuration-processor true org.springframework.boot spring-boot-maven-plugin 2.4.1 exec
2、在resource文件下添加文件
META-INF > spring.factories
文件内容:
org.springframework.boot.autoconfigure.
EnableAutoConfiguration=com.yzm.yzmspringbootstarter.EmailSenderImpl
此段代码的说明:当整个项目运行时,对应类就会随着运行
查看是否添加文件成功:

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

最后到本地仓库中查看有没有yzm这个文件夹(这个名字就是自己命名的)可以在pom文件中查看
4.0.0 com.yzm yzm-spring-boot-starter 0.0.1-SNAPSHOT yzm-spring-boot-starter yzm-spring-boot-starter
打包成功。

3、到之前的项目中导入邮箱依赖(必须使用同一个本地仓库)
com.yzm yzm-spring-boot-starter 0.0.1-SNAPSHOT
4、在测试类中加入注解
@Autowired private EmailSender emailSender;
导入此注解时会进行报错,原因:没有配置资源文件
spring:application:name: springBoot_06 email:host: smtp.qq.comusername: 自己qq@qq.compassword: exgdllmxqrhrieae

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

五、结合redis实现操作
由于现在数据繁多,不可能每次都会进入到数据库拿取数据,这时候就会运用缓存来提高程序运行速度。
1、步骤
1、导入操作redis的依赖
org.springframework.boot spring-boot-starter-data-redis
2、在applicaion.yml资源文件中加入redis资源
redis:database: 0 #数据库索引host: 127.0.0.1 #主机位置port: 6379 #端口password: #密码jedis:pool:max-active: 8 #最大连接数max-wait: -1 #最大阻塞等待时间(负数表示没限制)max-idle: 8 #最大空闲min-idle: 0 #最小空闲timeout: 10000 #连接超时时间
3、将帮助类写入到项目中
conf--->CrossConfiguration
package com.zj.code.conf;import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;/*** @author 银喾*/
@Configuration
public class CrossConfiguration extends WebMvcConfigurerAdapter {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry/*可以跨域的路径*/.addMapping("/**")/*可以跨域的ip*/.allowedOrigins("*")/*可以跨域的方法*/.allowedMethods("*")/*设置预检请求多就失效*/.maxAge(6000)/*允许携带的头部*/.allowedHeaders("*");}}
conf--->RedisConfiguration
package com.zj.code.conf;import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.ClassUtils;import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.time.Duration;/*** @author 银喾*/
@Configuration
@EnableCaching
public class RedisConfiguration extends CachingConfigurerSupport {@Bean@PrimaryCacheManager cacheManager(RedisConnectionFactory factory) {RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().computePrefixWith(cacheName -> cacheName + ":-cache-:")/*设置缓存过期时间*/.entryTtl(Duration.ofHours(1))/*禁用缓存空值,不缓存null校验*/.disableCachingNullValues()/*设置CacheManager的值序列化方式为json序列化,可使用加入@Class属性*/.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));/*使用RedisCacheConfiguration创建RedisCacheManager*/RedisCacheManager manager = RedisCacheManager.builder(factory).cacheDefaults(cacheConfiguration).build();return manager;}@Bean@Primarypublic RedisTemplate redisTemplate(RedisConnectionFactory factory) {RedisTemplate redisTemplate = new RedisTemplate();redisTemplate.setConnectionFactory(factory);RedisSerializer stringSerializer = new StringRedisSerializer();/* key序列化 */redisTemplate.setKeySerializer(stringSerializer);/* value序列化 */redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());/* Hash key序列化 */redisTemplate.setHashKeySerializer(stringSerializer);/* Hash value序列化 */redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.afterPropertiesSet();return redisTemplate;}@Bean@Primary@Overridepublic KeyGenerator keyGenerator() {return (Object target, Method method, Object... params) -> {final int NO_PARAM_KEY = 0;final int NULL_PARAM_KEY = 53;StringBuilder key = new StringBuilder();/* Class.Method: */key.append(target.getClass().getSimpleName()).append(".").append(method.getName()).append(":");if (params.length == 0) {return key.append(NO_PARAM_KEY).toString();}int count = 0;for (Object param : params) {/* 参数之间用,进行分隔 */if (0 != count) {key.append(',');}if (param == null) {key.append(NULL_PARAM_KEY);} else if (ClassUtils.isPrimitiveArray(param.getClass())) {int length = Array.getLength(param);for (int i = 0; i < length; i++) {key.append(Array.get(param, i));key.append(',');}} else if (ClassUtils.isPrimitiveOrWrapper(param.getClass()) || param instanceof String) {key.append(param);} else {/*JavaBean一定要重写hashCode和equals*/key.append(param.hashCode());}count++;}return key.toString();};}}
util-->RedisUtil(由于内容过长,这个类在上一篇博客中有,建议到上篇博客摘要)
https://blog.csdn.net/m0_53151031/article/details/122831095?spm=1001.2014.3001.5501
4、新建一个实体类和控制类
pojo:
package com.zj.code.pojo;import lombok.Data;@Data
public class User {private String account;
}
UserController:
package com.zj.code.controller;import com.yzm.yzmspringbootstarter.EmailSender;
import com.zj.code.pojo.User;
import com.zj.code.util.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.concurrent.TimeUnit;@RestController
@RequestMapping("/user")
public class UserController {private EmailSender sender;@GetMapping("/register")public String register(User user) {if (user.getAccount().length() < 5) {return "不符合规则";}String yzm = RedisUtil.StringOps.get(user.getAccount());if (yzm == null) {yzm = sender.sendText(user.getAccount());RedisUtil.StringOps.setEx(user.getAccount(), yzm, 1, TimeUnit.MINUTES);return "验证码已发送";}return "验证码还是有效期";}/*** 判断当前验证码与缓存中的验证码一致* @param user 用户* @param yzm 当前验证码* @return 当前验证码与该用户在缓存中的验证是否是一致的*/@GetMapping("/verify")public String verify(User user,String yzm) {String code = RedisUtil.StringOps.get(user.getAccount());if(code==null){return "验证码无效";}return code.equals(yzm)?"yes":"no";}}
运行之后出现一个错误:

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

运行成功

2、优化邮箱使用
前言:在我们注册一个邮箱时,往往会出现注册缓慢,理想状态应该为先出现注册成功,在之后出现邮箱发送成功
解决方法:
1、消息队列
2、异步操作
通常采取第二种方法,使用异步操作
步骤:
1、创建一个task类,专用来发送验证码
package com.zj.code.util;import com.yzm.yzmspringbootstarter.EmailSender;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;import java.util.concurrent.TimeUnit;@Component
public class Task {@Autowiredprivate EmailSender sender;@Asyncpublic void sendYzm(String account){String yzm = sender.sendText(account);RedisUtil.StringOps.setEx(account, yzm, 1, TimeUnit.MINUTES);}}
注意点:
一定要注入注解,不然会报错
其中
@Component(将此类声明为bean对象交给spring进行管理)
@Autowired(将其他类注入进来)
@Async(异步注解)这三个注解尤为重要
2、在启动类中注入开启异步注解
@EnableAsync

3、在controller类中注入task注解,
@Autowired private Task task;
package com.zj.code.controller;import com.yzm.yzmspringbootstarter.EmailSender;
import com.zj.code.pojo.User;
import com.zj.code.util.RedisUtil;
import com.zj.code.util.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.concurrent.TimeUnit;@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate Task task;@GetMapping("/register")public String register(User user) {if (user.getAccount().length() < 5) {return "不符合规则";}String yzm = RedisUtil.StringOps.get(user.getAccount());if (yzm == null) {task.sendYzm(user.getAccount());return "验证码已发送";}return "验证码还是有效期";}/*** 判断当前验证码与缓存中的验证码一致* @param user 用户* @param yzm 当前验证码* @return 当前验证码与该用户在缓存中的验证是否是一致的*/@GetMapping("/verify")public String verify(User user,String yzm) {String code = RedisUtil.StringOps.get(user.getAccount());if(code==null){return "验证码无效";}return code.equals(yzm)?"yes":"no";}}
4、进行测试

很明显和之前的运行结果进行比较得出,使用异步操作可以提高程序运行速度,对于此上,真正的验证码还没有发送。
今天的知识就分享到这了,希望能够帮助到大家,制作不易,点赞则是对我最大的鼓励。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
