相關(guān)文章
基于阿里egg框架搭建博客(1)——開發(fā)準(zhǔn)備
基于阿里egg框架搭建博客(2)——Hello World
基于阿里egg框架搭建博客(3)——注冊與登錄
基于阿里egg框架搭建博客(4)——權(quán)限控制
基于阿里egg框架搭建博客(5)——置頂導(dǎo)航條
基于阿里egg框架搭建博客(6)——瀏覽悴势、發(fā)表文章
基于阿里egg框架搭建博客(7)——編輯文章
git
https://github.com/ZzzSimon/egg-example
喜歡就點(diǎn)個贊吧郑象!
正文
俗話說萬事開頭難歼跟,此章節(jié)涉及大量的知識點(diǎn)漩符,在每個代碼后面都有解釋,需要大家查看官方文檔木西。
user表設(shè)計
簡單來說乐埠,注冊與登錄就是對user表的讀寫。所以我們首先對user表進(jìn)行設(shè)計:
字段說明
字段 | 解釋 |
---|---|
id | uuid |
username | 用戶名 |
password | 密碼 |
phone | 手機(jī)號 |
create_time | 創(chuàng)建時間 |
update_time | 更新時間 |
avatar_url | 頭像url |
sql腳本
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` varchar(20) NOT NULL,
`username` varchar(18) NOT NULL,
`password` varchar(20) NOT NULL,
`phone` varchar(11) DEFAULT NULL,
`create_time` datetime NOT NULL,
`update_time` datetime NOT NULL,
`avatar_url` varchar(255) DEFAULT NULL,
PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
注冊
頁面設(shè)計
頁面設(shè)計如上圖所示禽篱,需要用戶輸入用戶名畜伐,密碼,手機(jī)號躺率,還可以上傳自己的頭像玛界。
前端代碼
官方文檔推薦我們使用nunjucks
作為模板。
使用方法:https://eggjs.org/zh-cn/intro/quickstart.html#%E6%A8%A1%E6%9D%BF%E6%B8%B2%E6%9F%93
我們在app\view\home
目錄下創(chuàng)建register.tpl
文件:
<html>
<head>
<title>注冊</title>
<link rel="stylesheet" href="/public/bootstrap/css/bootstrap.css">
<script type="text/javascript" src="/public/js/jquery.min.js"></script>
<script type="text/javascript" src="/public/bootstrap/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container ">
<form class="center-block" style="width: 50%;margin-top: 10%"
method="POST" action="/user/register?_csrf={{ ctx.csrf | safe }}" enctype="multipart/form-data">
<div class="form-group ">
<img src="/public/avatar/default.jpg" id="avatarPic" class="img-circle center-block" style="width: 64px;">
<input type="file" id="avatarBtn" name="file" style="visibility: hidden">
<p class="text-center help-block">點(diǎn)擊頭像更改悼吱,只支持jpg,png格式慎框,大小≤ 200 kb</p>
</div>
<div class="form-group">
<label for="username">賬號</label>
<input type="text" class="form-control" id="username" placeholder="用戶名" name="username">
</div>
<div class="form-group">
<label for="password">密碼</label>
<input type="password" class="form-control" id="password" placeholder="密碼" name="password">
</div>
<div class="form-group">
<label for="phone">手機(jī)號</label>
<input type="text" class="form-control" id="phone" placeholder="手機(jī)號" name="phone">
</div>
<div class="form-group">
<button type="submit" class="btn btn-info pull-right">注冊</button>
</div>
</form>
</div>
<script>
$('#avatarPic').bind('click', function () {
$('#avatarBtn').click();
});
$('#avatarBtn').bind('change',function (e) {
if (window.FileReader) {
var reader = new FileReader();
reader.readAsDataURL(e.target.files[0]);
//監(jiān)聽文件讀取結(jié)束后事件
reader.onloadend = function (e) {
$('#avatarPic').attr("src",e.target.result); //e.target.result就是最后的路徑地址
};
}
});
</script>
</body>
</html>
有3點(diǎn)需要注意:
- 靜態(tài)文件的引用路徑
/public
官方文檔:https://eggjs.org/zh-cn/intro/quickstart.html#%E9%9D%99%E6%80%81%E8%B5%84%E6%BA%90
bootstrap自行搜索并下載,也可以用cdn后添。
- form表單請求url中的
?_csrf={{ ctx.csrf | safe }}
部分
- 最后一段js代碼的作用:
由于bootstrap沒有input type=file
標(biāo)簽樣式笨枯,原版實(shí)在丑的不行,于是我把原版的隱藏了吕朵,在頭像圖片的點(diǎn)擊事件監(jiān)聽里面猎醇,手動觸發(fā)input type=file
文件上傳按鈕的click事件。
然后當(dāng)用戶選完頭像后努溃,通過window.FileReader
實(shí)時把圖片顯示出來硫嘶。
后端代碼
HomeController
我們在app\controller\
目錄下創(chuàng)建home.js
文件:
該controller主要返回主頁、登錄頁梧税、注冊頁等基礎(chǔ)頁面沦疾。
const Controller = require('egg').Controller;
class HomeController extends Controller {
async register(){
await this.ctx.render('home/register.tpl')
}
}
module.exports = HomeController;
UserController
我們在app\controller\
目錄下創(chuàng)建user.js
文件:
//app/controller/user.js
const Controller = require('egg').Controller;
const fs = require('mz/fs');
class UserController extends Controller{
async register(){
const ctx = this.ctx;
const { username, password, phone } = ctx.request.body;
const avatar = ctx.request.files[0];
//默認(rèn)頭像
let filepathNew = this.config.baseDir+'\\app\\public\\avatar\\default.jpg';
//如果用戶上傳了頭像
if (avatar) {
console.log('file:%j', avatar);
let filenameNew = ctx.helper.uuid() +'.'+ avatar.filename.split('.').pop();
filepathNew = this.config.baseDir+'\\app\\public\\avatar\\'+filenameNew;
//把臨時文件剪切到新目錄去
await fs.rename(avatar.filepath, filepathNew);
}
const nowTime = new Date();
const userNew = {
id : ctx.helper.uuid(),
username : username,
password : password,
phone : phone,
avatar_url : filepathNew.split("\\app")[1],
create_time : nowTime,
update_time : nowTime
};
const flag = await ctx.service.user.save(userNew);
if (flag){
// 設(shè)置 Session
ctx.session.user = {username:username};
ctx.cookies.set('avatarUrl',userNew.avatar_url,{httpOnly:false});
ctx.body = {
successFlag:'Y',
errorMsg:'登錄成功称近!'
};
ctx.redirect('/')
}else {
ctx.body = {
successFlag:'N',
errorMsg:'用戶名已存在!'
}
}
}
}
module.exports = UserController;
有4點(diǎn)需要注意:
- controller獲取上傳的文件
- cookie與session
- 重定向
官方文檔:https://eggjs.org/zh-cn/basics/controller.html#%E9%87%8D%E5%AE%9A%E5%90%91
- uuid工具類哮塞,helper的使用
附上我自己實(shí)現(xiàn)的uuid生成方法:
moment組件請自行npm安裝刨秆,官方:http://momentjs.cn/
const moment = require('moment');
//uuid格式:年月日時分秒3位毫秒+3位隨機(jī)數(shù),共20位 ===> 20190312162455043167
exports.uuid = function uuid() {
let uuid = moment().format("YYYYMMDDHHmmssSSS");
uuid += (Array(3).join(0) + Math.random()*100).slice(-3);
return uuid;
};
UserService
我們在app\service\
目錄下創(chuàng)建user.js
文件:
const Service = require('egg').Service;
class UserService extends Service {
async save(user){
const userQ =await this.app.mysql.get('user', {username : user.username});
if (userQ){
return false
}else {
const result =await this.app.mysql.insert('user', user);
// 判斷插入成功
const insertSuccess = result.affectedRows === 1;
if (insertSuccess) {
return true
}
}
return false
}
}
module.exports = UserService;
有1點(diǎn)需要注意:
- mysql的使用
router.js
我們在app\
目錄下的router.js
文件中添加以下內(nèi)容:
module.exports = app => {
const { router, controller } = app;
//頁面
router.get('/register.htm', controller.home.register);
//接口
router.post('/user/register',controller.user.register);
};
登錄
頁面設(shè)計
前端代碼
我們在app\view\home
目錄下創(chuàng)建login.tpl
文件:
<html>
<head>
<title>登錄</title>
<link rel="stylesheet" href="/public/bootstrap/css/bootstrap.css">
<script type="text/javascript" src="/public/js/jquery.min.js"></script>
<script type="text/javascript" src="/public/bootstrap/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container ">
<form class="center-block" style="width: 50%;margin-top: 20%"
method="POST" action="/user/login?_csrf={{ ctx.csrf | safe }}" enctype="application/x-www-form-urlencoded">
<div class="form-group">
<label for="username">賬號</label>
<input type="text" class="form-control" id="username" placeholder="用戶名" name="username">
</div>
<div class="form-group">
<label for="password">密碼</label>
<input type="password" class="form-control" id="password" placeholder="密碼" name="password">
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="rememberMe">記住登錄狀態(tài)
</label>
</div>
<div class="form-group">
<button type="submit" class="btn btn-info pull-right">登錄</button>
<div>
<a href="/register.htm" class="btn btn-link pull-right">注冊</a>
</div>
</div>
</form>
</div>
</body>
</html>
后端代碼
HomeController
我們在app\controller\home.js
文件中添加以下內(nèi)容:
async login(){
await this.ctx.render('home/login.tpl');
}
UserController
我們在app\controller\user.js
文件中添加以下內(nèi)容:
async login(){
const ctx = this.ctx;
ctx.logger.info('req body:: %j',ctx.request.body);
const { username, password, rememberMe } = ctx.request.body;
const user = await ctx.service.user.loginAndGetUser(username, password);
if (!user){
ctx.body = {
successFlag:'N',
errorMsg:'用戶名或密碼錯誤忆畅!'
}
}else {
// 設(shè)置 Session
ctx.session.user = {username:user.username};
ctx.cookies.set('avatarUrl',user.avatar_url,{httpOnly:false});
// 如果用戶勾選了 `記住我`衡未,設(shè)置 的過期時間
if (rememberMe) ctx.session.maxAge = this.config.rememberMe;
ctx.body = {
successFlag:'Y',
errorMsg:'登錄成功!'
};
ctx.redirect('/')
}
}
有1點(diǎn)需要注意:
- 用戶勾選'記住我'后的session過期時間讀取了配置文件中的值家凯。配置:
UserService
我們在app\service\user.js
文件中添加以下內(nèi)容:
async loginAndGetUser(username, password) {
const user =await this.app.mysql.get('user', {username : username});
if (!user || user.password !== password){
return false
} else {
return user;
}
}
router.js
我們在app\router.js
文件中添加以下內(nèi)容:
router.get('/login.htm',controller.home.login);
router.post('/user/login',controller.user.login);
配置文件參考
config.default.js
參考官方文檔后缓醋,你的配置文件應(yīng)該如下(object 對象寫法):
const path = require('path');
module.exports = appInfo => {
return {
keys: "123456",
rememberMe : 24 * 60 * 60 * 1000, //選擇記住我之后,session有效時長
security : {
domainWhiteList:['.127.0.0.1'], // 安全白名單绊诲,以 . 開頭
},
multipart : {
mode: 'file',
tmpdir: path.join(appInfo.baseDir, 'app/public/temp'),
},
session : {
key: 'EGG_SESS',
maxAge: 10 * 1000, // 單位毫秒
httpOnly: true,
encrypt: true,
},
view : {
defaultViewEngine: 'nunjucks',
mapping: {
'.tpl': 'nunjucks',
},
},
mysql : {
// 單數(shù)據(jù)庫信息配置
client: {
// host
host: 'localhost',
// 端口號
port: '3306',
// 用戶名
user: '數(shù)據(jù)庫賬號',
// 密碼
password: '數(shù)據(jù)庫密碼',
// 數(shù)據(jù)庫名
database: '你的數(shù)據(jù)庫名',
},
// 是否加載到 app 上送粱,默認(rèn)開啟
app: true,
// 是否加載到 agent 上,默認(rèn)關(guān)閉
agent: false,
},
};
};
plugin.js
exports.nunjucks = {
enable: true,
package: 'egg-view-nunjucks'
};
exports.mysql = {
enable: true,
package: 'egg-mysql',
};
結(jié)尾
如果看完覺得有用掂之,請給作者一個喜歡吧抗俄!謝謝啦!