ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[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 ~~~