需求描述
想要实现一个验证码登录功能, 也就是用户直接使用邮箱注册, 加入存在该邮箱验证过的用户就直接登录; 不存在就提示让其注册账号, 完成数据绑定
效果
代码实现
引入依赖
<!--邮件发送-->
<!--spring支持-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.1</version>
</dependency>
书写 properties 文件
mail.properties
#服务器主机名 smtp.xx.com
mail.smtp.host=smtp.qq.com
#若无法识别可以写IP地址58.251.106.181,此处可能会用在部署到云服务器运行时设置
mail.smtp.username=XXXX@qq.com
#密码/客户端授权码 - 需要在 qq邮箱中开启授权(设置里面)
mail.smtp.password=
#编码字符
mail.smtp.defaultEncoding=utf-8
#是否进行用户名密码校验
mail.smtp.auth=true
#设置超时时间
mail.smtp.timeout=20000
注册 bean 类
注意: 如果有多个 bean 注入, 比如还有数据库注入的话, 需要在每个 bean 的后面写 ignore-unresolvable="true", 否则会提示找不到 bean 类
applicationContext.xml
<!--邮件配置-->
<!--
读取邮件配置文件,
其中ignore-unresolvable="true"属性是配置文件中存在
多个property-placeholder时出现解析不了的占位符进行忽略掉,
-->
<context:property-placeholder location="classpath:mail.properties" ignore-unresolvable="true"/>
<!--配置邮件接口-->
<bean id="javaMailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="${mail.smtp.host}"/>
<property name="username" value="${mail.smtp.username}"/>
<property name="password" value="${mail.smtp.password}"/>
<property name="defaultEncoding" value="${mail.smtp.defaultEncoding}"/>
<property name="javaMailProperties">
<props>
<prop key="mail.smtp.auth">${mail.smtp.auth}</prop>
<prop key="mail.smtp.timeout">${mail.smtp.timeout}</prop>
</props>
</property>
</bean>
前端代码
这里其实使用 html 也可以, 因为使用的是 ajax 方式, 同时没有使用 jsp 的组件。如果用别的框架也是可以的, 具体参照代码, 发送邮件主要还是后端比较重要, 前端你只需要获取数据比对。
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>后台管理-登陆</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta http-equiv="Access-Control-Allow-Origin" content="*">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="format-detection" content="telephone=no">
<link rel="stylesheet" href="../lib/layui-v2.6.3/css/layui.css" media="all">
<!--[if lt IE 9]>
<script src="https://cdn.staticfile.org/html5shiv/r29/html5.min.js"></script>
<script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<style>
body {background-image:url("../images/bg.jpg");height:100%;width:100%;}
#container{height:100%;width:100%;}
input:-webkit-autofill {-webkit-box-shadow:inset 0 0 0 1000px #fff;background-color:transparent;}
.admin-login-background {width:300px;height:300px;position:absolute;left:50%;top:40%;margin-left:-150px;margin-top:-100px;}
.admin-header {text-align:center;margin-bottom:20px;color:#ffffff;font-weight:bold;font-size:40px}
.admin-input {border-top-style:none;border-right-style:solid;border-bottom-style:solid;border-left-style:solid;height:50px;width:300px;padding-bottom:0px;}
.admin-input::-webkit-input-placeholder {color:#a78369}
.layui-icon-username {color:#a78369 !important;}
.layui-icon-username:hover {color:#9dadce !important;}
.layui-icon-password {color:#a78369 !important;}
.layui-icon-password:hover {color:#9dadce !important;}
.admin-input-username {border-top-style:solid;border-radius:10px 10px 0 0;}
.admin-input-verify {border-radius:0 0 10px 10px;}
.admin-button {margin-top:20px;font-weight:bold;font-size:18px;width:300px;height:50px;border-radius:5px;background-color:#a78369;border:1px solid #d8b29f}
.admin-icon {margin-left:260px;margin-top:10px;font-size:30px;}
i {position:absolute;}
.admin-captcha {position:absolute;margin-left:205px;margin-top:-40px;}
</style>
<script src="../js/jquery-2.1.0.min.js" type="text/javascript"></script>
</head>
<body>
<div id="container">
<div></div>
<div class="admin-login-background">
<div class="admin-header">
<span>layuimini</span>
</div>
<form class="layui-form" action="">
<%-- <!-- 附加, 为了封装方便 -->--%>
<%-- <input type="hidden" name="id" value="2" class="layui-input">--%>
<div>
<i class="layui-icon layui-icon-username admin-icon"></i>
<input type="text" name="username" placeholder="请输入用户名" autocomplete="off" class="layui-input admin-input admin-input-username" value="">
</div>
<div>
<i class="layui-icon layui-icon-password admin-icon"></i>
<input type="password" name="password" placeholder="请输入密码" autocomplete="off" class="layui-input admin-input" value="">
</div>
<div>
<input type="text" name="verifycode" placeholder="请输入验证码" autocomplete="off" class="layui-input admin-input admin-input-verify" value="">
<img class="admin-captcha" width="90" height="30" src="${pageContext.request.contextPath}/admin/checkcode">
</div>
<button class="layui-btn admin-button" lay-submit="" lay-filter="login">登 陆</button>
</form>
<button class="layui-btn admin-button" οnclick="loginWithCode()" >验 证 码 登 陆</button>
</div>
</div>
<script src="../lib/layui-v2.6.3/layui.js" charset="utf-8"></script>
<script>
function loginWithCode(){
//使用验证码登录
layer.open({
//layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)
type:2,
content:'${pageContext.request.contextPath}/pages/loginwithcode.jsp',
area: ['30%', '30%'],
offset: 'auto',
id: 'add' //设定一个id,防止重复弹出
});
}
</script>
<script>
layui.use(['form'], function () {
var form = layui.form,
layer = layui.layer;
// 登录过期的时候,跳出ifram框架
if (top.location !== self.location) top.location = self.location;
// 进行登录操作
form.on('submit(login)', function (data) {
data = data.field;
console.log(data)
if (data.username == '') {
layer.msg('用户名不能为空');
return false;
}
if (data.password == '') {
layer.msg('密码不能为空');
return false;
}
if (data.captcha == '') {
layer.msg('验证码不能为空');
return false;
}
//发送异步登录请求
$.ajax({
url:'${pageContext.request.contextPath}/admin/login',
type:'POST',
data: {
username: data.username,
password: data.password,
verifycode: data.verifycode
},
success:
function (response) {
layer.msg(response.msg);
console.log(response)
//code = 1 代表登录成功
if(response.code == "0"){
setTimeout(function(){
//带参跳转
window.location.href = "${pageContext.request.contextPath}/pages/login.jsp"
}, 1000);
return false;
}
else if(response.code == "1"){
setTimeout(function(){
//带参跳转
window.location.href = "${pageContext.request.contextPath}/pages/main.jsp?username="
+ window.decodeURIComponent(response.data.username) + "&id=" + window.decodeURIComponent(response.data.id);
}, 1000);
}
},
})
return false;
});
});
</script>
</body>
</html>
loginwithcode.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><!DOCTYPE html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>layui</title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" href="../css/public.css" media="all">
<style>
body {
background-color: #ffffff;
}
</style>
</head>
<body>
<form class="layui-form layuimini-form" action="" style="margin-left: -80px">
<div class="layui-form-item">
<label class="layui-form-label required">邮箱</label>
<div class="layui-input-block">
<input type="text" id="email" name="email" lay-verify="email" lay-reqtext="邮箱不能为空" placeholder="请输入邮箱(XX@qq/163/gmail.com)" value="" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label required">验证码</label>
<div class="layui-input-inline">
<input type="text" name="code" lay-verify="required" lay-reqtext="验证码不能为空" placeholder="请输入验证码" value="" class="layui-input">
</div>
<div class="layui-input-inline">
<input type="button" class="layui-btn layui-inline" id="send" value="发送验证码" οnclick="sendCode()">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="saveBtn">登录</button>
</div>
</div>
</form>
<link rel="stylesheet" href="../lib/layui-v2.6.3/css/layui.css" media="all">
<script src="../lib/layui-v2.6.3/layui.js" charset="utf-8"></script>
<script src="../js/jquery-2.1.0.min.js" type="text/javascript"></script>
<script>
function sendCode(){
//设置按钮不可点击
document.getElementById("send").disabled = "true";
document.getElementById("send").className = "layui-btn layui-btn-disabled layui-inline";
var form = layui.form,
layer = layui.layer;
var mail = '';
mail = $("#email").val(); //获取邮箱
console.log(typeof mail)
if (mail.length == 0) {
alert("邮箱不能为空")
layer.msg('邮箱不能为空');
return false;
}
$.ajax({
url:'${pageContext.request.contextPath}/admin/sendCode',
type: 'post',
async : false, //同步请求
data : {
mail: mail
},
success:function (response) {
if(response.code == '1'){
layer.msg("发送成功", {icon: 6});
} else{
layer.msg("发送失败", {icon: 5});
}
}
})
}
layui.use(['form'], function () {
var form = layui.form,
layer = layui.layer,
$ = layui.$;
//监听提交
form.on('submit(saveBtn)', function (data) {
console.log(data)
$.ajax({
url:'${pageContext.request.contextPath}/admin/loginWithCode',
type:'post',
data : {
email: data.field.email,
code: data.field.code
},
success:function (response) {
if(response.code == '1'){
layer.msg("登录成功", {icon: 6});
setTimeout(function(){
var index = parent.layer.getFrameIndex(window.name);//获取窗口索引
parent.layer.close(index); //关闭弹出层
//带参跳转
parent.window.location.href = "${pageContext.request.contextPath}/pages/main.jsp?username="
+ window.decodeURIComponent(response.data.username) + "&id=" + window.decodeURIComponent(response.data.id);
}, 1000);
} else if(response.code == '0'){
layer.msg(response.msg, {icon: 5});
setTimeout(function(){
var index = parent.layer.getFrameIndex(window.name);//获取窗口索引
parent.layer.close(index);//关闭弹出层
//带参跳转
//使用验证码登录
parent.layer.open({
//layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)
type:2,
content: "${pageContext.request.contextPath}/pages/signin.jsp?email="+ window.decodeURIComponent($("#email").val()),
area: ['40%', '40%'],
offset: 'auto',
id: 'signin' //设定一个id,防止重复弹出
});
//parent.window.location.href = ;
}, 1000);
} else{
layer.msg(response.msg, {icon: 5});
}
}
})
return false;
});
});
</script>
<script src="../lib/layui-v2.6.3/layui.js" charset="utf-8"></script>
</body>
</html>
sign.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- 指定字符集 -->
<meta charset="utf-8">
<!-- 使用Edge最新的浏览器的渲染方式 -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- viewport视口:网页可以根据设置的宽度自动进行适配,在浏览器的内部虚拟一个容器,容器的宽度与设备的宽度相同。
width: 默认宽度与设备的宽度相同
initial-scale: 初始的缩放比,为1:1 -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<link rel="stylesheet" href="../assets/css/layui.css">
<script src="../assets/layui.js"></script>
<script src="../js/jquery-2.1.0.min.js"></script>
<title>用户注册</title>
<%-- 获取layui属性依赖--%>
<script>
layui.use('form', function () {
var form = layui.form;
form.render(); //刷新select选择框渲染
});
layui.use('element', function(){
var element = layui.element;
//一些事件触发
element.on('tab(demo)', function(data){
console.log(data);
});
});
</script>
<%-- 更新登录用户, 获取传递的参数 --%>
<script type="text/javascript">
var paramobj = {};
window.onload = function () {
//此时parameterURL为:name=张三&age=25
var parameterURL = location.search.substring(1, location.search.length);
//此时paramArr为一个数组:["name=张三","age=25"]
var paramArr = parameterURL.split("&");
var temp;
//定义2个变量接收key,value并存到paramobj中
for (i = 0; i < paramArr.length; i++) {
temp = paramArr[i].split("=");
if (temp.length === 1) {
paramobj[temp[0]] = "";
}
else if(temp.length>1){
for (j = 0; j < temp.length; j++) {
paramobj[temp[0]] = decodeURIComponent(temp[1]);
}
}
}
//此时参数已全部保存至paramobj中,这里显示到div
var showStr="";
var email = '';
var i = 0;
for (var a in paramobj) {
if(i === 0)
email = paramobj[a];
showStr += (a + ":" + paramobj[a]);
i++;
}
console.log(showStr, email)
var input = document.getElementById("email"); //获取input对象
input.setAttribute("value", email); //为input对象设置value属性和值
$("#email").text(email);
//document.getElementById("mail").innerText = email;
}
</script>
<script>
layui.use('form', function(){
var form = layui.form;
form.on('submit(formDemo)', function(data){
data = data.field
console.log(data)
console.log(data.field)
console.log(data.form)
//监听提交
$.ajax({
url : '${pageContext.request.contextPath}/admin/signIn',
type : 'post',
data : {
id: data.id,
username: data.username,
password: data.password,
email: data.email
},
success : function(response) {
if (response.code == '1') {
layer.msg("登录成功", {icon: 6});
setTimeout(function(){
var index = parent.layer.getFrameIndex(window.name);//获取窗口索引
parent.layer.close(index); //关闭弹出层
//带参跳转
parent.window.location.href = "${pageContext.request.contextPath}/pages/main.jsp?username="
+ window.decodeURIComponent(response.data.username) + "&id=" + window.decodeURIComponent(response.data.id);
}, 1000);
} else {
layer.msg("登录失败", {icon: 5});
}
}
})
return false;
});
});
</script>
</head>
<body>
<div class="container" style="width: 100%">
<div class="layui-card" style="text-align: center;">
<h3><div class="layui-card-header layui-bg-cyan">用户注册</div></h3>
</div>
<form class="layui-form" method="post" action="" style="width: 60%; float:left; margin-left:15% ">
<input type="hidden" name="id" value="2" class="layui-input">
<div class="layui-form-item">
<label class="layui-form-label">用户名</label>
<div class="layui-input-block">
<input type="text" name="username" required placeholder="请输入用户名" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label for="password" class="layui-form-label">密码</label>
<div class="layui-input-block">
<input type="text" id="password" name="password" required placeholder="请输入密码" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label for="email" class="layui-form-label">邮箱</label>
<div class="layui-input-block">
<input type="text" id="email" name="email" required class="layui-input" placeholder="请输入邮箱" readonly>
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="formDemo">立即提交</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</form>
</div>
</body>
</html>
后端代码
AdminController
@RequestMapping("/admin")
@Controller
public class AdminController {
@Autowired
private AdminService adminService;
@Autowired
private JavaMailSenderImpl javaMailSender;
@RequestMapping("/signIn")
@ResponseBody
public LayuiUtils<Admin> signIn(Admin admin){
adminService.signIn(admin);
System.out.println(admin.toString());
//打印封装数据
return new LayuiUtils<Admin>("注册成功", admin,1,0);
}
@RequestMapping("/sendCode")
public LayuiUtils<String> sendCode(String mail, HttpServletRequest request) throws MessagingException {
MimeMessage message = javaMailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setSubject("验证码"); // 标题
String checkcode = getCheckCode();
//将验证码放入HttpSession中
request.getSession().setAttribute("codes",checkcode);
// 内容, 第二个参数为true则以html方式发送, 否则以普通文本发送
helper.setText("<h1 style='red'>" + checkcode + "</h1>", true);
//发送附件
//helper.addAttachment("1.jpg",new File("C:\\Users\\zpk\\Desktop\\loading\\加载-063.gif"));
helper.setTo(mail); // 收件人
helper.setFrom("1719XXX051@qq.com"); // 发件人 - 写自己的邮箱名称
javaMailSender.send(message); // 发送
//打印封装数据
return new LayuiUtils<String>("发送成功", null,1,0);
}
@RequestMapping("/loginWithCode")
@ResponseBody
public LayuiUtils<Admin> loginWithCode(String email, String code, HttpServletRequest request){
//根据邮箱判断用户是否存在
Admin admin = adminService.findAdminByEmail(email);
//从 session 中获取验证码
HttpSession session = request.getSession();
String codes = (String)session.getAttribute("codes");
LayuiUtils<Admin> result;
//验证码错误
if(!code.equalsIgnoreCase(codes)){
System.out.println(codes + code);
//打印封装数据
result = new LayuiUtils<Admin>("验证码错误", null,-1,0);
return result;
} else if(admin == null){
result = new LayuiUtils<Admin>("用户不存在,请完成注册!", null,0,0);
return result;
} else{
result = new LayuiUtils<Admin>("登陆成功", admin,1,0);
return result;
}
}
}
OVER~