我的夢(mèng)想,想做一個(gè)很牛逼的產(chǎn)品: 微信小程序《有夢(mèng)必達(dá)》。
有夢(mèng)必達(dá)初衷是一個(gè)幫助迷茫的、還沒有夢(mèng)想的、還在尋找夢(mèng)想的、有夢(mèng)想?yún)s還不知道怎么實(shí)現(xiàn)的童鞋更好的尋找或?qū)崿F(xiàn)夢(mèng)想的微信小程序。
有夢(mèng)必達(dá)的初始設(shè)計(jì)功能有:登錄、注冊(cè)、找回密碼、夢(mèng)想列表、夢(mèng)想詳情、推薦課程、收藏、瀏覽記錄、閱讀數(shù)。
產(chǎn)品不夠完善,仍需要完善,不喜勿噴。
備注:如果有同學(xué)完全按照此博客開發(fā)產(chǎn)品,可能會(huì)遇到坑,例如版本問題導(dǎo)致一些未知bug或者安裝系統(tǒng)限制等等。在我開發(fā)過程中就遇到過很多小問題,不過只要堅(jiān)持解決問題,這些問題都難不倒我。即使一開始遇到未知bug還是有點(diǎn)慌,但是后面通過各種方法尋找答案,解決完畢時(shí)會(huì)很自豪。
總體開發(fā)流程如下:
1、有一顆完成夢(mèng)想的決心
2、購買阿里云域名并且備案
3、購買阿里云服務(wù)器Cent Os
4、服務(wù)器安裝Node、Npm、Cnpm、Mysql、Nginx并配置、PM2
5、本地安裝Navicat Premium,連接遠(yuǎn)程服務(wù)器的Mysql、創(chuàng)建數(shù)據(jù)表、安裝Xshell連接遠(yuǎn)程服務(wù)器、Xftp查看服務(wù)器文件
6、Node+Express創(chuàng)建功能接口
7、Vue+Element創(chuàng)建后臺(tái)管理系統(tǒng)
8、部署后臺(tái)管理系統(tǒng)至域名服務(wù)器下
9、微信小程序+Vant前端展示
10、發(fā)布微信小程序
如果想做一個(gè)產(chǎn)品,就應(yīng)該把他當(dāng)做一個(gè)夢(mèng)想來看待,因?yàn)橛辛藟?mèng)想,就會(huì)有沖勁,自己會(huì)覺得有意義,從而時(shí)刻保持沖勁,有熱情去完成他,而不是三天打魚兩天曬網(wǎng),頂多堅(jiān)持幾天就半途而廢,到最后,產(chǎn)品沒完成,自己也覺得自己能力有問題。所以,即使夢(mèng)想再難,我們也要完成他,即使會(huì)慢一點(diǎn)!
此處較為簡(jiǎn)單,直接去阿里云官網(wǎng)-購買域名即可 阿里云萬網(wǎng)鏈接地址
備注:購買域名后,需要做域名備案才能在線上訪問(咱們要做就做正規(guī)的) 阿里云首次備案參考鏈接地址
亦可參考其他博客方法備案,能實(shí)現(xiàn)備案目的就行
五、本地安裝Navicat Premium,連接遠(yuǎn)程服務(wù)器的Mysql、創(chuàng)建數(shù)據(jù)表、安裝Xshell連接遠(yuǎn)程服務(wù)器、Xftp查看服務(wù)器文件
由于三、四、五步驟篇幅過長(zhǎng), 直接移駕到開源中國預(yù)覽
nodejs部分:
1、package.json
{
"name": "nodeDream",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "parchments",
"license": "MIT",
"dependencies": {
"body-parser": "^1.19.0",
"cors": "^2.8.5",
"express": "^4.17.1",
"jsonwebtoken": "^8.5.1",
"multer": "^1.4.2",
"mysql": "^2.17.1",
"nodemon": "^2.0.2",
"request": "^2.88.2"
}
}
復(fù)制代碼
|
2、connect.js
const path = require("path");
const mysql = require("mysql");
const express = require("express");
const app = express();//實(shí)例化一個(gè)app
const router = express.Router();
const cors = require('cors');
const jwt = require('jsonwebtoken'); //用來生成token
const request = require('request');
const bodyParser = require('body-parser');
app.use(bodyParser.json());//post請(qǐng)求req.body為空的處理 json請(qǐng)求
app.use(bodyParser.urlencoded({extended: false}));// 表單請(qǐng)求
// 全局配置跨域
app.use(cors());
//本地訪問不了已上傳的圖片,需要開啟靜態(tài)資源路徑訪問
const pathname = __dirname;
//靜態(tài)文件訪問
app.use(express.static(pathname));
// 使用靜態(tài)文件 這樣可以獲取靜態(tài)文件的東西
app.use(express.static('vueDream/dist'))
//校驗(yàn)token
function verifyToken(req, res, next){
let secretOrPrivateKey = 'jwtDream';//密鑰
jwt.verify(req.headers.token, secretOrPrivateKey, function (__err, decode) {
//時(shí)間失效的時(shí)候/ 偽造的token
if (__err) {
return res.status(401).send({
code: 401,
data: null,
message: "登錄過期,請(qǐng)重新登錄"
});
} else {
next();
}
})
}
//這里處理全局?jǐn)r截,一定要寫在最上面
app.all('*', (req, res, next) => {
//設(shè)置響應(yīng)頭
res.header("Access-Control-Allow-Origin", "*"); //*表示允許的域名地址,本地則為'http://localhost'
res.header("Access-Control-Allow-Headers", "*");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.header("Content-Type", "application/json;charset=utf-8");
//如果是登錄 注冊(cè) 找回密碼 需要放行 無需校驗(yàn)token
let isLogin = req.url.indexOf('login');
let isRegister = req.url.indexOf('register');
let isForgotPassword = req.url.indexOf('forgotPassword');
let isCollection = req.url.indexOf('collection');
let isHistory = req.url.indexOf('history');
// let isWechatLogin = req.url.indexOf('wechatLogin');
// let isGetWxAccessToken = req.url.indexOf('getWxAccessToken');
//微信小程序 并且是收藏接口需要校驗(yàn)token
let systype = req.headers.systype;
if(systype === 'wechat'){
if(isCollection !== -1 || isHistory !== -1){
verifyToken(req, res, next)
} else {
next();
}
} else if(systype === 'pc'){
//pc 登錄注冊(cè)找回密碼放行
if(isLogin !== -1 || isRegister !== -1 || isForgotPassword !== -1){
next();
}else{
verifyToken(req, res, next)
}
}
})
//這一步目的是,當(dāng)訪問根路徑時(shí),把前端代碼讀取出來并顯示
app.get('/', (req, res) => {
//服務(wù)器地址vueDream/dist/index.html
res.sendFile(path.resolve(__dirname, 'vueDream', 'dist', 'index.html'));
})
//配置mysql
const option = {
host: "www.yousit",
// host: "49.985.02.01",
user: 'admin',
port: '3306',
password: "mmmmmmmm.",
database: "node",
connectTimeout: 5000, //連接超時(shí)
//multipleStatements: false //是否允許一個(gè)query中包含多條sql語句
}
let pool;
repool();
function Res ({ code = 200, message = '', data = {} }) {
this.code = code;
this.message = message;
this.data = data;
}
function resJson (_res, result) {
return _res.json(new Res(result))
}
//斷線重連機(jī)制
function repool() {
//創(chuàng)建連接池
pool = mysql.createPool({
...option,
waitForConnections: true, //當(dāng)無連接池可用時(shí),等待(true)還是拋錯(cuò)(false)
connectionLimit: 200, //連接數(shù)限制
queueLimit: 0 //最大連接等待數(shù)(0為不限制)
})
pool.on('error', err => {
err.code === 'PROTOCOL_CONNECTION_LOST' && setTimeout(repool, 2000)
})
app.all('*', (_,__, next) => {
pool.getConnection( err => {
err && setTimeout(repool, 2000) || next()
})
})
}
module.exports = { app, pool, router, resJson , jwt , request}復(fù)制代碼
|
3、app.js
const { app, pool } = require('./connect');
//test
app.all('/api', (req, res) => {
pool.getConnection((err, conn) => {
res.json({ type: 'test success'})
pool.releaseConnection(conn) // 釋放連接池,等待別的連接使用
})
})
//引入上傳路由
const multerUpload = require('./routes/upload');
const user = require('./routes/user');
const dreamList = require('./routes/dream');
const collectionList = require('./routes/collection');
const historyList = require('./routes/history');
//使用路由
app.use('/upload', multerUpload);
app.use('/user', user);
app.use('/dream', dreamList);
app.use('/collection', collectionList);
app.use('/history', historyList);
//查看鏈接成功
app.get('/api/test', function (req, res) {
res.json({ message: "連接成功" })
});
//開啟監(jiān)聽
app.listen(8888, () => {
console.log("服務(wù)器端口8888開啟中...");
})復(fù)制代碼
|
express接口部分:
1、其中列表增刪改查接口
//夢(mèng)想接口
const {app, pool, router, resJson, jwt } = require('../connect');
// 查詢
/*
按分頁顯示賬號(hào)列表的路由 /getData
*/
app.post("/api/dream/getData", (req, res) => {
//后期需要補(bǔ)充校驗(yàn)
console.log("前端傳過來的",req.body)
// 接收前端參數(shù)
let { pageSize, pageNo , name , userId} = req.body;
// 默認(rèn)值
pageSize = pageSize ? pageSize : 5;
pageNo = pageNo ? pageNo : 1;
name = name ? name : null;
// 構(gòu)造sql語句 (查詢所有數(shù)據(jù) 按照時(shí)間排序)
let sqlStr = `select * from dream`;
// 執(zhí)行sql語句
pool.getConnection((err, conn) => {
conn.query(sqlStr, (err, data) => {
if (err) throw err;
// 計(jì)算數(shù)據(jù)總條數(shù)
let total = data.length;
// 分頁條件 (跳過多少條)
let n = (pageNo - 1) * pageSize;
// sqlStr += ` limit ${n}, ${pageSize}`;//表示從pageNo條數(shù)據(jù)取,取pageSize條數(shù)據(jù) 此處空格不能去掉不然無響應(yīng)
// 拼接分頁的sql語句
if(name){
sqlStr += ` where name like '%${name}%'`;
// 執(zhí)行sql語句 (查詢對(duì)應(yīng)頁碼的數(shù)據(jù))
conn.query(sqlStr, (_err, _data) => {
if (_err) throw _err;
res.send({
code: 1,
data: {
rows: _data,
total: _data.length,
pageNo: pageNo,
pageSize: pageSize,
},
message: '查詢成功!'
});
});
}else{
sqlStr += ` limit ${n} , ${pageSize}`;
conn.query(sqlStr, (_err, data) => {
if (_err) throw _err;
res.send({
code: 1,
data: {
rows: data,
total: total,
pageNo: pageNo,
pageSize: pageSize,
},
message: '查詢成功!'
});
});
}
});
pool.releaseConnection(conn) // 釋放連接池,等待別的連接使用
})
});
//添加接口
app.post('/api/dream/add', (req, res) => {
//后期需要補(bǔ)充校驗(yàn)
const data = req.body;
const name = req.body.name;
const sqlSameName = `select name from dream where name='${name}'`;
//先查詢數(shù)據(jù)庫 dream 表里是否有前端傳來的name值了 如果有返回重復(fù)提示 否則插入數(shù)據(jù)庫
pool.getConnection((err, conn) => {
conn.query(sqlSameName, data, (_err, _results) => {
if(_err){console.log(_err); return false;}
//根據(jù)查詢表結(jié)果個(gè)數(shù)判斷,如果1為數(shù)據(jù)庫已經(jīng)存在此名稱,不可插入 0代表數(shù)據(jù)庫不存在此名稱,可插入
if(_results.length > 0){
return res.json({
code: 0,
message: "不可重復(fù)添加!",
data: null
})
}else{
const sqlStr = 'insert into dream set ?';
conn.query(sqlStr, data, (err, results) => {
console.log(data)
if (err) throw err;
res.json({
code: 1,
message: '添加成功',
data: results
});
})
}
})
pool.releaseConnection(conn) // 釋放連接池,等待別的連接使用
})
});
//修改
app.post('/api/dream/edit', function (req, res) {
//后期需要補(bǔ)充校驗(yàn)
const data = req.body;
const id = req.body.id;
// let { name, collectionStatus, price, age, experience, education, analysis, introduce, duty, ask, coverImagePath, planImagePathArray, viedoUrl} = req.body;
let { name, coverImagePath, content, viedoUrl , recommend} = req.body;
let modSql = `update dream set
name='${name}',
coverImagePath='${coverImagePath}',
content='${content}',
viedoUrl='${viedoUrl}',
recommend='${recommend}'
where id ='${id}'`;
let nameSql = `select * from dream where name='${name}' and id !='${id}'`;
//先查詢數(shù)據(jù)庫 dream 表里是否有前端傳來的name值了 如果有返回重復(fù)提示 否則更新數(shù)據(jù)庫
pool.getConnection((err, conn) => {
conn.query(nameSql, data, (err, results) => {
console.log(results)
if(results.length >= 1){
return res.json({
code: 0,
message: "名稱已經(jīng)存在!",
data: null
})
}else{
conn.query(modSql, data, (err, results) => {
res.json({
code: 1,
message: '修改成功',
data: results
});
})
}
})
pool.releaseConnection(conn) // 釋放連接池,等待別的連接使用
})
});
//查看
app.post('/api/dream/show', function (req, res) {
//后期需要補(bǔ)充校驗(yàn)
let data = req.body;
//id是商品id
let { id , userId} = req.body;
let modSql = `select * from dream where id='${id}'`;
pool.getConnection((err, conn) => {
conn.query(modSql, data, (err, results) => {
if (err) {
console.log("查詢失敗原因",err)
return res.json({
code: 0,
message: "查詢失敗",
affectedRows: err
})
}
// 1.查詢出當(dāng)前readCount
results[0].readCount = results[0].readCount+1;
let newReadCount = results[0].readCount;
// 2.更新列表的id readCount
let sqlDreamCountStr = `update dream set readCount='${newReadCount}' where id ='${id}'`;
conn.query(sqlDreamCountStr, data, (_err, _data) => {
if (_err) throw _err;
console.log('更新列表的id readCount成功');
});
// 返回
res.json({
code: 1,
message: '查詢成功',
data: results
});
})
pool.releaseConnection(conn) // 釋放連接池,等待別的連接使用
})
});
// 刪除
app.post('/api/dream/del', (req, res) => {
//后期需要補(bǔ)充校驗(yàn)
console.log(req.body)
// let sqlStr = `DELETE FROM dream WHERE id = ${req.body.id}`;//單個(gè)刪除
let sqlStr = `DELETE FROM dream WHERE id in (${req.body})`;
pool.getConnection((err, conn) => {
conn.query( sqlStr, (err , results) => {
if(err) {
console.log(err);
}else {
res.json({
code: 1,
message: '刪除成功',
data: results
});
}
})
pool.releaseConnection(conn) // 釋放連接池,等待別的連接使用
})
})
module.exports = router;復(fù)制代碼
|
2、更多功能接口 請(qǐng)前往github預(yù)覽
以vue-admin-template作為基礎(chǔ)后臺(tái)框架, 查看vue-admin-template地址 ,搭建我的小程序后臺(tái)管理系統(tǒng),為實(shí)現(xiàn)登錄、注冊(cè)、用戶列表增刪改查、夢(mèng)想列表增刪改查、夢(mèng)想詳情、收藏、收藏列表增刪改查、瀏覽記錄等功能