哈士奇发布简单邮箱验证+邮箱登录+验证码超时【未使用MyBatis-Plus】

2.1、创建MySQL表

// 有效信息表
CREATE TABLE `t_emailInfo`
(
	`id` INT(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
	`code` CHAR(6) DEFAULT NULL COMMENT '验证码',
	`toEmail` VARCHAR(50) DEFAULT NULL COMMENT '邮箱地址',
	`valid_time` DATETIME DEFAULT NULL COMMENT '有效时间',
	PRIMARY KEY (`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8mb4;

// 用户表
CREATE TABLE `t_user`(
	`id` INT(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
	`username` VARCHAR(32) DEFAULT NULL COMMENT '用户名称',
	`nickname` VARCHAR(32) DEFAULT NULL COMMENT '用户昵称',
	`password` CHAR(32) NOT NULL COMMENT '用户密码',
	`salt` CHAR(36) NOT NULL COMMENT '盐值',
	`phone` VARCHAR(20) DEFAULT NULL COMMENT '手机号码',
	`email` VARCHAR(30) DEFAULT NULL COMMENT '电子邮箱',
	`gender` ENUM('未知', '男', '女') DEFAULT '未知' COMMENT '性别',
	`avatar` VARCHAR(50) DEFAULT NULL COMMENT '头像',
	`is_delete` TINYINT(1) DEFAULT '0' COMMENT '0-未删除,1-已删除',
	PRIMARY KEY (`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8mb4;

2.2、引入坐标

<!--mail-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.7.20</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>4.1.2</version>
</dependency>

2.3、yaml文件中的配置【之前的邮箱验证有,但为了方便再次设置】

spring:
  mail:
    host: smtp.qq.com
    username: 你自己的qq号@qq.com
    password: qq邮箱-》设置-》POP3/SMTP服务-》点击开启-》发验证码-》收到验证码后填入
    properties:
      mail:
        smtp:
          ssl:
            enable: true
        default-encoding: UTF-8
    port: 465

2.4、创建实体类 【使用lombok;懒】

用户表

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    private Integer id;
    private String username;
    private String nickname;
    private String password;
    private String salt;
    private String phone;
    private String email;
    private String avatar;
    private Boolean isDelete;
    
}

邮箱验证有效表

@Data
@AllArgsConstructor
@NoArgsConstructor
public class EmailInfo implements Serializable {

    private static final long serialVersionUID = 1L;
    private Integer id;
    private String code;
    private String toEmail;
    private Date validTime;

}

2.5、创建Mapper接口

UserMapper接口

@Mapper
public interface UserMapper {

    // 新增
    int add(User user);

    // 判断用户名是否已存在
    int usernameIsExist(@Param("username") String username);

    // 登录
    LoginUserVo login(@Param("username") String username, @Param("password") String password);

    // 通过用户名获取用户信息
    User GetOneByUsername(@Param("username") String username);

    // 通过邮箱获取用户信息
    LoginUserVo getOneByEmail(@Param("email") String email);
}

EmailInfoMapper接口

@Mapper
public interface EmailInfoMapper {

    // 新增有效信息
    int add(EmailInfo emailInfo);

    // 通过邮箱和验证码获取 有效信息
    EmailInfo getEmailByEC(@Param("email") String email, @Param("code") String code);
}

2.6、Mapper.xml

UserMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.it.hashiqiexercise.mapper.UserMapper">
    
    <resultMap id="UserMap" type="user">
        <id column="id" property="id"></id>
        <result column="is_delete" property="isDelete"></result>
    </resultMap>

    <insert id="add" parameterType="com.it.hashiqiexercise.pojo.User">
        INSERT INTO exercise.t_user (username, password, salt) VALUES (#{username}, #{password}, #{salt})
    </insert>

    <select id="usernameIsExist" resultType="java.lang.Integer">
        SELECT count(*) FROM exercise.t_user WHERE username=#{username}
    </select>
    
    <select id="login" resultType="com.it.hashiqiexercise.vo.LoginUserVo">
        SELECT id, username, nickname, phone, email, avatar FROM exercise.t_user WHERE username=#{username} and password=#{password}
    </select>

    <select id="GetOneByUsername" resultMap="UserMap">
        SELECT * FROM exercise.t_user WHERE username=#{username}
    </select>

    <select id="getOneByEmail" resultType="com.it.hashiqiexercise.vo.LoginUserVo">
        SELECT * FROM exercise.t_user WHERE email=#{email}
    </select>

</mapper>

EmailInfoMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.it.hashiqiexercise.mapper.EmailInfoMapper">

    <insert id="add" parameterType="emailInfo">
        INSERT INTO exercise.t_emailinfo (code, toEmail, valid_time) VALUES (#{code}, #{toEmail}, #{validTime})
    </insert>

    <select id="getEmailByEC" resultType="com.it.hashiqiexercise.pojo.EmailInfo">
        SELECT * FROM exercise.t_emailinfo WHERE toEmail=#{email} and code=#{code}
    </select>
</mapper>

2.7、业务接口层

用户业务接口层

public interface UserService {

    String add(RegisterUserDto registerUserDto);

    boolean usernameIsExist(String username);

    User login(String username, String password);
}

有效信息业务接口层

public interface EmailInfoService {

    boolean send(String email);

    User getOneByEmailAndCode(String email, String code);
}

2.8、业务实现层 【这里未实现将业务异常信息转发到前端页面】

用户业务实现层 【这里有一个md5加密】

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    /**
     * 注册
     * @param registerUserDto 注册用户
     * @return 返回状态值
     */
    @Override
    public String add(RegisterUserDto registerUserDto) {
        // 1、取出 registerUserDto 里的值
        String username = registerUserDto.getUsername();
        String password = registerUserDto.getPassword();
        // 2、判断 username 和 password 是否为空
        if (username == null || password == null) {
            System.err.println("用户名为空 或 密码为空");
            return Constants.CODE_4000;
        }
        // 3、判断 username 是否已存在数据库中
        boolean isExist = usernameIsExist(username);
        if (isExist) {
            System.err.println("用户名已存在");
            return Constants.CODE_4001;
        }
        // 4、设置盐值
        String salt = UUID.randomUUID().toString().toUpperCase();
        // 5、使用md5进行加密
        String md5Password = passwordMd5(password, salt);

        // 4、添加数据
        User user = new User();
        user.setUsername(username);
        user.setPassword(md5Password);
        user.setSalt(salt);
        int addCount = userMapper.add(user);
        if (addCount > 0) {
            return Constants.CODE_200;
        }
        return Constants.CODE_6000;
    }

    /**
     * 判断用户名是否已存在
     * @param username 注册用户名
     * @return 返回布尔值
     */
    @Override
    public boolean usernameIsExist(String username) {
        return userMapper.usernameIsExist(username) > 0;
    }

    /**
     * 查看是否成功登录
     * @param username 登录用户名
     * @param password 登录密码
     * @return 返回登录用户的信息
     */
    @Override
    public User login(String username, String password) {
        if (username == null || password == null) {
            return null;
        }
        // 判断用户名是否存在
        int isExist = userMapper.usernameIsExist(username);
        if (isExist < 1) {
            return null;
        }
        // 通过用户名获取数据库中保存的密码和盐值
        User user1 = userMapper.GetOneByUsername(username);
        if (user1 == null) {
            return null;
        }
        // 将登录的密码进行md5加密
        String md5Password = passwordMd5(password, user1.getSalt());
        // 将登录的密码进行md5加密后 与 数据库中的加密密码进行比较
        if (!md5Password.equals(user1.getPassword())) {
            return null;
        }
        // 通过验证后,直接通过用户名和密码获取 用户信息
        LoginUserVo loginUserVo = userMapper.login(username, md5Password);
        // 创建 User 实体对象
        // 创建 User
        LoginUserVoToUser loginUserVoToUser = new LoginUserVoToUser();
        User user = loginUserVoToUser.toUser(loginUserVo);
        return user;
    }

    /**
     * md5加密
     * @param password 注册密码
     * @param salt 盐值
     * @return 返回加密后的密码
     */
    public String passwordMd5(String password, String salt) {
        for (int i = 0; i < 3; i++) {
            password = DigestUtils.md5DigestAsHex((salt + password + salt).getBytes()).toUpperCase();
        }
        return password;
    }
}

有效信息业务实现层

@Service
public class EmailInfoServiceImpl implements EmailInfoService {

    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    @Autowired
    private JavaMailSender mailSender;
    @Autowired
    private EmailInfoMapper emailInfoMapper;
    @Autowired
    private UserMapper userMapper;
    @Value("${spring.mail.username}")
    private String from;

    /**
     * 模拟前端点击获取验证码,将输入的QQ邮箱作为要接收验证码的邮箱地址
     * @param email 输入的QQ邮箱
     * @return 返回布尔值
     */
    @Override
    public boolean send(String email) {
        try {
            SimpleMailMessage mailMessage = new SimpleMailMessage();

            // 主题
            mailMessage.setSubject("验证码邮件");
            // 生成随机数
            String code = randomCode();
            // 内容
            mailMessage.setText("您收到的验证码是:" + code + ", 五分钟有效,请妥善保管");
            // 发给谁
            mailMessage.setTo(email);
            // 设置发送的时间
            Date now = new Date();
            mailMessage.setSentDate(now);
            // 自己的邮箱
            mailMessage.setFrom(from);
            // 发送
            mailSender.send(mailMessage);
            // 创建发送邮箱信息 并加入 数据库表中
            EmailInfo emailInfo = new EmailInfo();
            emailInfo.setCode(code);
            emailInfo.setToEmail(email);
            // 向后延长5分钟
            emailInfo.setValidTime(DateUtil.offsetMinute(now, 5));
            int addCount = emailInfoMapper.add(emailInfo);
            if (addCount > 0) {
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("发送失败,出现异常");
        }
        return true;
    }

    @Override
    public User getOneByEmailAndCode(String email, String code) {
        // 先判断邮箱或验证码是否为空
        if (email == null || code == null) {
            throw new RuntimeException("邮箱为空或者验证码为空");
        }
        // 通过 邮箱和验证码 来获取邮箱信息实体
        EmailInfo emailByEC = emailInfoMapper.getEmailByEC(email, code);
        if (emailByEC == null) {
            throw new RuntimeException("验证码错误");
        }
        // 获取当前时间 与 数据库表中保存的有效时间进行比较
        Date now = new Date();
        Date oldDate = emailByEC.getValidTime();
        if (now.after(oldDate)) { // 说明当前时间已经超过有效时间
            throw new RuntimeException("有效时间过期,请重新发送验证码");
        }

        // 通过 邮箱 获取 用户信息
        LoginUserVo loginUserVo = userMapper.getOneByEmail(email);
        if (loginUserVo == null) {
            throw new RuntimeException("用户不存在");
        }
        // 创建 User
        LoginUserVoToUser loginUserVoToUser = new LoginUserVoToUser();
        User user = loginUserVoToUser.toUser(loginUserVo);
        return user;
    }

    /**
     * 随机生成6位数的虚拟验证码
     * @return
     */
    public String randomCode() {
        StringBuilder str = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < 6; i++) {
            str.append(random.nextInt(10));
        }
        return str.toString();
    }
}

2.9、控制层 【Controller】【R是一个统一结果集】

UserController

@RestController
public class UserController extends BaseController {

    @Autowired
    private UserService userService;

    @GetMapping("user/register")
    public R registerUser(RegisterUserDto registerUserDto) {
        String addIsOk = userService.add(registerUserDto);
        if ("200".equals(addIsOk)) {
            return R.success();
        } else {
            return handleR(addIsOk);
        }
    }

    @GetMapping("user/login/{username}/{password}")
    public R loginUser(@PathVariable String username, @PathVariable String password) {
        User loginUser = userService.login(username, password);
        if (loginUser == null) {
            return handleR("6000");
        } else {
            return R.success(loginUser);
        }
    }
}

EmailInfoController

@RestController
public class EmailInfoController {

    @Autowired
    EmailInfoService emailInfoService;

    /**
     * 前端点击获取验证码 发送验证码到邮箱
     * @param email 接收方邮箱
     * @return 返回结果
     */
    @RequestMapping("email/send")
    public R send(String email){
        return R.success(emailInfoService.send(email));
    }

    @GetMapping("email/get/{email}/{code}")
    public R getLogin(@PathVariable String email, @PathVariable String code) {
        return R.success(emailInfoService.getOneByEmailAndCode(email, code));
    }
}

最后请你自己去验证啦~ 本人懒,不想写前端 O(∩_∩)O哈哈~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值