1. 前言
在第一季的第四篇教程中我留了一個坑,關(guān)于登錄界面的赐劣。在那篇教程中做登錄時無論成功還是失敗都會跳轉(zhuǎn)到另一個界面嫉拐,這個設(shè)計(jì)不能說不好,只能說不合適魁兼,用戶體驗(yàn)特別差婉徘。當(dāng)時說是以后會用Ajax技術(shù)重新寫的,本篇教程我們就來談?wù)勅绾问褂肁jax技術(shù)整出一個高逼格的登錄界面咐汞。
2. 使用Ajax技術(shù)實(shí)現(xiàn)一個登錄示例
在開始之前我們先來看一下最終實(shí)現(xiàn)的效果
![登錄效果圖](https://github.com/SemiWarm/SemiWarmAdminPhotos/raw/master/0063.gif)
有人可能會問盖呼,為什么無論是用戶名出錯了還是密碼出錯都只提示“用戶名或密碼有誤!”呢?其實(shí)在生產(chǎn)環(huán)境中如果你的提示太過細(xì)致化很有可能會招致暴力破解化撕,例如你用戶名通過了几晤,密碼出錯了,你提示“密碼有誤!”那不就等變相告訴別人用戶名是對的嗎植阴?所以在生產(chǎn)環(huán)境中我們的提示應(yīng)該模糊點(diǎn)兒不要太過細(xì)致蟹瘾。
如何實(shí)現(xiàn)?
首先用戶輸入用戶名和密碼墙贱,按登錄按鈕或者直接回車热芹,請求發(fā)出。
- 后臺接收到請求后將數(shù)據(jù)封裝成對象
- 拿個這個封裝好的對象執(zhí)行業(yè)務(wù)邏輯
- 返回執(zhí)行結(jié)果
- 前臺Ajax處理返回結(jié)果
- 提示用戶
步驟大致就是這樣惨撇。
先來看前臺代碼:
這是登錄表單
<div class="login-card">
<div class="login-form">
<h1 class="logo hide-text">半暖</h1>
<form id="signInForm">
<div class="group-inputs">
<div class="input-wrapper account">
<input id="adminName" name="adminName" type="text" aria-label="請輸入用戶名" placeholder="請輸入用戶名"
required>
</div>
<div class="input-wrapper password">
<input id="password" name="password" type="password" aria-label="請輸入密碼" placeholder="請輸入密碼"
required>
</div>
</div>
<div class="button-wrapper">
<button id="signIn-button" name="signIn-button" type="button" class="signIn-button">登錄</button>
</div>
</form>
<div id="message-info" class="message-info">
<span id="message"></span>
</div>
</div>
</div>
兩個必填項(xiàng)一個登錄按鈕和一個錯誤信息提示框伊脓,很簡潔。
這是請求邏輯
<script src="<%=request.getContextPath()%>/static/js/jquery.min.js"></script>
<script type="text/javascript">
$(function () {
// 將錯誤信息提示框設(shè)為不可見
$('#message-info').css('display', 'none');
// 監(jiān)聽回車事件
$('body').keydown(function (e) {
if (e.keyCode == 13) {
doLogin();
}
});
// 監(jiān)聽登錄按鈕事件
$('#signIn-button').click(function () {
doLogin();
});
});
// 登錄邏輯
var doLogin = function () {
$.ajax({
// 請求發(fā)送方式
type: 'post',
// 請求地址
url: '<%=request.getContextPath()%>/signIn',
// 請求數(shù)據(jù)魁衙,用戶名和密碼
data: {'adminName': $('#adminName').val(), 'password': $('#password').val()},
// 異步报腔,不寫默認(rèn)為True
async: false,
// 請求成功后的回調(diào)
success: function (signInResponse) {
// 登錄成功狀態(tài)碼為 1
if (signInResponse["success"] == 1) {
// 隱藏錯誤信息提示框
$('#message-info').css('display', 'none');
// 設(shè)置成功提示信息
$('#message').text(signInResponse["message"]);
// 跳轉(zhuǎn)到主頁
window.location.href = "<%=request.getContextPath()%>/main";
} else if (signInResponse["success"] == 0) {
// 登錄失敗狀態(tài)碼為 0
// 設(shè)置錯誤提示信息
$('#message').text(signInResponse["message"]);
// 顯示錯誤提示框
$('#message-info').css('display', 'block');
}
},
error: function (errorMessage) {
// 其它錯誤信息
$('#message').text(errorMessage);
$('#message-info').css('display', 'block');
}
});
}
</script>
實(shí)現(xiàn)過程已經(jīng)在代碼中注釋的很詳細(xì)了。
下面的是請求<%=request.getContextPath()%>/signIn
地址后得到的Json數(shù)據(jù)剖淀,僅供參考
{
"success": 1,
"message": "登錄成功!",
"administrator": null
}
后臺沒有傳入管理員信息纯蛾,原因是方式數(shù)據(jù)被劫持。其實(shí)前臺之需要判斷狀態(tài)就可以了纵隔,1就代表可以跳轉(zhuǎn)頁面了翻诉,0就代表登錄失敗。
以上代碼就可以實(shí)現(xiàn)登錄失敗時在當(dāng)前頁面顯示錯誤信息捌刮,登錄成功時跳轉(zhuǎn)到主頁了碰煌,但是我們是不是忘了啥?
3. 使用Session記錄登錄狀態(tài)
如果不在main界面判斷用戶是否登錄了绅作,那么是不是任何人鍵入main頁面的地址都可以訪問主頁了芦圾?如果是那樣那設(shè)置登錄頁面有個毛用?所以俄认,我們要在除了登錄頁面的其它頁面設(shè)置登錄狀態(tài)檢測
- 用戶登錄成功后設(shè)置Session信息
- 跳轉(zhuǎn)到除了登錄界面的其它界面時需要首先檢查登錄狀態(tài)
- 如果沒有登錄狀態(tài)則直接重定向到登錄界面
以上就是登錄的后續(xù)邏輯
我們再來分析个少,如果用戶打開了登錄界面是不是就代表需要重新登錄呢洪乍?所以,我們耍一個小聰明夜焦,在登錄界面的頭部添加以下代碼
<%
session.invalidate();
%>
這行代碼的意思是清空Session數(shù)據(jù)壳澳。
只要用戶來到登錄頁面,就清空之前所有的Session數(shù)據(jù)糊探。
然后我們在除了登錄界面的其它界面添加以下代碼
<%
Long adminId = (Long) session.getAttribute("adminId");
String adminName = (String) session.getAttribute("adminName");
Integer privilegeLevel = (Integer) session.getAttribute("privilegeLevel");
if (null == adminId) {
response.sendRedirect(request.getContextPath() + "/signIn");
return;
}
%>
這段代碼的意思是判斷當(dāng)前Session中是否存在‘a(chǎn)dminId’字段钾埂,之前我們說了,只要登錄成功就會寫入Session數(shù)據(jù)科平。
下面是登錄的接口
/**
* 管理員登錄接口
*
* @param session 會話
* @param administrator 管理員信息
* @return SignInResponse
* @throws Exception 異常信息
*/
public SignInResponse signIn(HttpSession session, Administrator administrator) throws Exception {
SignInResponse response = new SignInResponse();
Administrator administratorInfo = administratorMapper.verifyAdministratorByName(administrator);
if (null != administratorInfo) {
// 設(shè)置返回信息
response.setSuccess(1);
response.setMessage("登錄成功!");
// 存儲Session
session.setAttribute("adminId", administratorInfo.getAdminId());
session.setAttribute("adminName", administratorInfo.getAdminName());
session.setAttribute("privilegeLevel", administratorInfo.getPrivilegeLevel());
} else {
response.setSuccess(0);
response.setMessage("用戶名或密碼有誤!");
}
return response;
}
在主頁設(shè)置退出登錄的按鈕
<a href="<%=request.getContextPath()%>/signIn" class="btn btn-default btn-flat">退 出</a>
之需要在點(diǎn)擊退出按鈕的時候鏈接到登錄界面即可褥紫,因?yàn)榈卿浗缑嬖跍?zhǔn)備完成之前就已經(jīng)清空了Session數(shù)據(jù)了。
至此登錄界面完成瞪慧,喜歡的小伙伴記得關(guān)注哦髓考!