目录
4. 修改配置文件application.yml,添加相关配置信息
一、简介
用户注册系统时,一般会以邮箱进行关联注册,需要用户输入邮箱地址以获取随机验证码,然后在注册页面输入该验证码并完善其他相关注册信息点击注册,完成注册。
基于SpringBoot的后端开发项目实现的逻辑分为两步:
- 向邮箱发送随机验证码;
- 收到用户输入验证码进行校验完成注册;
二、代码实现
1. 添加pom依赖
<!-- spring data redis 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- hutool工具包依赖-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.5.7</version>
</dependency>
<!-- mail依赖-->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
<!-- 模板引擎依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
2. 创建邮件发送信息传输类、授权信息类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class EmailDto {
/**
* 发送邮箱列表
*/
private List<String> tos;
/**
* 主题
*/
private String subject;
/**
* 内容
*/
private String content;
}
@ApiModel(value = "授权用户信息")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class AuthUserDto {
@ApiModelProperty(value = "用户名")
private String username;
@ApiModelProperty(value = "密码")
private String password;
@ApiModelProperty(value = "临时登录凭证")
private String code;
@ApiModelProperty(value = "邮箱")
private String email ;
}
3. 创建邮箱服务接口和实现类
public interface EmailService {
/**
* 发送邮件
*
* @param emailDto 邮箱列表
*/
void send(EmailDto emailDto);
}
@Service
@RequiredArgsConstructor
public class EmailServiceImpl implements EmailService {
@Value("${spring.mail.email}")
private String email;
@Value("${spring.mail.host}")
private String host;
@Value("${spring.mail.port}")
private String port;
@Value("${spring.mail.username}")
private String username;
@Value("${spring.mail.password}")
private String password;
@Override
public void send(EmailDto emailDto) {
// 读取邮箱配置
if (email == null || host == null || port == null || username == null || password == null) {
throw new RuntimeException("邮箱配置异常");
}
// 设置
MailAccount account = new MailAccount();
account.setHost(host);
account.setPort(Integer.parseInt(port));
// 设置发送人邮箱
account.setFrom(username + "<" + email + ">");
// 设置发送人名称
account.setUser(username);
// 设置发送授权码
account.setPass(password);
account.setAuth(true);
// ssl方式发送
account.setSslEnable(true);
// 使用安全连接
account.setStarttlsEnable(true);
// 发送邮件
try {
int size = emailDto.getTos().size();
Mail.create(account)
.setTos(emailDto.getTos().toArray(new String[size]))
.setTitle(emailDto.getSubject())
.setContent(emailDto.getContent())
.setHtml(true)
//关闭session
.setUseGlobalSession(false)
.send();
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
}
4. 修改配置文件application.yml,添加相关配置信息
mail:
# 负责发送验证码的邮箱
email: XXXX@126.com
host: smtp.126.com
port: 465
username: XXXX
# 授权码是用于登录第三方邮件客户端的专用密码。
password: XXXXXXXXX
#邮箱验证码有效时间/秒
code:
expiration: 300
此处授权密码需要在邮箱中申请配置,如下获取一个授权密码:【登录邮箱】-【设置】,springboot即可通过邮箱+授权码自动发送验证码邮件:
5. 创建邮件模板
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<style>
@page {
margin: 0;
}
</style>
</head>
<body>
<div class="header">
<div style="padding: 10px;padding-bottom: 0px;">
<p style="margin-bottom: 10px;padding-bottom: 0px;">尊敬的用户,您好:</p>
<p style="text-indent: 2em; margin-bottom: 10px;">您正在注册【XXX平台】账号,您的验证码为:</p>
<p class="code-text">${code}</p>
<div class="footer">
</div>
</div>
</div>
</body>
</html>
<style lang="css">
body {
margin: 0px;
padding: 0px;
font: 100% SimSun, Microsoft YaHei, Times New Roman, Verdana, Arial, Helvetica, sans-serif;
color: #000;
}
.header {
height: auto;
width: 820px;
min-width: 820px;
margin: 0 auto;
margin-top: 20px;
border: 1px solid #eee;
}
.code-text {
text-align: center;
font-family: Times New Roman;
font-size: 22px;
color: #C60024;
padding: 20px 0px;
margin-bottom: 10px;
font-weight: bold;
background: #ebebeb;
}
.footer {
margin: 0 auto;
z-index: 111;
width: 800px;
margin-top: 30px;
border-top: 1px solid #DA251D;
}
</style>
6. 创建功能服务接口与实现类
public interface AuthService {
/**
* 向指定邮箱发送验证码
*
* @param email 邮箱号
* @return 结果
*/
RespBean sendMailCode(String email);
/**
* 注册
*
* @param authUserDto 认证用户请求信息
* @return 是否成功
*/
RespBean register(AuthUserDto authUserDto);
}
主要实现两个功能
- 向邮箱发送随机验证码;sendMailCode
- 收到用户输入验证码进行校验完成注册;register
@Service
@RequiredArgsConstructor
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class AuthServiceImpl implements AuthService {
@Value("${code.expiration}")
private Long expiration;
// private final IAdminService adminService;
// private final RedisUtils redisUtils;
private final EmailService emailService;
private final PasswordEncoder passwordEncoder;
@Autowired
private RedisTemplate<String,Object> redisTemplate;
@Autowired
private AdminServiceImpl adminService;
@Override
@Transactional(rollbackFor = Exception.class)
public RespBean register(AuthUserDto authUserDto) {
ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
// 通过email获取redis中的code
Object value = valueOperations.get(authUserDto.getEmail());
if (value == null || !value.toString().equals(authUserDto.getCode())) {
return RespBean.error("无效验证码!");
}
// 如果前端没有传入用户名,则以邮箱号作为用户名进行注册
String userName = StringUtils.isEmpty(authUserDto.getUsername()) ? authUserDto.getEmail() : authUserDto.getUsername();
if (adminService.getAdminByUserName(userName) != null) {
return RespBean.error("用户名已存在!");
}
// 创建用户
Admin admin = new Admin();
admin.setUsername(userName);
try {
admin.setPassword(passwordEncoder.encode(authUserDto.getPassword()));
} catch (Exception e) {
return RespBean.error("注册密码异常!");
}
admin.setEmail(authUserDto.getEmail());
if(adminService.create(admin) == null){
return RespBean.error("用户注册失败!");
};
redisTemplate.delete(authUserDto.getEmail());
return RespBean.success("用户注册成功!");
}
@Override
public RespBean sendMailCode(String email) {
ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
// 查看注册邮箱是否存在
if (adminService.registerEmailExist(email)) {
return RespBean.error("邮箱已被注册!");
}
// 获取发送邮箱验证码的HTML模板
TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("templates", TemplateConfig.ResourceMode.CLASSPATH));
Template template = engine.getTemplate("email-code.ftl");
// 从redis缓存中尝试获取验证码
Object code = valueOperations.get(email);
if (code == null) {
// 如果在缓存中未获取到验证码,则产生6位随机数,放入缓存中
code = RandomUtil.randomNumbers(6);
try {
valueOperations.set(email, code, expiration, TimeUnit.SECONDS);
} catch (Exception e) {
return RespBean.error("后台缓存服务异常");
}
}
// 发送验证码
emailService.send(new EmailDto(Collections.singletonList(email),
"邮箱验证码", template.render(Dict.create().set("code", code))));
return RespBean.success("验证码发送成功");
}
}
7. 编写Controller层API接口
@Api(tags = "admin-controller")
@RestController
@RequestMapping("/user")
public class AdminController {
@Autowired
AuthServiceImpl authService;
@ApiOperation(value = "发送邮箱验证码")
@PostMapping("/getemailcode")
public RespBean getEmailCode(@RequestParam String email) {
return authService.sendMailCode(email);
}
@ApiOperation(value = "注册")
@PostMapping("/register")
public RespBean register(@RequestBody AuthUserDto authUserDto) {
return authService.register(authUserDto);
}
}
根据原项目完善用户服务类(adminService)相关的方法实现,即可实现邮箱验证码注册功能。
三、结果演示
1. 发送邮箱验证码接口
-
请求方式:post
-
请求地址:/user/getemailcode
-
参数:
{ "email": "XXXX@foxmail.com" }
2. 注册账号接口
-
请求方式:post
-
请求地址:/user/register
-
参数:
{ "code": "214941", "email": "XXXXXXX@foxmail.com", "password": "123", "username": "myself" }