Node Koa2 mysql搭建后端服务器
前言
前段时间公司要开发自己的一套博客系统,网上找了很多源码,看了下都比较复杂,因为是公司内自己的技术博客,不需要很复杂,索性自己搭一套后端服务,找一套博客前端模版即可实现,话不多说开始搭建历程吧。
开发环境
- node.js v8.0.0+
- mysql ^2.1.0
- koa ^2.7.0
- redis ^3.0.2
- sequelize ^5.21.5
准备工作
项目中用到了es6 es7的一些语法 比如promise,async await ,还有熟悉mysql sequlize的一些语法
安装 mysql
到官网 https://www.mysql.com/downloads 下载对应版本,并安装数据库
安装 Sequelize
安装sequlize
npm install sequelize --save
安装 mysql2
npm install mysql2 --save
下载redis
具体操作不一一说明了,网上有教程
https://www.jianshu.com/p/bb7c19c5fc47
目录结构
先上图
- app/controllers 控制器处理业务逻辑
- app/models 逻辑实现的方法
- app/schema 定义sequlize模型,也就是表模型
- bin/www 项目启动文件
- config/env 不同开发环境配置文件
- config/config 读取config/env配置文件
- config/constants 定义一些枚举
- config/redis redis配置文件
- config/secretKeys session redis一些密钥
- middleware 项目所需中间件
- models sequlize 初始化连接池文件
- public 项目静态文件如 js css等
- routers 路由文件
- utils 公共工具包或方法
- views 视图页面
- .eslintrc.js eslint 检查文件
- app.js 入口文件
使用 Sequelize 初始化连接池
'use strict';
const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const basename = path.basename(__filename);
const config = require('../config/config');
const db = {};
let sequelize;
sequelize = new Sequelize(config.db.database, config.db.username, config.db.password, config.db);
sequelize.authenticate().then(()=> {
console.log('db success')
}).catch(() => {
console.log('db error')
})
sequelize.sync({alter: true})
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
配置 config
config 通过config 可以读取不同环境的env文件
/**
* [@description](/user/description) 配置文件
* [@author](/user/author) Tony
*/
process.env.NODE_CONFIG_DIR = __dirname + '/env';
const config = require('config');
module.exports = config
配置redis
/**
* [@description](/user/description) 连接redis的方法
* [@author](/user/author) Tony
*/
const redis = require('redis')
const config = require('./config')
const redisClient = redis.createClient(config.redisStore);
redisClient.auth(config.redisStore.pass, function() {
console.log('Redis client connected');
});
redisClient.on("error", function(err) {
console.log("Error " + err);
});
/**
* redis 操作插入
* [@param](/user/param) {*} key
* [@param](/user/param) {*} val
* [@param](/user/param) {*} timeout
*/
function set(key,val,timeout = 60*60) {
if(typeof val === 'object') {
val = JSON.stringify(val)
}
redisClient.set(key,val)
redisClient.expire(key,timeout)
}
/**
* redis 查找
* [@param](/user/param) {*} key
*/
function get(key) {
const promise = new Promise((resolve,reject)=> {
redisClient.get(key,(err,val)=> {
if(err) {
reject(err)
return
}
if(val == null) {
resolve(null)
return
}
try {
resolve(JSON.parse(val))
} catch (error) {
resolve(val)
}
})
})
return promise
}
module.exports = {
redisClient,
set,
get
}
配置密钥文件
/**
* [@description](/user/description) 密钥常量
* [@author](/user/author) tony
*/
module.exports = {
CRYPTO_SECRET_KEY: 'xxxxxxxx',
SESSION_SECRET_KEY: 'xxxxxxxxx'
}
上面都是配置文件,下面开始真正的开发啦
1. 定义数据表模型
/**
* 定义user schema
*/
module.exports = function(sequelize, DataTypes) {
return sequelize.define("user", {
userName: {
type: DataTypes.STRING,
allowNull: false,
comment: '用户名'
},
password: {
type: DataTypes.STRING,
allowNull: false,
comment: '密码'
},
nickName: {
type: DataTypes.STRING,
allowNull: true,
comment: '昵称'
}
{
freezeTableName: true
}
);
};
2. 定义models逻辑用到的方法
const db = require('../../models/index')
const Sequelize = db.sequelize
const Op = db.Sequelize.Op
const User = Sequelize.import('../schema/user')
const { formatUser } = require('./_format')
User.sync({ force: false })
class UserModel{
/**
* 获取用户信息
* [@param](/user/param) {*} userName
* [@param](/user/param) {*} password
*/
static async getUerInfo(userName,password){
const whereOpt = {
userName
}
if(password) {
Object.assign(whereOpt,{ password })
}
const result = await User.findOne({
where: whereOpt,
attributes: ['id','userName','nickName','picture','city']
})
if(result == null) {
return result
}
const formatRes = formatUser(result.dataValues)
return formatRes
}
/**
* 创建用户
* [@param](/user/param) {*} data
*/
static async createUser(data){
return await User.create(data)
}
}
module.exports = UserModel
3. 定义控制器
/**
* [@description](/user/description) 用户逻辑处理
* [@author](/user/author) Tony
*/
const userModel = require('../models/user')
const { SuccessModel,ErrorModel} = require('../../utils/ResModel')
const doCrypto = require('../../utils/cryp')
class UserControler {
/**
* 判断用户是否存在
* [@param](/user/param) {*} ctx
*/
static async isExist(ctx){
try {
const { userName } = ctx.request.body
const userInfo = await userModel.getUerInfo(userName)
if(userInfo) {
ctx.body = new SuccessModel(userInfo)
} else {
ctx.body = new ErrorModel({
errno: 10003,
message: '用户名已存在'
})
}
} catch (error) {
return Promise.reject(error)
}
}
/**
* 注册
* [@param](/user/param) {*} ctx
*/
static async register(ctx) {
try {
const { userName,nickName,password,gender } = ctx.request.body
const userInfo = await userModel.getUerInfo(userName)
if(userInfo) {
ctx.body = new ErrorModel({
errno: 10003,
message: '用户名已存在'
})
}
const result = await userModel.createUser({ userName, nickName, password : doCrypto(password), gender })
ctx.body = new SuccessModel(result)
} catch (error) {
ctx.body = new ErrorModel({
errno: 10000,
message: '注册失败'
})
}
}
/**
* 登录
* [@param](/user/param) { } ctx
*/
static async login(ctx) {
const { userName,password } = ctx.request.body
const userInfo = await userModel.getUerInfo(userName,doCrypto(password))
if(!userInfo) {
ctx.body = new ErrorModel({
errno: 10004,
message: '用户名或密码不存在'
})
}
if(ctx.session.userInfo == null) {
ctx.session.userInfo = userInfo
}
ctx.body = new SuccessModel(userInfo)
}
}
module.exports = UserControler
4. 定义路由
/**
* [@description](/user/description) user API 路由
* [@author](/user/author) Tony
*/
const router = require('koa-router')()
const UserController = require('../../app/controllers/user')
const userValidate = require('../../utils/validator/user')
const { genValidator } = require('../../middleware/validator')
router.prefix('/api/user')
// 用户名是否存在
router.post('/isExist',UserController.isExist)
router.post('/register',genValidator(userValidate),UserController.register)
//登录
router.post('/login',UserController.login)
//返回router
module.exports = router
入口文件
const Koa = require('koa')
const app = new Koa()
const views = require('koa-views')
const json = require('koa-json')
const onerror = require('koa-onerror')
const bodyparser = require('koa-bodyparser')
const logger = require('koa-logger')
const session = require("koa-generic-session")
const redisStore = require('koa-redis')
const jwtKoa = require('koa-jwt')
const config = require('./config/config')
const { SECRET } = require('./config/constants')
const { SESSION_SECRET_KEY } = require('./config/secretKeys')
// 错误处理
onerror(app)
// 中间件
app.use(bodyparser({
enableTypes:['json', 'form', 'text']
}))
app.use(json())
app.use(logger())
app.use(require('koa-static')(__dirname + '/public'))
app.use(views(__dirname + '/views', {
extension: 'ejs'
}))
// session 配置
app.keys = [ SESSION_SECRET_KEY ]
app.use(session({
key: 'koa.sid', // cookie name 默认koa.sid
prefix: 'koa:sess', // redis key 前缀 默认 koa:sess
cookie: {
path: '/',
httpOnly: true,
maxAge: 24 * 60 * 60 * 1000 // 单位 ms
},
store: redisStore({
all: `${config.redisStore.host}:${config.redisStore.port}`
})
}))
// logger
app.use(async (ctx, next) => {
const start = new Date()
await next()
const ms = new Date() - start
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`)
})
const userViewRouter = require('./routes/view/user')
const userAPIRouter = require('./routes/api/user')
app.use(userViewRouter.routes(), userViewRouter.allowedMethods())
app.use(userAPIRouter.routes(), userAPIRouter.allowedMethods())
// error-handling
app.on('error', (err, ctx) => {
console.error('server error', err, ctx)
});
module.exports = app
项目启动
npm run start
项目编译
npm run build
接口测试
启动项目后可以通过postman等一些测试工具测试
项目部署
项目可通过nginx pm2等进行部署,具体操作可网上查询,今天先分享到这,一些细节代码没有贴出来,还请见谅。