avatar

Spring Boot实现邮件登录注册

使用Spring Boot完成邮箱登录注册

源码:https://github.com/Hobo-clh/spring-boot-email

前提

主要记录一下邮箱注册,使用Spring Boot和MyBatis

  1. springboot中导入email相关依赖
  2. 开启邮箱的POP3/SMTP服务(这里使用的是qq邮箱)文档
  3. 在springboot的配置文件中添加email相关配置

编码思路

  • 获取验证码:填写邮箱号后点击发送验证码按钮–>发送ajax请求–>后端生成验证码发送邮件,生成一个验证对象插入验证表中,使用多线程五分钟后删除改信息。
  • 注册: 点击注册按钮–>发送ajax请求–>后端判断验证码是否正确–>返回json数据–>注册是否成功

开始

  • 目录结构
    目录结构

  • 在idea中创建Spring Boot工程
    在pom.xml 配置文件中加入spring-boot-starter-mail 依赖

    1
    2
    3
    4
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
    </dependency>
  • 在springboot配置文件application.yml中添加邮箱配置信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    #邮件相关配置
    spring:
    mail:
    host: smtp.qq.com
    username: longhuahobo@foxmail.com
    password: qq邮箱是授权码
    port: 465
    # SMTP服务
    properties:
    mail:
    smtp:
    ssl:
    enable: true
    auth: true
    socketFactory:
    class: javax.net.ssl.SSLSocketFactory
    port: 465
  • model层User和Verify实体类,数据库创建相对应的表

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    package com.example.springboot.model;
    import lombok.Data;
    /**
    * 用户表
    */
    @Data
    public class User {
    private Long id;
    private String email;
    private String password;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    package com.example.springboot.model;
    import lombok.Data;
    /**
    * 临时验证码存放表
    */
    public class Verify {
    private Long id;
    private String email;
    private int code;
    }
  • 当进行注册的业务逻辑时,会出现一些错误信息,例如邮箱号为空、验证码为空等,要将这些信息精准的返回给用户则需要添加一个enum类,对这些错误信息进行定义

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    package com.example.springboot.exception;
    /**
    * 自定义枚举类,将错误信息定义为枚举
    */
    public enum CustomizeErrorCode {
    EMAIL_IS_EXIST(201,"邮箱已经注册过了"),
    EMAIL_IS_BLANK(202,"邮箱不能为空"),
    EMAIL_OR_PWD_BLANK(203,"邮箱或密码不能为空"),
    INVALID_ADDRESSES(204,"无效的地址!"),
    VERIFY_IS_ERROR(205,"验证码错误"),
    REGISTER_FAIL(206,"注册失败"),
    EMAIL_OR_PWD_ERROR(206,"邮箱号或密码错误,登录失败");

    private Integer code;
    private String message;

    public String getMessage() {
    return message;
    }
    public Integer getCode() {
    return code;
    }
    CustomizeErrorCode(Integer code,String message) {
    this.message = message;
    this.code = code;
    }
    }
  • 将错误信息封装到dto层的ResuDTO中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    package com.example.springboot.dto;

    import com.example.springboot.exception.CustomizeErrorCode;
    import lombok.Data;
    /**
    * 返回工具类
    */
    @Data
    public class ResultDTO {

    private Integer code;
    private String message;
    /**
    * 将CustomizeErrorCode枚举对象的值转换给ResultDTO
    * @param errorCode 枚举对象
    * @return
    */
    public static ResultDTO errorInfo(CustomizeErrorCode errorCode){
    return init(errorCode.getCode(),errorCode.getMessage());
    }
    /**
    * 初始化ResultDTO对象
    * @param code 状态码
    * @param message 描述信息
    * @return
    */
    private static ResultDTO init(Integer code,String message){
    ResultDTO resultDTO = new ResultDTO();
    resultDTO.setCode(code);
    resultDTO.setMessage(message);
    return resultDTO;
    }
    public static ResultDTO info(Integer code, String message) {
    return init(code,message);
    }
    }
  • controller层的RegisterController

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    package com.example.springboot.controller;

    import com.example.springboot.dto.ResultDTO;
    import com.example.springboot.dto.UserDTO;
    import com.example.springboot.exception.CustomizeErrorCode;
    import com.example.springboot.service.RegisterService;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.mail.javamail.JavaMailSender;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.*;

    @Controller
    public class registerController {
    @Autowired
    RegisterService registerService;
    @Autowired
    JavaMailSender mailSender;
    /**
    * 注册
    * 将注册参数code、email、pwd封装带UserDTO中
    * @param userDTO
    * @return ResultDTO 返回json格式,带有code和message
    */
    @ResponseBody
    @PostMapping("/register")
    public ResultDTO register(UserDTO userDTO){
    System.out.println(userDTO);
    if (StringUtils.isBlank(userDTO.getEmail())&&StringUtils.isBlank(userDTO.getPassword())){
    return ResultDTO.errorInfo(CustomizeErrorCode.EMAIL_OR_PWD_BLANK);
    }
    return registerService.register(userDTO);
    }
    /**
    * 发送验证码
    * @param email 邮箱号
    * @return ResultDTO 返回json格式,带有code和message
    */
    @ResponseBody
    @PostMapping("/sendCode")
    public ResultDTO sendCode(@RequestParam("email") String email){
    System.out.println(email);
    if (StringUtils.isBlank(email)){
    return ResultDTO.errorInfo(CustomizeErrorCode.EMAIL_IS_BLANK);
    }
    ResultDTO resultDTO = registerService.sendCode(email);
    if (resultDTO.getCode()==200) {
    //多线程五分钟后删除
    registerService.removeCode(email);
    }
    return resultDTO;
    }
    }
  • service层的RegisterService,创建多线程将发送的验证码在5分钟后进行删除(使用“@Async”时需要在Spring Boot启动类使用“@EnableAsync”)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    package com.example.springboot.service;

    import com.example.springboot.dto.ResultDTO;
    import com.example.springboot.dto.UserDTO;
    import com.example.springboot.exception.CustomizeErrorCode;
    import com.example.springboot.mapper.UserMapper;
    import com.example.springboot.mapper.VerifyMapper;
    import com.example.springboot.model.User;
    import com.example.springboot.model.Verify;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.mail.MailException;
    import org.springframework.mail.SimpleMailMessage;
    import org.springframework.mail.javamail.JavaMailSender;
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.stereotype.Service;

    @Slf4j
    @Service
    public class RegisterService {

    @Autowired
    UserMapper userMapper;
    @Autowired
    JavaMailSender mailSender;
    @Autowired
    VerifyMapper verifyMapper;

    /**
    * 检查邮箱号是否注册
    * @param email 邮箱号
    * @return
    */
    public boolean checkRegister(String email){
    User user1 = userMapper.selectByEmail(email);
    if (user1==null){
    return true;
    }
    return false;
    }

    /**
    * 注册
    * @param userDTO 该对象参数含有email、pwd、code
    * @return ResultDTO
    */
    public ResultDTO register(UserDTO userDTO) {
    //checkRegister()返回结果为true表示可以注册
    if (!checkRegister(userDTO.getEmail())){
    return ResultDTO.errorInfo(CustomizeErrorCode.EMAIL_IS_EXIST);
    }
    userDTO.getCode();
    Verify verify = verifyMapper.selectVerify(userDTO.getCode(),userDTO.getEmail());
    if (verify==null){
    //验证码错误
    return ResultDTO.errorInfo(CustomizeErrorCode.VERIFY_IS_ERROR);
    }
    User user = new User();
    user.setEmail(userDTO.getEmail());
    user.setPassword(userDTO.getPassword());
    int flag = userMapper.insert(user);
    //注册成功
    if (flag==1){
    //登录成功将验证码删除
    verifyMapper.deleteByEmail(userDTO.getEmail());
    return ResultDTO.info(200,"注册成功");
    }
    //注册失败
    return ResultDTO.errorInfo(CustomizeErrorCode.REGISTER_FAIL);
    }

    /**
    * 发送邮件
    * @param email 邮箱号
    * @return ResultDTO
    */
    public ResultDTO sendCode(String email){
    //随机六位数验证码
    if (!checkRegister(email)){
    return ResultDTO.errorInfo(CustomizeErrorCode.EMAIL_IS_EXIST);
    }
    try {
    SimpleMailMessage message = new SimpleMailMessage();
    int code = (int)((Math.random() * 9 + 1) * 100000);
    message.setSubject("Hobo社区验证码");
    message.setText("欢迎加入Hobo社区! 您的验证码是:"+ code + ",请在5分钟内完成注册。");
    message.setTo(email);
    message.setFrom("longhuahobo@foxmail.com");
    mailSender.send(message);
    Verify verify = new Verify();
    //
    verify.setCode(code);
    verify.setEmail(email);
    verifyMapper.insert(verify);
    return ResultDTO.info(200,"邮件发送成功");
    }catch (MailException e){
    log.error("邮件发送出错" + e);
    return ResultDTO.errorInfo(CustomizeErrorCode.INVALID_ADDRESSES);
    }

    }

    /**
    * 使用多线程五分钟后清除验证码数据
    * @param email email
    */
    @Async
    public void removeCode(String email){
    try {
    Thread.sleep(1000*60*5);
    verifyMapper.deleteByEmail(email);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    }
  • mapper层的UserMapper、VerifyMapper,使用注解方式对数据库进行增删改查

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    package com.example.springboot.mapper;

    import com.example.springboot.model.User;
    import org.apache.ibatis.annotations.Insert;
    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.annotations.Select;

    @Mapper
    public interface UserMapper {
    /**
    * 插入用户表
    * @param user 用户,带有email、password参数
    * @return
    */
    @Insert("insert into user(email,password) values(#{email},#{password})")
    int insert(User user);

    /**
    * 使用id查找用户
    * @param id 用户id
    * @return
    */
    @Select("select * from user where id = #{id}")
    User selectById(Long id);

    /**
    * 使用邮箱号和密码查找用户
    * @param email 邮箱号
    * @param password 密码
    * @return
    */
    @Select("select * from user where email = #{email} and password = #{password} ")
    User selectByEmailPwd(String email, String password);

    /**
    * 使用邮箱号查找用户
    * @param email 邮箱号
    * @return
    */
    @Select("select * from user where email = #{email}")
    User selectByEmail(String email);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    package com.example.springboot.mapper;

    import com.example.springboot.model.Verify;
    import org.apache.ibatis.annotations.Delete;
    import org.apache.ibatis.annotations.Insert;
    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.annotations.Select;

    @Mapper
    public interface VerifyMapper {
    /**
    * 插入验证表
    * @param verify 带有email和code参数
    * @return
    */
    @Insert("insert into verify(email,code) values(#{email},#{code})")
    int insert(Verify verify);

    /**
    * 使用验证码和邮箱号查找验证表
    * @param code 验证码
    * @param email 邮箱号
    * @return
    */
    @Select("select * from verify where code = #{code} and email = #{email}")
    Verify selectVerify(String code,String email);

    /**
    * 使用邮箱号删除验证表
    * @param email 邮箱号
    * @return
    */
    @Delete("delete from verify where email = #{email}")
    int deleteByEmail(String email);
    }

    前端代码省略….
    result
    result2

结束

文章作者: Hobo
文章链接: https://hobo-clh.github.io/2020/04/19/Email/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Hobo's blog
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论