前言
由於一直在用 vue 寫業務,為了熟悉下 react 開發模式,所以選擇了 react。數據庫一開始用的是 mongodb,后來換成 mysql 了,一套下來感覺 mysql 也挺好上手的。react-router、koa、mysql 都是從0開始接觸開發的,期間遇到過很多問題,印象最深的是 react-router 參考官方文檔配置的,楞是跑不起來,花費了好幾個小時,最后才發現看的文檔是v1.0, 而項目中是v4.3, 好在可參考的資料比較多,問題都迎刃而解了。
博客介紹
- 前端項目通過 create-react-app 構建,server端通過 koa-generator 構建
- 前后端分離,博客頁、后台管理都在 blog-admin 里,對含有 /admin 的路由進行登錄攔截
- 前端: react + antd + react-router4 + axios
- server端: koa2 + mysql + sequelize
- 部署:server端 運行在 3000 端口,前端 80 端口,nginx設置代理
喜歡或對你有幫助,歡迎 star
功能
- [x] 登錄
- [x] 分頁
- [x] 查詢
- [x] 標簽列表
- [x] 分類列表
- [x] 收藏列表
- [x] 文章列表
- [x] 發布文章時間軸
- [x] 文章訪問次數統計
- [x] 回到頂部
- [x] 博客適配移動端
- [ ] 后台適配移動端
- [ ] 對文章訪問次數進行可視化
- [ ] 留言評論
- [ ] 渲染優化、打包優化
效果
標簽

分類

收藏

文章

編輯

博客頁

響應式


運行項目
前端
git clone https://github.com/gzwgq222/blog-admin.git
cd blog-admin
npm install
localhost:2019
server 端
本地安裝 mysql,新建 dev 數據庫
git clone https://github.com/gzwgq222/blog-server.git
cd blog-server
npm install
server 端
前端 react + antd 開發,較為平緩,在此就不再敘述。主要記錄下 koa + mysql 相關事宜
全局安裝 koa-generator
npm install -g koa-generato
創建 node-server 項目
koa node-server
安裝依賴
cd node-server
npn install
運行
npm dev
出現 Hello Koa 2! 表示運行成功

先看routes文件
index.js
const router = require('koa-router')()
router.get('/', async (ctx, next) => {
await ctx.render('index', {
title: 'Hello Koa 2!'
})
})
router.get('/string', async (ctx, next) => {
ctx.body = 'koa2 string'
})
router.get('/json', async (ctx, next) => {
ctx.body = {
title: 'koa2 json'
}
})
module.exports = router
users.js
const router = require('koa-router')()
router.prefix('/users')
router.get('/', function (ctx, next) {
ctx.body = 'this is a users response!'
})
router.get('/bar', function (ctx, next) {
ctx.body = 'this is a users/bar response'
})
module.exports = router
分別訪問下列路由
localhost:3000/string
localhost:3000/users
localhost:3000/bar
大概你已經猜到了,koa-router 定義路由訪問時返回相應的內容,那我們只需要把相應的 data 返回去就行了,只是我們的數據得從數據庫查詢出來。
本地安裝 mysql
項目安裝 mysql
npm install mysql --save
項目安裝 sequelize
sequelize 是 ORM node框架,對SQL查詢語句的封裝,讓我們可以用OOP的方式操作數據庫
npm install --save sequelize
新建 sequelize.js,建立連接池
const Sequelize = require('sequelize');
const sequelize = new Sequelize('dev', 'root', '123456', {
host: 'localhost',
dialect: 'mysql',
operatorsAliases: false,
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
}
})
sequelize
.authenticate()
.then(() => {
console.log('MYSQL 連接成功......');
})
.catch(err => {
console.error('鏈接失敗:', err);
});
// 根據模型自動創建表
sequelize.sync()
module.exports = sequelize
創建 model、controllers 文件夾 定義model:定義表結構;controller:定義對數據庫的查詢方法

以 tag.js 為例
model => tag.js
const sequelize = require('../sequelize ')
const Sequelize = require('sequelize')
const moment = require('moment') // 日期處理庫
// 定義表結構
const tag = sequelize.define('tag', {
id: {
type: Sequelize.INTEGER(11), // 設置字段類型
primaryKey: true, // 設置為主建
autoIncrement: true // 自增
},
name: {
type: Sequelize.STRING,
unique: { // 唯一
msg: '已添加'
}
},
createdAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
get() {
// this.getDataValue 獲取當前字段value
return moment(this.getDataValue('createdAt')).format('YYYY-MM-DD HH:mm')
}
},
updatedAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
get() {
return moment(this.getDataValue('updatedAt')).format('YYYY-MM-DD HH:mm')
}
}
},
{
// sequelize會自動使用傳入的模型名(define的第一個參數)的復數做為表名 設置true取消默認設置
freezeTableName: true
})
module.exports = tag
controller => tag.s 定義了 create、findAll、findAndCountAll、destroy 方法
const Tag = require('../model/tag')
const Op = require('sequelize').Op
const listAll = async (ctx) => {
const data = await Tag.findAll()
ctx.body = {
code: 1000,
data
}
}
const list = async (ctx) => {
const query = ctx.query
const where = {
name: {
[Op.like]: `%${query.name}%`
}
}
const {rows:data, count: total } = await Tag.findAndCountAll({
where,
offset: (+query.pageNo - 1) * +query.pageSize,
limit: +query.pageSize,
order: [
['createdAt', 'DESC']
]
})
ctx.body = {
data,
total,
code: 1000,
desc: 'success'
}
}
const create = async (ctx) => {
const params = ctx.request.body
if (!params.name) {
ctx.body = {
code: 1003,
desc: '標簽不能為空'
}
return false
}
try {
await Tag.create(params)
ctx.body = {
code: 1000,
data: '創建成功'
}
}
catch(err) {
const msg = err.errors[0]
ctx.body = {
code: 300,
data: msg.value + msg.message
}
}
}
const destroy = async ctx => {
await Tag.destroy({where: ctx.request.body})
ctx.body = {
code: 1000,
desc: '刪除成功'
}
}
module.exports = {
list,
create,
listAll,
destroy
在 routers 文件夾 index.js 中引入定義好的 tag controller ,定義路由
const router = require('koa-router')()
const Tag = require('../controllers/tag')
// tag
router.get('/tag/list', Tag.list)
router.get('/tag/list/all', Tag.listAll)
router.post('/tag/create', Tag.create)
router.post('/tag/destroy', Tag.destroy)
module.exports = router
/* 如每個 route 是單獨的文件,可以使用 router.prefix 定義路由前綴
router.prefix('/tag')
router.get('/list', Tag.list)
router.get('/list/all', Tag.listAll)
router.post('/create', Tag.create)
router.post('/destroy', Tag.destroy)
*/
因為 app 中 已經引入 routers 中的 index.js 調用了 app.use了,所以此處不需再引入
在瀏覽器里輸入 localhost:3000/tag/list 就可以看到返回的數據結構了,只不過 data 為空數組,因為我們還沒添加進去任何數據
到這里,model 定義表結構、sequelize操作數據庫、koa-router 定義路由 這一套流程算是完成了,其他表結構,接口 都是一樣定義的
總結
之前沒有寫過 node server 和 react,算是從零搭建該博客,踩了一些坑,也學到了很多東西,譬如react 開發模式、react-router、sequelize 操作mysql的crud、koa、nginx的配置等等。
麻雀雖小,也是一次完整的前后端開發體驗,脫離了瀏覽器的限制,像海賊王一樣,打開了新世界的大門,尋找 onepiece ......
后續會在個人博客中添加關於此次部署文章
Links
初嘗 react + Node,錯誤之處還望斧正,歡迎提 issue
