实现的功能:新用户通过邮箱账号来注册登录系统,只有输入正确的验证码,才能注册成功。
目录
(一)所有代码:
1.创建一个springboot项目,然后导入依赖。
2.数据表结构如下:
3.注册页面(完整代码):
4.工具类(util包):
5.controller层:
6.service层:
7.service.impl层:
8.dao层:
9.tbUserDao.xml:
10.实体类:
11.application.properties:
12.DemoApplication.java:
(二)运行结果:
编辑
(三)具体说明:
1.MsgCodeData工具类。
2.邮箱验证正则表达式、验证码倒计时。
3.两次输入密码必须一样。
4.定义SecurityCode工具类和EmailUtil工具类。
5.点击发送验证码按钮,发送验证码到邮箱。
6.输入正确的验证码,输入密码,前端点击添加按钮,进行注册,将登录名和密码添加到数据库。
7.最后,不要忘了在DemoApplication中添加:@MapperScan("com.example.demo.dao")以及在application.properties中配置数据库。
8.项目结构图:
(一)所有代码:
1.创建一个springboot项目,然后导入依赖。
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
</dependency>
2.数据表结构如下:
3.注册页面(完整代码):
<!DOCTYPE html>
<html class="x-admin-sm">
<head>
<meta charset="UTF-8">
<title>注册</title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width,user-scalable=yes, minimum-scale=0.4, initial-scale=0.8,target-densitydpi=low-dpi" />
<link rel="stylesheet" href="./css/font.css">
<link rel="stylesheet" href="./css/xadmin.css">
<script type="text/javascript" src="./lib/layui/layui.js" charset="utf-8"></script>
<script type="text/javascript" src="./js/xadmin.js"></script>
<script type="text/javascript" src="./js/jquery.min.js"></script>
<link rel="stylesheet" href="./css/register.css">
</head>
<body class="register-bg">
<div class="layui-fluid" style="width: 40%;margin-top: 10%;background-color: aliceblue;height: 330px;">
<h2 style="text-align: center;">注册</h2>
<div class="layui-row" style="margin-top: 28px;font-size: 14px;">
<form class="layui-form">
<div class="layui-form-item">
<label for="loginname" class="layui-form-label">
<span class="x-red">*</span>邮箱:</label>
<div class="layui-input-inline">
<input type="loginname" id="loginname" name="loginname" required="" lay-verify="loginname" autocomplete="off"
class="layui-input" placeholder="请输入已绑定的邮箱号" >
</div>
</div>
<div class="layui-form-item">
<label for="code1" class="layui-form-label">
<span class="x-red">*</span>验证码:</label>
<div class="layui-input-inline" >
<input type="text" id="code1" name="securityCode" required="" placeholder="邮箱验证码" lay-verify="codenumber" autocomplete="off" class="layui-input">
</div>
<input id="btnSendCode1" class="layui-btn layui-btn-sm layui-btn-normal" type="button" style="margin-left: 10px;margin-top:2px;" value="获取验证码" onClick="sendMessage1()" />
</div>
<div class="layui-form-item">
<label for="L_pass" class="layui-form-label">
<span class="x-red">*</span>密码:</label>
<div class="layui-input-inline">
<input type="password" id="L_pass" name="pwd" required="" lay-verify="pwd" autocomplete="off"
class="layui-input" >
</div>
<div class="layui-form-mid layui-word-aux" style="margin-left: 10px;">6到16个字符</div>
</div>
<div class="layui-form-item">
<label for="L_repass" class="layui-form-label">
<span class="x-red">*</span>确认密码:</label>
<div class="layui-input-inline">
<input type="password" id="L_repass" name="repass" required="" lay-verify="repass"
autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label for="L_repass" class="layui-form-label"></label>
<button class="layui-btn layui-btn-lg" lay-filter="add" lay-submit="" style="width:200px;">增加</button>
</div>
</form>
</div>
</div>
</body>
<!-- layui -->
<script>
layui.use(['form', 'layer', 'jquery'],
function () {
$ = layui.jquery;
var form = layui.form;
var layer = layui.layer;
//自定义验证规则
form.verify({
codenumber: function (value) {
if (value.length != 6) {
return '验证码必须为6位数字';
}
},
pwd: [/(.+){6,12}$/, '密码必须6到12位'],
repass: function (value) {
if ($('#L_pass').val() != $('#L_repass').val()) {
return '两次密码不一致';
}
}
});
//1.1开始对form表单进行操作
form.on('submit(add)',function(data){
//2.定义一个变量,存取form表单提交的值
var getDatas=data.field//filed:{name : value}
console.log(getDatas);
// 3.发送请求
$.ajax({
url:"http://localhost:8080/tbUser/register",
method:"GET",
data:{
loginname: getDatas.loginname,
password: getDatas.pwd,
securityCode:getDatas.securityCode
},
dataType:"JSON",
success:function(res){
layer.msg(res.msg);
}
});
return false;//阻止表单跳转
});
});
</script>
<!-- 验证码倒计时 -->
<script type="text/javascript">
var loginnameReg = /(^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$)/;//邮箱号正则
var count = 60; //间隔函数,1秒执行
var InterValObj1; //timer变量,控制时间
var curCount1;//当前剩余秒数
/*第一*/
function sendMessage1() {
curCount1 = count;
var phone = $.trim($('#loginname').val());
if (!loginnameReg.test(phone)) {
alert(" 请输入有效的邮箱号");
return false;
}
//设置button效果,开始计时
$("#btnSendCode1").attr("disabled", "true");
$("#btnSendCode1").val(+ curCount1 + "秒再获取");
InterValObj1 = window.setInterval(SetRemainTime1, 1000); //启动计时器,1秒执行一次
//向后台发送处理数据
$.ajax({
type:"POST",
url:"http://localhost:8080/tbUser/getCode",
//1.从前端取值
data:{
"loginname":$("#loginname").val(),
},
dataType:"JSON",
success:function(res){
console.log(res)
}
});
}
function SetRemainTime1() {
if (curCount1 == 0) {
window.clearInterval(InterValObj1);//停止计时器
$("#btnSendCode1").removeAttr("disabled");//启用按钮
$("#btnSendCode1").val("重新发送");
}
else {
curCount1--;
$("#btnSendCode1").val(+ curCount1 + "秒再获取");
}
}
</script>
</html>
4.工具类(util包):
(1)MsgCodeData.java
package com.example.demo.util;
public class MsgCodeData {
private Integer code;
private String msg;
private Object data;
public MsgCodeData() {
}
public MsgCodeData(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public MsgCodeData(Integer code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
(2)SecurityCode.java
package com.example.demo.util;
public class SecurityCode {
public static String getCode(){
//获取6为随机验证码
String[] letters = new String[] {"0","1","2","3","4","5","6","7","8","9"};
String stringBuilder ="";
for(int i = 0; i < 6; i++){
stringBuilder = stringBuilder + letters[(int)Math.floor(Math.random()*letters.length)];
}
return stringBuilder;
}
}
(3)EmailUtil.java
package com.example.demo.util;
import org.springframework.stereotype.Component;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;
/**
* 发邮件工具类
*/
@Component
public class EmailUtil {
public static boolean sendMail(String to, String text, String title){
String USER="*******@qq.com"; // 发件人邮箱地址
String PASSWORD="******"; // 授权码
try {
final Properties props = new Properties();
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.host", "smtp.qq.com");
// 发件人的账号
props.put("mail.user", USER);
//发件人的密码
props.put("mail.password", PASSWORD);
// 构建授权信息,用于进行SMTP进行身份验证
Authenticator authenticator = new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
// 用户名、密码
String userName = props.getProperty("mail.user");
String password = props.getProperty("mail.password");
return new PasswordAuthentication(userName, password);
}
};
// 使用环境属性和授权信息,创建邮件会话
Session mailSession = Session.getInstance(props, authenticator);
// 创建邮件消息
MimeMessage message = new MimeMessage(mailSession);
// 设置发件人
String username = props.getProperty("mail.user");
InternetAddress form = new InternetAddress(username);
message.setFrom(form);
// 设置收件人
InternetAddress toAddress = new InternetAddress(to);
message.setRecipient(Message.RecipientType.TO, toAddress);
// 设置邮件标题
message.setSubject(title);
// 设置邮件的内容体
message.setContent(text, "text/html;charset=UTF-8");
// 发送邮件
Transport.send(message);
return true;
}catch (Exception e){
e.printStackTrace();
}
return false;
}
}
5.controller层:
package com.example.demo.controller;
import com.example.demo.entity.TbUser;
import com.example.demo.service.TbUserService;
import com.example.demo.util.EmailUtil;
import com.example.demo.util.MsgCodeData;
import com.example.demo.util.SecurityCode;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@CrossOrigin("*")
@RestController
@RequestMapping("tbUser")
public class TbUserController {
/**
* 服务对象
*/
@Resource
private TbUserService tbUserService;
String randomNum= SecurityCode.getCode();
@RequestMapping("/register")
//从前端接收注册的用户名和密码,以及验证码
public MsgCodeData register(TbUser tbUser,String securityCode){
MsgCodeData resultData= tbUserService.register(tbUser,securityCode,randomNum);
return resultData;
}
@RequestMapping("/getCode")
//点击按钮,直接发送验证码到qq邮箱。
public void getCode(String loginname){
EmailUtil.sendMail(loginname,randomNum,"欢迎注册我们的系统,请接收您的验证码");
}
}
6.service层:
package com.example.demo.service;
import com.example.demo.entity.TbUser;
import com.example.demo.util.MsgCodeData;
/**
* (TbUser)表服务接口
*
* @author makejava
* @since 2023-09-24 19:41:34
*/
public interface TbUserService {
MsgCodeData register(TbUser tbUser, String securityCode, String randomNum);
}
7.service.impl层:
package com.example.demo.service.impl;
import com.example.demo.dao.TbUserDao;
import com.example.demo.entity.TbUser;
import com.example.demo.service.TbUserService;
import com.example.demo.util.MsgCodeData;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* (TbUser)表服务实现类
*
* @author makejava
* @since 2023-09-24 19:41:34
*/
@Service("tbUserService")
public class TbUserServiceImpl implements TbUserService {
@Resource
private TbUserDao tbUserDao;
@Override
public MsgCodeData register(TbUser tbUser, String securityCode, String randomNum) {
String loginnameFromHtml = tbUser.getLoginname();
TbUser userRsFromMySQL = tbUserDao.login(loginnameFromHtml);
System.out.println("1:" + randomNum);
System.out.println("2:" + securityCode);
if (userRsFromMySQL == null) {
if (securityCode.equals(randomNum)) {
Integer i = tbUserDao.register(tbUser);
if (i == 0) {
return new MsgCodeData(201, "注册失败!");
} else {
return new MsgCodeData(200, "注册成功~");
}
} else {
return new MsgCodeData(202, "验证码错误!");
}
} else {
return new MsgCodeData(203, "该用户已存在!");
}
}
}
8.dao层:
package com.example.demo.dao;
import com.example.demo.entity.TbUser;
/**
* (TbUser)表数据库访问层
*
* @author makejava
* @since 2023-09-24 19:41:34
*/
public interface TbUserDao {
TbUser login(String loginname);
Integer register(TbUser tbUser);
}
9.tbUserDao.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.example.demo.dao.TbUserDao">
<resultMap type="com.example.demo.entity.TbUser" id="TbUserMap">
<result property="id" column="id" jdbcType="INTEGER"/>
<result property="loginname" column="loginname" jdbcType="VARCHAR"/>
<result property="password" column="password" jdbcType="VARCHAR"/>
<result property="username" column="username" jdbcType="VARCHAR"/>
</resultMap>
<select id="login" resultMap="TbUserMap">
select * from tb_user where loginname = #{loginname}
</select>
<insert id="register" keyProperty="id" useGeneratedKeys="true">
insert into tb_user(loginname, password)
values (#{loginname}, #{password})
</insert>
</mapper>
10.实体类:
package com.example.demo.entity;
import java.io.Serializable;
/**
* (TbUser)实体类
*
* @author makejava
* @since 2023-09-24 19:41:34
*/
public class TbUser implements Serializable {
private static final long serialVersionUID = -38402979771638178L;
private Integer id;
private String loginname;
private String password;
private String username;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getLoginname() {
return loginname;
}
public void setLoginname(String loginname) {
this.loginname = loginname;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
11.application.properties:
spring.jpa.database = mysql
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=******
spring.datasource.url=jdbc:mysql://localhost:3306/emailtest00?serverTimezone=Asia/Shanghai&useSSL=false&useUnicode=true&characterEncoding=UTF-8
mybatis.mapper-locations=classpath/*.xml
12.DemoApplication.java:
package com.example.demo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.example.demo.dao")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
(二)运行结果:
(三)具体说明:
1.MsgCodeData工具类。
对前端接收的数据进行封装,后端发送到前端的结果是msg,code,data的形式。
msg:文字提示,code:状态码,data:返回给前端的数据。
package com.example.demo.util;
public class MsgCodeData {
private Integer code;
private String msg;
private Object data;
public MsgCodeData() {
}
public MsgCodeData(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public MsgCodeData(Integer code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
2.邮箱验证正则表达式、验证码倒计时。
<!-- 验证码倒计时 -->
<script type="text/javascript">
//邮箱的正则表达式
var loginnameReg = /(^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$)/;//邮箱号正则
var count = 60; //间隔函数,1秒执行
var InterValObj1; //timer变量,控制时间
var curCount1;//当前剩余秒数
/*第一*/
function sendMessage1() {
curCount1 = count;
var phone = $.trim($('#loginname').val());
if (!loginnameReg.test(phone)) {
alert(" 请输入有效的邮箱号");
return false;
}
//设置button效果,开始计时
$("#btnSendCode1").attr("disabled", "true");
$("#btnSendCode1").val(+ curCount1 + "秒再获取");
InterValObj1 = window.setInterval(SetRemainTime1, 1000); //启动计时器,1秒执行一次
//向后台发送处理数据
//这里加入下一个步骤写的ajax
}
function SetRemainTime1() {
if (curCount1 == 0) {
window.clearInterval(InterValObj1);//停止计时器
$("#btnSendCode1").removeAttr("disabled");//启用按钮
$("#btnSendCode1").val("重新发送");
}
else {
curCount1--;
$("#btnSendCode1").val(+ curCount1 + "秒再获取");
}
}
</script>
3.两次输入密码必须一样。
<script>
layui.use(['form', 'layer', 'jquery'],
function () {
$ = layui.jquery;
var form = layui.form;
var layer = layui.layer;
//自定义验证规则
form.verify({
codenumber: function (value) {
if (value.length != 6) {
return '验证码必须为6位数字';
}
},
pwd: [/(.+){6,12}$/, '密码必须6到12位'],
repass: function (value) {
if ($('#L_pass').val() != $('#L_repass').val()) {
return '两次密码不一致';
}
}
});
});
</script>
4.定义SecurityCode工具类和EmailUtil工具类。
(1)SecurityCode.java用来生成随机数。
package com.example.demo.util;
public class SecurityCode {
public static String getCode(){
//获取6为随机验证码
String[] letters = new String[] {"0","1","2","3","4","5","6","7","8","9"};
String stringBuilder ="";
for(int i = 0; i < 6; i++){
stringBuilder = stringBuilder + letters[(int)Math.floor(Math.random()*letters.length)];
}
return stringBuilder;
}
}
(2)EmailUtil.java用来发送信息到邮箱。
package com.example.demo.util;
import org.springframework.stereotype.Component;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;
/**
* 发邮件工具类
*/
@Component
public class EmailUtil {
public static boolean sendMail(String to, String text, String title){
String USER="填你自己的qq号码@qq.com"; // 发件人邮箱地址
String PASSWORD="填自己的授权码"; // 如果是qq邮箱可以使户端授权码
try {
final Properties props = new Properties();
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.host", "smtp.qq.com");
// 发件人的账号
props.put("mail.user", USER);
//发件人的密码
props.put("mail.password", PASSWORD);
// 构建授权信息,用于进行SMTP进行身份验证
Authenticator authenticator = new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
// 用户名、密码
String userName = props.getProperty("mail.user");
String password = props.getProperty("mail.password");
return new PasswordAuthentication(userName, password);
}
};
// 使用环境属性和授权信息,创建邮件会话
Session mailSession = Session.getInstance(props, authenticator);
// 创建邮件消息
MimeMessage message = new MimeMessage(mailSession);
// 设置发件人
String username = props.getProperty("mail.user");
InternetAddress form = new InternetAddress(username);
message.setFrom(form);
// 设置收件人
InternetAddress toAddress = new InternetAddress(to);
message.setRecipient(Message.RecipientType.TO, toAddress);
// 设置邮件标题
message.setSubject(title);
// 设置邮件的内容体
message.setContent(text, "text/html;charset=UTF-8");
// 发送邮件
Transport.send(message);
return true;
}catch (Exception e){
e.printStackTrace();
}
return false;
}
}
5.点击发送验证码按钮,发送验证码到邮箱。
(1)获取到前端输入的邮箱号,然后发送验证码到输入的邮箱号。
data中,前面的"loginname"与控制层中方法的参数必须保持一致。
$.ajax({
type:"POST",
url:"http://localhost:8080/tbUser/getCode",
//1.从前端取值
data:{
//loginname是登录名(用邮箱进行登录)
"loginname":$("#loginname").val(),
},
dataType:"JSON",
success:function(res){
console.log(res)
}
});
(2)在TbUserController方法上面要加上@CrossOrigin("*")。
本次实验采用的是前后端分离的方式,加上@CrossOrigin("*")后才不会报错。
(3)在TbUserController中定义全局变量randomNum,表示生成的随机数。
String randomNum= SecurityCode.getCode();
(4)在TbUserController中定义方法getCode。
void表示该函数不需要返回参数。
String loginname表示前端传过来的参数。
String loginname要和前面的ajax中的data里面的第一个"loginname"保持一致,否则传过来的值为空。
sendMail("收件人","内容","标题")
@RequestMapping("/getCode")
//点击按钮,直接发送验证码到qq邮箱。
public void getCode(String loginname){
EmailUtil.sendMail(loginname,randomNum,"欢迎注册我们的系统,请接收您的验证码");
}
}
然后发送验证码的代码就写完啦。
6.输入正确的验证码,输入密码,前端点击添加按钮,进行注册,将登录名和密码添加到数据库。
(1)前端写ajax。
//1.1开始对form表单进行操作
form.on('submit(add)',function(data){
//2.定义一个变量,存取form表单提交的值
var getDatas=data.field//filed:{name : value}
console.log(getDatas);
// 3.发送请求
$.ajax({
url:"http://localhost:8080/tbUser/register",
method:"GET",
data:{
loginname: getDatas.loginname,
password: getDatas.pwd,
securityCode:getDatas.securityCode
},
dataType:"JSON",
success:function(res){
layer.msg(res.msg);
}
});
return false;//阻止表单跳转
});
(2)在TbUserController中添加register方法。
public MsgCodeData register中的MsgCodeData表示该函数返回值类型为MsgCodeData,即状态码和消息内容。
tbUser表示前端传过来的登录名和密码,securityCode表示前端输入的验证码,randomNum表示发送到邮箱的验证码。
需要将前端输入的验证码和后端生成的验证码(发送至邮箱的验证码)进行匹配,所以tbUserService中的register方法需要加入前面定义的randomNum参数。
@RequestMapping("/register")
//从前端接收注册的用户名和密码,以及验证码
public MsgCodeData register(TbUser tbUser,String securityCode){
MsgCodeData resultData= tbUserService.register(tbUser,securityCode,randomNum);
return resultData;
}
(3)在TbUserService中添加register方法。
MsgCodeData register(TbUser tbUser, String securityCode, String randomNum);
(4)在TbUserServiceImpl方法中添加register方法,进行逻辑判断。
将前端输入的登录名和数据库中的登录名进行匹配,如果该用户已存在,那么提示该用户已经注册,不能进行注册。
如果数据库中没有该用户,那么可以进行注册。如果前端输入的验证码和发送至邮箱的验证码一致,那么注册成功;如果验证码错误,提示验证码错误。
@Override
public MsgCodeData register(TbUser tbUser, String securityCode, String randomNum) {
String loginnameFromHtml = tbUser.getLoginname();
TbUser userRsFromMySQL = tbUserDao.login(loginnameFromHtml);
System.out.println("1:" + randomNum);
System.out.println("2:" + securityCode);
if (userRsFromMySQL == null) {
if (securityCode.equals(randomNum)) {
Integer i = tbUserDao.register(tbUser);
if (i == 0) {
return new MsgCodeData(201, "注册失败!");
} else {
return new MsgCodeData(200, "注册成功~");
}
} else {
return new MsgCodeData(202, "验证码错误!");
}
} else {
return new MsgCodeData(203, "该用户已存在!");
}
}
(5)在TbUserDao中添加login方法和register方法。
TbUser login(String loginname);
Integer register(TbUser tbUser);
(6)在TbUserDao.xml中写sql语句。
<select id="login" resultMap="TbUserMap">
select * from tb_user where loginname = #{loginname}
</select>
<insert id="register" keyProperty="id" useGeneratedKeys="true">
insert into tb_user(loginname, password)
values (#{loginname}, #{password})
</insert>
到这里,代码就写完啦。
7.最后,不要忘了在DemoApplication中添加:@MapperScan("com.example.demo.dao")以及在application.properties中配置数据库。
@MapperScan("com.example.demo.dao")
spring.jpa.database = mysql
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=数据库密码
spring.datasource.url=jdbc:mysql://localhost:3306/emailtest00?serverTimezone=Asia/Shanghai&useSSL=false&useUnicode=true&characterEncoding=UTF-8
mybatis.mapper-locations=classpath/*.xml
8.项目结构图:
PS:如果有问题的,欢迎小伙伴们在评论区留言哦,需要源码的,也可以私我哦(不收取任何费用)。