最近手有點癢琢磨着作個啥,牽腸掛肚仍是寫個KTV點歌系統,模擬了一下KTV開戶的思路,7天累死我了,不過技術點還挺多的,但願你能夠看完(〜^㉨^)〜html
用Node(Express)教你寫KTV點歌系統,包括前臺內容和後臺管理系統,整合Express框架和Mongodb數據庫服務器開發;教你用Vue.JS,ElementUI和iViewUI寫出超漂亮的頁面,隨心點歌隨心聽前端
本項目分前臺開發,後臺開發和服務器開發vue
-- 服務器基本架構 ktv-select_music-system ├── README.md ├── index.js -- 後臺文件入口 ├── test.http -- 測試文件 ├── api -- 路由文件 │ ├── admin.js -- 配置管理員的操做 | ├── music.js -- 配置歌曲信息 | ├── user.js -- 配置用戶的相關操做 | └── safecode.js -- 配置安全碼 ├── config -- 配置 | ├── Date.js -- 配置日期格式化插件 | ├── delNoUse.js -- 封裝閒置刪除閒置資源方法 | ├── http.js -- 配置跨域 | ├── isBadAccount.js -- 封裝帳戶是否合法 | ├── newaccount.js -- 封裝隨機開戶方法 | ├── passport.js -- 驗證token是否合法 | ├── uploadImg.js -- 封裝上傳圖片方法 | └── uploadMusic.js -- 封裝上傳歌曲方法 ├── ktv-admin --後臺管理系統界面 ├── ktv-client --前臺用戶點歌項目界面 ├── dbModel | └── ** -- Mongodb數據庫的一些模型 ├── mongodb | └── mongodb.js -- 配置Mongodb,連接數據庫 ├── secret | ├── mongodbURI.js -- Mongodb地址 | └── jwtkey.js -- token的私鑰 ├── static -- 資源存放處 | ├── music -- 歌曲上傳目標文件夾 | ├── poster -- 歌曲海報上傳目標文件夾 └── └── view -- 配置404文件
-- 後臺管理系統架構 ktv-admin ├── README.md ├── public | ├── index.html -- vue掛載頁面 | └── ** -- 你能夠在這裏連接少許靜態資源 ├── src -- 開發文件夾 | ├── App.vue -- Vue掛載根頁面 | ├── main.js -- Vue程序入口文件,掛載各類組件 | ├── router.js -- Vue路由配置文件 | ├── store.js -- Vuex的狀態管理文件 | ├── assets -- 靜態資源文件夾 | ├── components --公共組件 | | └── nav.vue -- 後臺導航欄 | ├── plugins --插件 | | ├── axios.js -- 配置跨域,攔截器等等 | | ├── Date.js -- 格式化日期 | | └── wsmLoading.js -- 加載動畫Loading | ├── stores -- 狀態管理文件夾 | | └── adminStore.js -- 管理員狀態 | ├── views -- 頁面文件夾 | | ├── 404.vue -- 404頁面 | | ├── adminlikes.vue -- 管理員處理ktv收藏歌曲 | | ├── allorders.vue -- 訂單管理 | | ├── Home.vue -- 後臺根頁面 | | ├── Index.vue -- 後臺首頁 | | ├── managemusic.vue -- 音樂管理 | | ├── user_service.vue -- 給用戶開戶 | | └── login.vue -- 後臺登陸 └── babel.config.js -- babel配置
-- 前臺用戶聽歌架構 ktv-client ├── README.md ├── public | ├── index.html -- vue掛載頁面 | └── ** -- 你能夠在這裏連接少許靜態資源 ├── src -- 開發文件夾 | ├── App.vue -- Vue掛載根頁面 | ├── main.js -- Vue程序入口文件,掛載各類組件 | ├── router.js -- Vue路由配置文件 | ├── store.js -- Vuex的狀態管理文件 | ├── assets -- 靜態資源文件夾 | ├── components --公共組件 | | ├── bottomNav.vue -- 底部音樂控制區域 | | └── topNav.vue -- 頂部信息區域 | ├── config --配置 | | ├── addSong.js --封裝選取歌曲方法 | | ├── isBadAccount.js --驗證帳戶合法性 | | ├── isLogin.js --是否登陸 | | ├── nextSong.js --封裝下一首歌曲方法 | | └── prevSong.js --封裝上一首歌曲方法 | ├── plugins --插件 | | ├── axios.js -- 配置跨域,攔截器等等 | | └── wsmLoading.js -- 加載動畫Loading | ├── stores -- 狀態管理文件夾 | | └── song.js -- 存儲歌曲信息 | ├── views -- 頁面文件夾 | | ├── 404.vue -- 404頁面 | | ├── abc.vue -- 拼音點歌 | | ├── artist.vue -- 明星點歌 | | ├── Home.vue -- 後臺根頁面 | | ├── Index.vue -- 後臺首頁 | | ├── hot.vue -- 熱播歌曲 | | ├── ktvlikes.vue -- ktv推薦歌曲 | | ├── selected.vue -- 已選歌曲 | | ├── style.vue -- 風格點歌 | | └── language.vue -- 語種點歌 ├── babel.config.js -- babel配置 └── vue.config.js -- vue配置
npm run server 或者 node index &
命令啓動Node服務器,啓動成功會顯示:Server is running on port [8633].node
Mongodb is Connected.Please have a great coding.ios
npm run client
啓動前臺用戶項目,啓動成功後用瀏覽器訪問http://localhost:xxxx
npm run admin
啓動後臺管理系統項目,啓動成功後用瀏覽器訪問http://localhost:xxxx
secret/mongodbURI.js
配置文件信息。10.項目啓動成功git
因爲腦殼很差使的緣由加上js沒有元素格式化日期的方法,就瞎掰一個(值得學習)github
Date.jsweb
/** * * @author: Mr_Wei * @version: 1.0.0 * @description: 格式化日期 * @Date: 2019/10/16 09:32 * */ Date.prototype.format = function(format) { var o = { "M+": this.getMonth() + 1, //月份 "d+": this.getDate(), //日 "H+": this.getHours(), //小時 "m+": this.getMinutes(), //分 "s+": this.getSeconds(), //秒 "q+": Math.floor((this.getMonth() + 3) / 3), //季度 "f+": this.getMilliseconds() //毫秒 }; if (/(y+)/.test(format)) format = format.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); for (var k in o) if (new RegExp("(" + k + ")").test(format)) format = format.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); return format; } export default Date.prototype.format 而後咱們使用其格式日期 require(Date); // const now = new Date().format("yyyy/MM/dd HH:mm:ss.S"); const now = new Date().format("yyyy/MM/dd HH:mm:ss");
svg-captcha驗證碼的運用,防止暴力破解密碼,增強安全性.
詳細的文檔地址:svg-captchamongodb
使用驗證碼數據庫
// 後臺生成驗證碼 router.get("/getCaptcha", (req, res) => { var captcha = svgCaptcha.create({ // 翻轉顏色 inverse: false, // 字體大小 fontSize: 38, // 噪聲線條數 noise: 3, // 寬度 width: 80, // 高度 height: 32, }); // 保存到session,忽略大小寫 req.session = captcha.text.toLowerCase(); console.log(req.session); //0xtg 生成的驗證碼 //保存到cookie 方便前端調用驗證 res.cookie('captcha', req.session); res.setHeader('Content-Type', 'image/svg+xml'); res.send(String(captcha.data)); res.end(); }) // 前臺獲取驗證碼 --HTML <img width="80" style="background:#EEE9E9;margin-left:30px;" ref="captcha" height="32" src="http://localhost:3001/api/user/getCaptcha" @click="refreshCaptcha"> --js // 獲取驗證碼cookie getCookie(cname){ var name = cname + "="; var ca = document.cookie.split(';'); for(var i=0; i<ca.length; i++){ var c = ca[i].trim(); if (c.indexOf(name)==0) return c.substring(name.length,c.length); } return ""; }, // 刷新驗證碼 refreshCaptcha(){ this.$refs.captcha.src = "http://localhost:3001/api/user/getCaptcha?d=" + Math.random(); }, 最後用 填寫的驗證碼進行對比
formidable來處理文件上傳信息,用起來方便,很友好,若是你沒有接觸過文件操做,趕忙收藏起來
封裝歌曲方法uploadMusic.js
/** * * @author: Mr_Wei * @version: 1.0.0 * @description: 封裝上傳音樂方法 * @Date: 2019/10/16 08:35 * */ const fs = require('fs'); const path = require('path'); const formidable = require('formidable'); // 文件處理庫 const formatTime = require('silly-datetime'); // 格式化數據 module.exports = (req, res) => { let form = new formidable.IncomingForm(); //建立上傳表單 form.encoding = 'utf-8'; // 設置編碼格式 form.uploadDir = path.join(__dirname, '../static/music'); // 設置上傳目錄(這個目錄必須先建立好) form.keepExtensions = true; // 保留文件後綴名 form.maxFieldsSize = 20 * 1024 *1024; // 設置文件大小 /* 格式化form數據 */ form.parse(req, (err, fields, files) => { let file = files.file; /* 獲取異常 */ if(err) { return res.status(500).json({'status': 500, result: '服務器內部錯誤'}); } if(file.size > form.maxFieldsSize) { fs.unlink(file.path); return res.status(412).json({'status': 412, result: '音頻不能超過20M'}); } /* 存儲後綴名 */ let extName = ''; switch (file.type) { case 'audio/mp3': extName = 'mp3'; break; } if(extName.length == 0) { fs.unlink(file.path); return res.status(412).json({'status': 412, result: '只支持mp3格式音頻'}); } /* 拼接新的文件名 */ let time = formatTime.format(new Date(), 'YYYYMMDDHHmmss'); let num = Math.floor(Math.random() * 8999 + 10000); let songName = `${time}_${num}.${extName}`; let newPath = form.uploadDir + '/' + songName; /* 更更名字和路徑 */ fs.rename(file.path, newPath, (err) => { if(err) { return res.status(500).json({'status': 500, result: '音頻上傳失敗'}); } else { return res.send({'status': 200, 'msg': '音頻上傳成功', result: {src: songName}}); } }) }) };
關於ElementUI分頁詳細請見:ElementUI的Pagination分頁學習
上圖
-- html <el-pagination v-if='paginations.total > 0' :page-sizes="paginations.page_sizes" :page-size="paginations.page_size" :layout="paginations.layout" :total="paginations.total" :current-page.sync='paginations.page_index' @current-change='handleCurrentChange' @size-change='handleSizeChange'> </el-pagination> -- js data(){ return{ allUsers:[], // 用來存儲最終信息, 被顯示的dom點調用 allTableData:[], // 用戶承接分頁設置的數據 paginations: { // 分頁組件信息 page_index: 1, // 當前位於哪頁 total: 0, // 總數 page_size: 5, // 1頁顯示多少條 page_sizes: [5, 10, 15, 20], //每頁顯示多少條 layout: "total, sizes, prev, pager, next, jumper" // 翻頁屬性 }, } }, methods:{ // 獲取當前頁 handleCurrentChange(page) { let sortnum = this.paginations.page_size * (page - 1); let table = this.allTableData.filter((item, index) => { return index >= sortnum; }); // 設置默認分頁數據 this.getAllUsers = table.filter((item, index) => { return index < this.paginations.page_size; }); this.getAllUsers = table.filter((item, index) => { return index < this.paginations.page_size; }); }, // 切換size handleSizeChange(page_size) { this.paginations.page_index = 1; this.paginations.page_size = page_size; this.getAllUsers = this.allTableData.filter((item, index) => { return index < page_size; }); }, // 總頁數 setPaginations() { this.paginations.total = this.allTableData.length; this.paginations.page_index = 1; this.paginations.page_size = 5; // 設置默認分頁數據 this.getAllUsers = this.allTableData.filter((item, index) => { return index < this.paginations.page_size; }); }, }
沒了嗎?對,分頁就是這麼簡單!你學會了嗎?有些前端開發的同窗老是對分頁比較陌生,學會這個,讓你再也不產生煩惱!
jsonwebtoken是對用戶信息加密成不可逆向破解的token.關於passport-jwt,是用來對用戶請求時所帶的token信息進行過時驗證,若是超過簽證的合法時間,則會請前臺發出token失效的信息,提示用戶從新獲取合法的token信息,不然沒法繼續請求加密的信息;
用法
- passport-jwt const key = require("../config/keys").KEYORSECRET; const JwtStrategy = require('passport-jwt').Strategy, ExtractJwt = require('passport-jwt').ExtractJwt; var opts = {} opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken(); opts.secretOrKey = key; module.exports = passport => { passport.use(new JwtStrategy(opts, (jwt_payload, done) => { UserInfo.findById(jwt_payload.id) .then(user => { if (user) { return done(null, user); } else { return done(null, false); // or you could create a new account } }) })); } // 設置token // 規則 const rule = { id:String(userinfo._id), username:userinfo.username, email:userinfo.email, date:user.date, signdate:userinfo.signdate, signcount:userinfo.signcount, avatar:userinfo.avatar, phone:userinfo.phone }; // 簽證加密 // jwt.sign(規則, key(私鑰), {配置:好比過時時長}, (err, token){ 響應程序 }) jwt.sign(rule,key,{expiresIn:7200},(err, token) => { if(err) throw err; res.json({"token" : "Bearer " + token}) }) 自定義驗證方法 /** * * @author: Mr_Wei * @version: 1.0.0 * @description: 判斷是否過時用戶 * @Date: 2019/10/19 12:19 * */ const UserOrOrders = require("../dbModel/user"); module.exports = async params => { const flag = await new Promise((resolve) => { if(params){ const account = params.account; UserOrOrders.findOne({account}) .then(user => { if(user){ if(new Date().getTime() > new Date(user.endTime).getTime()){ console.log("過時用戶"); // 處理 return resolve(false); }else{ console.log("合法用戶"); return resolve(true); } }else{ return resolve(false); } }) }else{ console.log("不合法用戶"); return resolve(false); } }) return flag; } 使用: // 測試 isBadAccount(params)方法 router.post("/test", passport.authenticate("jwt", {session:false}), async (req, res) => { // console.log(req.user) if(await isBadAccount(req.user)){ // do something res.send("OK"); }else{ res.status(401).json({status:"401", result:"賬號過時,請聯繫管理員"}) } })
詳細的文檔地址:Passport-Jwt合法驗證,token加密
以上代碼均已上傳 github
https://github.com/1046224544/ktv-select_music-system
若是你們有興趣,歡迎star. 歡迎你們加入個人前端交流羣:866068198 ,一塊兒交流學習前端技術。博主目前一直在自學Node中,技術有限,若是能夠,會盡力給你們提供一些幫助,或是一些學習方法.
If you have some questions after you see this article, you can contact me or you can find some info by clicking these links.
若是對你有幫助,請賞個star~ github地址