前言
随着IT行业的发展,越来越多的人投入到计算机行业,也越来越多的草根站长尝试创建自己的网站,一是检验自己的编码水平,二是经营好一个网站可以给我们带来一定的收入。一个网站,一般前期都有会员的登录注册功能,随着用户上来,可能就会开始集成第三方登录登录,如QQ,微信,微博扫码登录等。本文档主要介绍基于邮箱验证码来实现合理的登录注册功能,保证注册用户的合法性。
创建工程
项目主要采用springboot来快速构建工程,构建方式此处省略,在构建项目过程中我们主要引用如下依赖即可,后期根据需求再逐个添加其他依赖:
集成静态界面
快速集成静态界面,将资料里面的boot-login-layui-demo文件夹下的html文件集成到项目中
新建FrontController.java控制类
package com.democxy.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class FrontController {
@GetMapping("/login")
public String login(){
return "login";
}
@GetMapping("/regit")
public String regit(){
return "reg";
}
@GetMapping("/index")
public String index(){
return "index";
}
}
启动项目,浏览器输入http://localhost:8080/login 访问登录界面
到此,静态界面初步引入成功:
抽离出公共界面
在前一节中 我们已经初步引入了我们的静态界面,并可正常输入请求地址请求到相关界面,本节主要是对静态界面做一些改进,如抽离头部部分,改善代码中引入路径等信息
抽离公共页面:
我们可以发现无论是首页 登录页还是注册页,都有一段重复的代码,也就是我们的头部和尾部
头部代码:
<div class="fly-header layui-bg-black">
<div class="layui-container">
<a class="fly-logo" href="index.html">
<img src="img/logo.png" alt="layui">
</a>
<ul class="layui-nav fly-nav layui-hide-xs">
<li class="layui-nav-item layui-this">
<a href="http://www.democxy.com" target="_blank"><i class="iconfont icon-jiaoliu"></i>源码分享</a>
</li>
<li class="layui-nav-item">
<a href="http://www.democxy.com" target="_blank"><i class="iconfont icon-iconmingxinganli"></i>案例</a>
</li>
</ul>
<ul class="layui-nav fly-nav-user">
<!-- 未登入的状态 -->
<!-- <li class="layui-nav-item">
<a class="iconfont icon-touxiang layui-hide-xs" href="user/login.html"></a>
</li>
<li class="layui-nav-item">
<a href="login.html">登入</a>
</li>
<li class="layui-nav-item">
<a href="reg.html">注册</a>
</li> -->
<!-- 登入后的状态 -->
<li class="layui-nav-item">
<a class="fly-nav-avatar" href="javascript:;">
<cite class="layui-hide-xs">贤心</cite>
<i class="iconfont icon-renzheng layui-hide-xs" title="认证信息:layui 作者"></i>
<i class="layui-badge fly-badge-vip layui-hide-xs">VIP3</i>
<img src="https://tva1.sinaimg.cn/crop.0.0.118.118.180/5db11ff4gw1e77d3nqrv8j203b03cweg.jpg">
</a>
<dl class="layui-nav-child">
<dd><a href="../user/set.html"><i class="layui-icon"></i>基本设置</a></dd>
<dd><a href="../user/message.html"><i class="iconfont icon-tongzhi" style="top: 4px;"></i>我的消息</a></dd>
<dd><a href="../user/home.html"><i class="layui-icon" style="margin-left: 2px; font-size: 22px;"></i>我的主页</a></dd>
<hr style="margin: 5px 0;">
<dd><a href="" style="text-align: center;">退出</a></dd>
</dl>
</li>
</ul>
</div>
</div>
尾部代码:
<div class="fly-footer">
<p><a href="http://www.democxy.com" target="_blank">DEMO程序园</a> 2020 ? <a href="http://www.democxy.com/" target="_blank">democxy.com 出品</a></p>
<p>
<a href="https://www.democxy.com/f/projects/index.html?projectType=1" target="_blank">源码分享</a>
<a href="https://www.democxy.com/f/projects/index.html?projectType=3" target="_blank">资料分享</a>
<a href="https://www.democxy.com/f/projects/index.html?projectType=8" target="_blank">博客分享</a>
</p>
</div>
我们新建一个common.html界面:将以上两部分公共代码块保存起来,并使用thymeleaf标签th:fragment声明这是一个代码块:
<div class="fly-header layui-bg-black" th:fragment="header">
<div class="layui-container">
<a class="fly-logo" href="index.html">
<img src="img/logo.png" alt="layui">
</a>
<ul class="layui-nav fly-nav layui-hide-xs">
<li class="layui-nav-item layui-this">
<a href="http://www.democxy.com" target="_blank"><i class="iconfont icon-jiaoliu"></i>源码分享</a>
</li>
<li class="layui-nav-item">
<a href="http://www.democxy.com" target="_blank"><i class="iconfont icon-iconmingxinganli"></i>案例</a>
</li>
</ul>
<ul class="layui-nav fly-nav-user">
<!-- 未登入的状态 -->
<!-- <li class="layui-nav-item">
<a class="iconfont icon-touxiang layui-hide-xs" href="user/login.html"></a>
</li>
<li class="layui-nav-item">
<a href="login.html">登入</a>
</li>
<li class="layui-nav-item">
<a href="reg.html">注册</a>
</li> -->
<!-- 登入后的状态 -->
<li class="layui-nav-item">
<a class="fly-nav-avatar" href="javascript:;">
<cite class="layui-hide-xs">贤心</cite>
<i class="iconfont icon-renzheng layui-hide-xs" title="认证信息:layui 作者"></i>
<i class="layui-badge fly-badge-vip layui-hide-xs">VIP3</i>
<img src="https://tva1.sinaimg.cn/crop.0.0.118.118.180/5db11ff4gw1e77d3nqrv8j203b03cweg.jpg">
</a>
<dl class="layui-nav-child">
<dd><a href="../user/set.html"><i class="layui-icon"></i>基本设置</a></dd>
<dd><a href="../user/message.html"><i class="iconfont icon-tongzhi" style="top: 4px;"></i>我的消息</a></dd>
<dd><a href="../user/home.html"><i class="layui-icon" style="margin-left: 2px; font-size: 22px;"></i>我的主页</a></dd>
<hr style="margin: 5px 0;">
<dd><a href="" style="text-align: center;">退出</a></dd>
</dl>
</li>
</ul>
</div>
</div>
<div class="fly-footer" th:fragment="footer">
<p><a href="http://www.democxy.com" target="_blank">DEMO程序园</a> 2020 ? <a href="http://www.democxy.com/" target="_blank">democxy.com 出品</a></p>
<p>
<a href="https://www.democxy.com/f/projects/index.html?projectType=1" target="_blank">源码分享</a>
<a href="https://www.democxy.com/f/projects/index.html?projectType=3" target="_blank">资料分享</a>
<a href="https://www.democxy.com/f/projects/index.html?projectType=8" target="_blank">博客分享</a>
</p>
</div>
引入代码块:
抽离出公共代码块 接下来我们就可以在使用它的地方使用标签:th:replace来引入
如:
<!-- 引入头部 -->
<div th:replace="common :: header"></div>
<!-- 引入底部 -->
<div th:replace="common :: footer"></div>
修改头部文件
在上一节已经把公共头部抽离出来了,本节主要修改头部代码,使其实现未登录时出现登录注册按钮,并设置跳转对应链接:
首先,为了便于开发,我们先要关闭thymeleaf的模板缓存,在配置文件中加入:
spring:
thymeleaf:
cache: false
修改头部代码(修改后代码如下):
<div class="fly-header layui-bg-black" th:fragment="header">
<div class="layui-container">
<a class="fly-logo" href="index.html">
<img src="img/logo.png" alt="layui">
</a>
<ul class="layui-nav fly-nav layui-hide-xs">
<li class="layui-nav-item layui-this">
<a href="http://www.democxy.com" target="_blank"><i class="iconfont icon-jiaoliu"></i>源码分享</a>
</li>
<li class="layui-nav-item">
<a href="http://www.democxy.com" target="_blank"><i class="iconfont icon-iconmingxinganli"></i>案例</a>
</li>
</ul>
<ul class="layui-nav fly-nav-user">
<!-- 未登入的状态 -->
<li class="layui-nav-item" th:if="${session.login==null}">
<a href="/login">登入</a>
</li>
<li class="layui-nav-item" th:if="${session.login==null}">
<a href="/regit">注册</a>
</li>
<!-- 登入后的状态 -->
<li class="layui-nav-item" th:if="${session.login!=null}">
<a class="fly-nav-avatar" href="javascript:;">
<cite class="layui-hide-xs">贤心</cite>
<img src="https://tva1.sinaimg.cn/crop.0.0.118.118.180/5db11ff4gw1e77d3nqrv8j203b03cweg.jpg">
</a>
</li>
<li class="layui-nav-item" th:if="${session.login!=null}">
<a href="/logout">安全退出</a>
</li>
</ul>
</div>
</div>
集成mybaits
引入依赖:
<!--mybatis依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<!--mysql依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
新增mybatis-config.xml配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- 指定 MyBatis 如何自动映射 数据基表的列 NONE:不隐射 PARTIAL:部分 FULL:全部 -->
<setting name="autoMappingBehavior" value="PARTIAL"/>
<!-- 设置但JDBC类型为空时,某些驱动程序 要指定值,default:OTHER,插入空值时不需要指定类型 -->
<setting name="jdbcTypeForNull" value="NULL"/>
</settings>
<!-- <plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
分页参数合理化
<property name="reasonable" value="true"/>
</plugin>
</plugins> -->
</configuration>
yaml文件新增数据库配置信息:
mybatis:
config-location: classpath:mybatis-config.xml
mapper-locations: classpath:mapper/**/*.xml
spring:
datasource:
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/email-demo?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=UTF-8
完善后台代码:
新建实体类com.democxy.entity.Member
package com.democxy.entity;
import java.util.Date;
public class Member {
// 会员ID
private String id;
// 会员昵称
private String username;
// 会员密码
private String password;
// 会员注册时间
private Date regitTime;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Date getRegitTime() {
return regitTime;
}
public void setRegitTime(Date regitTime) {
this.regitTime = regitTime;
}
}
新建mapper接口类 com.democxy.mapper.MemberMapper
package com.democxy.mapper;
import com.democxy.entity.Member;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface MemberMapper {
int insert(Member member);
Member login(Member member);
}
新建service接口类 com.democxy.service.MemberService
pacage com.democxy.service;
import com.democxy.entity.Member;
import com.democxy.mapper.MemberMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
?
@Service
public class MemberService {
?
@Autowired
MemberMapper memberMapper;
?
public int insert(Member member){
return memberMapper.insert(member);
}
?
public Member login(Member member){
return memberMapper.login(member);
}
?
}
?
新建mapper配置文件:mapper/MemberMapper.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.democxy.mapper.MemberMapper">
<sql id="accountColumns">
a.id AS "id",
a.username AS "username",
a.password AS "password",
a.regit_time AS "regitTime"
</sql>
<sql id="accountJoins">
</sql>
<select id="login" resultType="com.democxy.entity.Member">
SELECT
<include refid="accountColumns"/>
FROM member a
<include refid="accountJoins"/>
WHERE a.username = #{username} and a.password = #{password}
</select>
<insert id="insert">
INSERT INTO member(
username,
password,
regit_time
) VALUES (
#{username},
#{password},
#{regitTime}
)
</insert>
</mapper>
新增测试代码:com.democxy.EmailDemoApplicationTests
package com.democxy;
import com.democxy.entity.Member;
import com.democxy.service.MemberService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import javax.xml.ws.Service;
import java.util.Date;
@SpringBootTest
class EmailDemoApplicationTests {
@Autowired
MemberService memberService;
@Test
void contextLoads() {
Member member = new Member();
member.setUsername("admin");
member.setPassword("123456");
member.setRegitTime(new Date());
memberService.insert(member);
}
}
启动测试后我们会发现数据库成功插入了一条记录,至此后台代码基本完善。
集成email实现邮件发送功能
引入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
yaml文件新增邮箱配置信息:
spring:
mail:
host: smtp.qq.com
port: 465
username: 2534754276@qq.com
password: xxxx #授权码
default-encoding: utf-8
properties:
mail:
smtp:
ssl:
enable: true #一定要开启ssl,不然会503 验证失败的
新增邮件发送服务类com.democxy.service.EmailService
package com.democxy.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
@Service
public class EmailService {
@Autowired
private JavaMailSender javaMailSender;
@Value("${spring.mail.username}")
private String sender;
public void sendMail(String to, String subject, String content) {
SimpleMailMessage mailMessage=new SimpleMailMessage();
mailMessage.setFrom(sender);
mailMessage.setTo(to);
mailMessage.setSubject(subject);
mailMessage.setText(content);
try {
javaMailSender.send(mailMessage);
}catch (Exception e){
e.printStackTrace();
System.out.println("发送简单邮件失败");
}
}
public void sendHtmlMail(String to,String subject, String content) {
MimeMessage message = javaMailSender.createMimeMessage();
try {
//true表示需要创建一个multipart message
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(sender);
helper.setTo(to);//邮件接收者
helper.setSubject(subject);//邮件主题
helper.setText(content, true);//邮件内容
javaMailSender.send(message);
} catch (MessagingException e) {
}
}
}
测试类新增测试方法:
package com.democxy;
import com.democxy.entity.Member;
import com.democxy.service.EmailService;
import com.democxy.service.MemberService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import javax.xml.ws.Service;
import java.util.Date;
@SpringBootTest
class EmailDemoApplicationTests {
@Autowired
MemberService memberService;
@Autowired
EmailService emailService;
@Test
void contextLoads() {
Member member = new Member();
member.setUsername("admin");
member.setPassword("123456");
member.setRegitTime(new Date());
memberService.insert(member);
}
@Test
void sendEmail() {
emailService.sendHtmlMail("2534754276@qq.com","网站注册","验证码:<span style='color:red'>8989</span>");
}
}