前言
由于一直在用 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
功能
登录
分页
查询
标签列表
分类列表
收藏列表
文章列表
发布文章时间轴
文章访问次数统计
回到顶部
博客适配移动端
后台适配移动端
对文章访问次数进行可视化
留言评论
渲染优化、打包优化
效果
标签
分类
收藏
文章
编辑
博客页
响应式
运行项目
前端
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