图书管理系统
项目:https://github.com/dreamsgarden/node_books
采用 MVC
架构,基于 node.js 的 koa + art-template + mysql, bootstrap布局,实现图书的增删改查。
一、项目架构
1.SSR 服务端渲染
将组件或页面通过服务器生成html字符串,再把渲染的完整的页面发送到浏览器
2.CSR 客户端渲染
通过接口请求数据,前端通过JS动态处理和生成页面需要的结构和页面展示
二、项目搭建
1.初始化项目
npm init -y
books/
|
+- config <-- 配置文件
|
+- controllers <-- 控制层
|
+- middlewares <-- 错误中间件
|
+- models <-- 模型层
|
+- publics <-- 静态资源
|
+- views <-- 视图层
|
+- app.js <-- 入口文件
|
+- package.json <-- 项目描述文件
|
+- node_modules/ <-- npm安装的所有依赖包
2.入口文件
npm install koa
在 app.js
中
const Koa = require('koa')
const app = new Koa()
app.use(ctx => {
ctx.body = 'Hello Koa';
});
app.listen(config.port, () => {
console.log('server is running...')
})
3.注册路由
使用 koa-simple-router
路由
安装
npm install koa-simple-router
用法
const Koa = require('koa')
const router = require('koa-simple-router')
const app = new Koa()
app.use(router(_ => {
_.get('/', (ctx, next) => {})
_.post('/name/:id', (ctx, next) => {})
}))
在 controllers
下route.js
处理路由
const router = require('koa-simple-router')
const Controller = require('./index')
const controller = new Controller()
module.exports = (app) => {
app.use(
router((_) => {
_.get('/', controller.index())
// 首页
_.get('/index', controller.index())
})
)
}
在 controllers
下 index.js 处理业务逻辑
class IndexController {
constructor() {}
// 首页
index() {
return (ctx, next) => {
ctx.body = 'Hello Koa'
}
}
}
module.exports = IndexController
在 app.js
中 开启路由
// 开启路由
require('./controllers/route')(app)
4.模板配置
使用 art-template
模板引擎
安装
npm install --save art-template koa-art-template
在 app.js
中
const render = require('koa-art-template')
// 配置 koa-art-template
render(app, {
root: path.join(__dirname, 'views'), // 视图的位置
extname: '.html', // 后缀名
debug: process.env.NODE_ENV !== 'production', // 是否开启调试模式
})
app.use(async function (ctx) {
await ctx.render('user')
})
在 views
中创建 layout.html
和 index.html
,使用模板继承
5.静态资源
npm install koa-static
在 app.js
中
// 静态文件
app.use(static(path.join(__dirname, 'public')))
6.错误处理
在 middlewares
下 index.js
const middlewares = {
error(app) {
app.use(async (ctx, next) => {
try {
await next()
} catch (err) {
console.log(err)
ctx.status = 500
ctx.body = '服务器忙,请稍后重试!'
}
})
app.use(async (ctx, next) => {
await next()
if (ctx.status != 404) return
ctx.status = 404
ctx.body = `<script type="text/javascript" src="//qzonestyle.gtimg.cn/qzone/hybrid/app/404/search_children.js" charset="utf-8"></script>`
})
},
}
module.exports = middlewares
6.配置
在 config
下 index.js
let config = {
port: 3000,
mysql: {
host: 'localhost', // 主机地址
user: 'root1', // 用户名
password: '123456', // 密码
database: 'test', // 数据库名
}
}
module.exports = config
三、设计路由
请求方式 | 请求路径 | GET/POST参数 | 说明 |
---|---|---|---|
GET | /index | 获取图书 | |
GET | /addpage | 添加图书页 | |
POST | /add | 添加数据处理 | |
GET | /editpage | 修改图书页 | |
POST | /edit | 修改数据处理 | |
GET | /delete | 删除图书 |
四、数据模型
1.使用 MySQL
数据库,设计表结构,创建模型文件
2.调用模型,获取数据 并 传递给视图
npm init mysql
封装 mysql
const config = require('../config')
module.exports.query = (sql, data = null) => {
return new Promise((resolve, reject) => {
const mysql = require('mysql')
const connection = mysql.createConnection(config.mysql)
connection.connect()
connection.query(sql, data, (error, results) => {
if (error) return reject(error)
resolve(results)
})
connection.end()
})
}
图书数据模型(增删改查)
const db = require('./db')
/**
* 图书数据模型(增删改查)
* @type {[type]}
*/
class BookModel {
constructor() {}
/**
* 获取图书列表
* @return {[type]}
*/
async find() {
let meta = {
code: 0,
message: '',
data: [],
}
try {
let data = await db.query(`SELECT * FROM book`)
// console.log(data)
if (data.length > 0) {
meta.data = data
meta.message = '获取成功'
return Promise.resolve(meta)
} else {
meta.code = 1
meta.message = '获取失败'
return Promise.reject(meta)
}
} catch (err) {
// console.log(err)
meta.code = 1
meta.message = err.message
return Promise.reject(meta)
}
}
/**
* 根据 id 获取图书信息
* @param {Number} id 图书 id
* @return {[type]}
*/
async findById(id) {}
/**
* 添加图书
* @param {Object} book 图书对象
* @return {[type]}
*/
async add(book) {}
/**
* 更新图书
* @param {[type]} book 图书对象
* @return {[type]}
*/
async update(book) {}
/**
* 删除图书
* @param {[type]} id 图书 id
* @return {[type]}
*/
async deleteById(id) {}
}
module.exports = BookModel
五、SSR 服务端渲染
contreollers
下route.js
处理路由
const router = require('koa-simple-router')
const Controller = require('./index')
const controller = new Controller()
module.exports = (app) => {
app.use(
router((_) => {
_.get('/', controller.index())
// 获取图书
_.get('/index', controller.index())
// 添加图书
_.get('/addpage',controller.addpage())
_.post('/add',controller.add())
// 修改图书
_.get('/editpage',controller.editpage())
_.post('/edit',controller.edit())
// 删除图书
_.get('/delete',controller.delete())
})
)
}
contreollers
下index.js
处理业务,调用数据模型,获取数据传递给视图
const BookModel = require('../models')
const bookModel = new BookModel()
class IndexController {
constructor() {}
// 获取图书
index() {
return async function (ctx) {
try {
let res = await bookModel.find()
// console.log(res)
if (res.code == 0) {
ctx.render('index', {
data: res.data,
})
} else {
ctx.body = '获取失败'
}
} catch (err) {
console.log(err)
}
}
}
// 添加图书页
addpage(){}
// 添加数据处理
add() {}
// 修改图书页
editpage(){}
// 修改数据处理
edit() {}
// 删除图书
delete() {}
}
六、CSR 客户端渲染
1.后台输出接口
修改 contreollers
下 index.js
,返回 JSON
数据
const BookModel = require('../models')
const bookModel = new BookModel()
class IndexController {
constructor() {}
// 获取图书
index() {
return async function (ctx) {
try {
let res = await bookModel.find()
// console.log(res)
ctx.body = res
// if (res.code == 0) {
// ctx.render('index', {
// data: res.data,
// })
// } else {
// ctx.body = '获取失败'
// }
} catch (err) {
console.log(err)
}
}
}
}
2. 前端 Ajax 调用
在public
下新建 index.html
,bootstrap
布局,Ajax
请求数据,art-template
渲染数据,
toastr.js
是一个基于jQuery的非阻塞、简单、漂亮的消息提示插件,使用简单、方便。
七、RESTful API
一套关于设计请求的规范。
- GET: 获取数据
- POST: 添加数据
- PUT: 更新数据
- DELETE: 删除数据
1.设计路由
请求方式 | 请求路径 | GET/POST参数 | 说明 |
---|---|---|---|
GET | /book | 获取图书 | |
POST | /book | 添加图书 | |
GET | /book/:id | 根据 id 获取图书 | |
PUT | /book | 修改图书 | |
DELETE | /book:id | 删除图书 |
2.修改路由
contreollers
下 route.js
module.exports = (app) => {
app.use(
router((_) => {
_.get('/', controller.index())
// 获取图书
_.get('/book', controller.index())
// 添加图书
_.post('/book', controller.add())
// 根据 id 获取图书
_.get('/book/:id', controller.editpage())
// 修改图书
_.put('/book', controller.edit())
// 删除图书
_.delete('/book/:id', controller.delete())
)
}
3.获取动态路由参数
contreollers
下 index.js
修改图书页 和 删除图书 获取 id
let id = ctx.params.id
4. 调用接口
总结
这是 学习 Node.js 的初次项目,总结一下开发