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哈哈~