[TOC]
>[success] # API 对接 MySQL
这个章节我们将之前 **controller 处理接口数据的文件** 里的 **假数据** ,**全部替换** 成 **真实数据** ,我们首先先从 **controller** 中根据 **sql 指令** 然后通过 **exec 方法** 从 **数据库** 中 **取出数据** ,再 **层层往回传递数据**,正如标题括号中所说的那样,**controller > router > app.js > 传给前端** 这么一个顺序,所以下面的文件就先从 **controller** 来看,看完再看 **router** ,然后再看 **app.js** 看每层都如何做的处理。
>[success] ## controller 文件(处理数据后返回给 router)
1. **博客相关文件**
**blog-1/src/controller/blog.js**
~~~
// 引入mysql工具函数
const { exec } = require('../db/mysql')
/**
* 获取博客列表
* @param {string} author - 作者
* @param {string} keyword - 搜索关键字
*/
const getList = (author, keyword) => {
let sql = `select * from blogs where 1=1 ` // 注意:这里为什么写 1=1,如果author没有值【select * from blogs where】会报错,如果有值就会带上查询条件
if(author){
sql += `and author='${author}' ` // 注意:后面有空格
}
if(keyword){
// 模糊查询
sql += `and title like '%${keyword}%' ` // 注意:后面有空格
}
// 按照时间倒序排序
sql += `order by createtime desc`
// 返回的是 promise 对象
return exec(sql)
}
/**
* 获取博客详情
* @param {number} id - 博客列表 item id
*/
const getDetail = (id) => {
const sql = `select * from blogs where id='${id}'`
return exec(sql).then(rows => {
return rows[0] // 因为 sql 语句查询出来的是个数组
})
}
/**
* 新增博客
* @param {object} blogData - blogData 是一个博客对象,包含 title content author 属性
*/
const newBlog = (blogData = {}) => {
// 整理要插入的数据
const title = blogData.title
const content = blogData.content
const author = blogData.author
const createtime = Date.now()
// 创建 sql 语句
let sql = `
insert into blogs(title, content, author, createtime)
values('${title}', '${content}', '${author}', '${createtime}');`
return exec(sql).then(insertData => {
return {
id: insertData.insertId
}
})
}
/**
* 更新博客
* @param {number} id - 要更新的博客的id
* @param {object} blogData - blogData 是一个博客对象,包含 title content 属性
*/
const updateBlog = (id, blogData = {}) => {
const title = blogData.title
const content = blogData.content
let sql = `update blogs set title='${title}', content='${content}' where id=${id};` // id整数型数据不需要引号包裹
return exec(sql).then(updateData => {
if(updateData.affectedRows > 0){
return true
}
return false
})
}
/**
* 删除博客
* @param {number} id - 要删除的博客的id
* @param {string} author - 作者身份,因为不可以越权删除,所以要加作者
*/
const deleteBlog = (id, author) => {
const sql = `delete from blogs where id=${id} and author='${author}'`
return exec(sql).then(deldateData => {
if(deldateData.affectedRows > 0){
return true
}
return false
})
}
module.exports = {
getList,
getDetail,
newBlog,
updateBlog,
deleteBlog
}
~~~
注意:这里需要注意一下 **getList** 方法中的 **sql** 语句中的 **1=1** ,因为这里如果不这样写,如果 **author** 没有值就会变成这样: `select * from blogs where` **where** 后面 **没有条件会报错** 。还有一点就是 **sql** 语句后面是有 **空格** 的,一定要注意。还有 **新增功能,新增时是需要登录人信息的,由于登陆功能目前未开发,【author】参数目前手动写死假数据代替** ,以及 **删除功能也同样需要登录人信息,暂时也使用的假数据代替** 。
2. **用户相关文件**
**blog-1/src/controller/user.js**
~~~
// 引入mysql工具函数
const { exec } = require('../db/mysql')
/**
* 登陆
* @param {string} username - 用户名
* @param {string} password - 密码
*/
const login = (username, password) => {
const sql = `select username, realname from users where username='${username}' and password='${password}';`
return exec(sql).then(rows => {
return rows[0] || {}
})
}
module.exports = { login }
~~~
>[success] ## router文件(处理数据后返回给 app.js)
1. **博客路由文件**
**blog-1/src/router/blog.js**
~~~
// 从 controller 中获取数据
const { getList,
getDetail,
newBlog,
updateBlog,
deleteBlog } = require('../controller/blog')
// 引入数据模型
const { SuccessModel, ErrorModel } = require('../model/resModel')
const handleBlogRouter = (req, res) => {
const method = req.method // GET POST
const id = req.query.id
// 获取博客列表
if(method === 'GET' && req.path === '/api/blog/list'){
// 取得参数
const author = req.query.author || ''
const keyword = req.query.keyword || ''
// 从 controller 中获取数据
const result = getList(author, keyword)
// 结果返回给app.js
return result.then(listData => {
// 通过数据模型加工数据返回带有 erron 属性的对象数据
return new SuccessModel(listData)
})
}
// 获取博客详情
if(method === 'GET' && req.path === '/api/blog/detail'){
const result = getDetail(id)
return result.then(data => {
return new SuccessModel(data)
})
}
// 新建一篇博客
if(method === 'POST' && req.path === '/api/blog/new'){
req.body.author = 'zhangsan' // 假数据,待开发登陆时再改成真数据,这里是根据当前登录人角色传过来的,目前没有做登陆功能
const result = newBlog(req.body)
return result.then(data => {
return new SuccessModel(data)
})
}
// 更新一篇博客
if(method === 'POST' && req.path === '/api/blog/update'){
const result = updateBlog(id, req.body)
return result.then(val => {
if(val){ // 更新成功
return new SuccessModel()
} else {
return new ErrorModel('更新博客失败')
}
})
}
// 删除一篇博客
if(method === 'POST' && req.path === '/api/blog/delete'){
const author = 'zhangsan' // 假数据,待开发登陆时再改成真数据,这里是根据当前登录人角色传过来的,目前没有做登陆功能
const result = deleteBlog(id, author)
return result.then(val => {
if(val){ // 删除成功
return new SuccessModel()
} else {
return new ErrorModel('删除博客失败')
}
})
}
}
module.exports = handleBlogRouter
~~~
2. **用户路由文件**
**blog-1/src/router/user.js**
~~~
// 从 controller 中获取数据
const { login } = require('../controller/user')
// 引入数据模型
const { SuccessModel, ErrorModel } = require('../model/resModel')
const handleUserRouter = (req, res) => {
const method = req.method // GET POST
// 登陆
if(method === 'POST' && req.path === '/api/user/login'){
const { username, password } = req.body
const result = login(username, password)
return result.then(data => {
if(data.username){ // 登陆成功
return new SuccessModel()
} else {
return new ErrorModel('登陆失败')
}
})
}
}
module.exports = handleUserRouter
~~~
>[success] ## app.js文件(处理数据后返回给 前端)
**blog-1/app.js**
~~~
const querystring = require('querystring')
// 引入处理路由文件
const handleBlogRouter = require('./src/router/blog')
const handleUserRouter = require('./src/router/user')
// 用于处理 post data
const getPostData = (req) => {
const promise = new Promise((resolve, reject) => {
if(req.method !== 'POST'){ // 不等于 post 请求
resolve({})
return
}
if(req.headers['content-type'] !== 'application/json'){ // 传入的数据格式不是 application/json ,可能是form-data的参数
resolve({})
return
}
// 1. POST通过数据流方式接收数据
let postData = ''
// 2. 给req注册data事件,当有数据提交过来就会触发,事件的作用是接收数据,接收大量数据的时候,是分块接收的
req.on('data', chunk => {
postData += chunk.toString()
})
// 3. 给req注册end事件,当数据全部接收完毕,会触发
req.on('end', () => {
if(!postData){ // 无数据返回空对象
resolve({})
return
}
resolve(
JSON.parse(postData)
)
})
})
return promise
}
const serverHandle = (req, res) => {
// 设置返回格式 JSON
res.setHeader('Content-type', 'application/json')
// 获取 path
const url = req.url
req.path = url.split('?')[0]
// 解析query 参数
req.query = querystring.parse(url.split('?')[1])
// 处理 post data 参数
getPostData(req).then(postData => {
req.body = postData
// 处理 blog 路由
const blogResult = handleBlogRouter(req, res)
if(blogResult){
blogResult.then(blogData => {
res.end(
JSON.stringify(blogData)
)
})
return // 这里需要return,不然返回数据后还会往下走
}
// 处理 user 路由
const userResult = handleUserRouter(req, res)
if(userResult){
userResult.then(userData => {
res.end(
JSON.stringify(userData)
)
})
return
}
// 未命中路由,返回 404
res.writeHead(404, {"Content-type": "text/plain"}) // 把响应头状态码设置为404,然后Content-type: text/plain是纯文本,为了覆盖上面的json类型
// 返回内容
res.write('404 Not Found\n')
res.end()
})
}
module.exports = serverHandle
~~~
- NodeJS基础
- 什么是NodeJS
- npm
- Node.js+Express+Koa2+开发Web Server博客
- 下载和安装node
- nodejs和js的区别
- commonjs-演示
- nodejs如何debugger
- server端与前端的区别
- 项目需求分析
- 开发接口(不使用任何框架)
- http-概述
- 处理get请求
- 处理post请求
- 处理http请求的综合示例
- 搭建开发环境
- 初始化并且开发路由
- 开发博客项目之数据存储
- MySql介绍
- 数据库操作(创建和增、删、查)
- Nodejs 操作 Mysql
- Nodejs 链接 mysql 做成工具
- API 对接 MySQL
- 开发博客项目之登陆
- cookie-介绍
- cookie用于登录验证
- cookie做限制