1.安装koa-generator
npm install -g koa-generator
2.新建项目
koa2 -e my-server
3.安装依赖,启动项目
// cd my-server
npm install
npm run dev
4.安装跨域插件
npm i koa2-cors --save
5.配置跨域,在app.js添加如下配置
// 配置跨域
const cors = require('koa2-cors');
app.use(cors({
origin: '*',
allowMethods: ['GET', 'POST', 'DELETE', 'PUT', 'PATCH', 'OPTIONS'],
allowHeaders: ['Content-Type', 'Authorization', 'Accept']
}));
6.链接mysql数据库
首先安装mysql插件
npm install mysql --save
项目根目录创建mysql文件夹,创建mysql.js
项目根目录创建utils文件夹,创建code.js,定义 返回成功失败类型
mysql.js文件中创建数据库链接池,封装增删改查数据返回格式
const mysql = require('mysql')
const code=require('../utils/code')
console.log(mysql)
// 创建数据池
const pool = mysql.createPool({
host : '127.0.0.1', // 数据库地址
user : 'root', // 数据库用户
password : 'yanglian', // 数据库密码
database : 'labour' // 选中数据库
})
// params 进行添加或修改的数据
function poolFn(connecQuery, sql, params) {
// getConnection 创建连接池
return new Promise((resolve, reject) => {
pool.getConnection((err, connection) => {
if(err) {
reject('建立连接池失败')
throw err
}
connecQuery(connection, sql, params).then(data => {
connection.release() // 到这步说明已经完成操作,释放连接
resolve(data)
})
})
// console.log(pool._allConnections.length) // 连接池里的连接数
})
}
/*
* connection 连接句柄
* sql 查询语句
* */
// 基于promise方法实现
// 查询数据
function find(connection, sql) {
return new Promise((resolve, reject) => {
connection.query(sql, (err, data) => {
// console.log(data)
if(err) {
reject(err)
throw err
}
resolve(data)
})
})
}
// 添加数据
function add(connection, sql, params) {
return new Promise((resolve, reject) => {
connection.query(sql, params, (err, result) => {
if(err) {
resolve({
msg:'添加失败',
code:code.err,
data:null
})
throw err
}
resolve({
msg:'添加成功',
code:code.success,
data:null
})
})
})
}
// 删除数据
function del(connection, sql) {
return new Promise((resolve, reject) => {
connection.query(sql, (err, result) => {
if(err) {
resolve({
msg:'删除失败',
code:code.err,
data:null
})
throw err
}
resolve({
msg:'删除成功',
code:code.success,
data:null
})
})
})
}
// 修改数据
function update(connection, sql, params) {
return new Promise((resolve, reject) => {
connection.query(sql, params, (err, result) => {
if(err) {
reject(err)
throw err
}
resolve(result)
})
})
}
// 将方法封装统一导出
function queryFn(connecQuery, sql, params) {
return new Promise((resolve) => {
poolFn(connecQuery, sql, params).then(data => {
console.log(data)
resolve(data)
})
})
}
module.exports = {
findData(sql, params) {
return queryFn(find, sql, params)
},
addData(sql, params) {
return queryFn(add, sql, params)
},
delData(sql, params) {
return queryFn(del, sql, params)
},
updateData(sql, params) {
return queryFn(update, sql, params)
}
}
code.js文件创建数据状态
module.exports={
success:1,//成功
err:0,//失败
repeat:2,//重复
}
在mysql文件夹 中创建processData.js,处理最终的数据返回格式
const {
findData,
addData,
delData,
updateData
} = require('./mysql')
const code=require('../utils/code')
// 这边通过async方法保证数据的同步获取
let query = async(ctx,sql,config={}) => { // 获取数据
let {params,type='json',isObj}=config
// 返回的数据格式为json
ctx.response.type = type
await findData(sql,params).then(data => {
ctx.body = {
data:isObj ? data[0] : data,
msg:'查询成功',
code:code.success
}
})
}
let add = async(ctx,sql,config={}) => { // 添加数据
// console.log(ctx)
let {params,type='json'}=config
ctx.response.type =type
console.log(params)
await addData(sql, params).then(data => {
ctx.body = data
}, () => {
ctx.body = data
})
}
let del = async(ctx,sql,config={}) => { // 删除数据
let {params,type='json'}=config
ctx.response.type =type
await delData(sql,params).then(data => {
ctx.body = data
}, () => {
ctx.body = data
})
}
let update = async(ctx,sql,config={}) => { // 修改数据
let {params,type='json',msg='更新成功'}=config
ctx.response.type =type
await updateData(sql, params).then(data => {
// console.log(data)
ctx.body = {
data:null,
msg,
code:code.success
}
})
}
module.exports = {
query,
add,
del,
update
}
7.创建一个get请求查询数据库数据
在routes文件夹下创建一个news模块
const router = require('koa-router')()
const msql=require('../mysql/processData')
const myCode=require('../utils/code')
router.prefix('/news')
//获取数据库信息
router.get('/list', async function (ctx, next) {
await msql.query(ctx,`SELECT * FROM news`)
})
module.exports = router
在app.js将news模块导入,这样就可以通过/news/list查询到数据库的信息了
const news = require('./routes/new')
app.use(news.routes(), users.allowedMethods())
条件查询如下,使用where操作
router.get('/list', async function (ctx, next) {
// sql条件查询语句,匹配content相同的内容
await msql.query(ctx,`SELECT * FROM news WHERE content='${ctx.query.content}'`)
})
模糊查询如下,使用like操作
router.get('/list', async function (ctx, next) {
// 模糊查询content内容带o的数据
await msql.query(ctx,`SELECT * FROM news WHERE content LIKE '%${ctx.query.content}%'`)
})
当我们有更多条件的时候,比如实际项目中的分页查询等,需要很多参数,这样我们就需要封装一个get传递的参数
在utils中创建sqlQs.js,封装两个函数,用来生成精准匹配和模糊查询sql条件字符串
sqlQs.js
// 将对象转换成mysql更新字符串函数
function stringify(obj,config={}) {
let {likeArr=[]}=config
if(!(obj instanceof Object)){
console.error(`${obj}数据格式错误`)
return
}
let qsStr=''
for (let i in obj){
let connectStr='='
let valueGuard=""
if(likeArr.includes(i)){
//模糊查询
connectStr=' like '
valueGuard=`%`
}
let value=typeof obj[i]==='number' ? obj[i] : `'${valueGuard}${obj[i]}${valueGuard}'`
if(!value && value!==0){
//没有值的不做拼接
continue
}
qsStr+=`,${i}${connectStr}${value}`
}
qsStr=qsStr.replace(',','')
console.log(qsStr)
return qsStr
}
// 将mysql更新字符串函数解析成对象
function parse(str,config={}) {
if(typeof str !=='string'){
console.error(`${str}数据格式错误`)
return
}
let {likeArr=[]}=config
let strArr=str.split(',')
return strArr.reduce((result,current)=>{
let likeIndex=likeArr.findIndex(item=>new RegExp(`^${item}`).test(current))
let connectStr=likeIndex>-1 ? ' like ' : '='
let itemArr=current.split(connectStr)
if(likeIndex>-1){
result[itemArr[1]]=result[itemArr[1]].replaceAll('%','')
}
result[itemArr[0]]=result[itemArr[1]]
return result
},{})
}
module.exports={
stringify,
parse
}
然后我们将get请求改成
router.get('/list', async function (ctx, next) {
let queryObj= {...ctx.request.query}
let query=sqlQs.stringify(queryObj,{likeArr:['content']})
await msql.query(ctx,`SELECT * FROM news WHERE ${query}`)
})
然后我们再看看返回给前端的数据,会发现返回的时间字符串格式不是前端想要的,直接从数据库查到的时间,带有T,我们得改下返回的时间格式。那么用mysql的DATE_FORMAT语法即可,DATE_FORMAT(time,’%Y-%m-%d %H:%i:%S’) as time。更改过后
router.get('/list', async function (ctx, next) {
let queryObj= {...ctx.request.query}
query=sqlQs.stringify(queryObj,{likeArr:['companyName']})
await msql.query(ctx,`SELECT *,DATE_FORMAT(time,'%Y-%m-%d %H:%i:%S') as time FROM news WHERE ${query}`)
})
接着我们写一个查看详情接口
router.get('/detail',async (ctx,next) => {
let {id} = ctx.request.query
if(!id) {
ctx.body = {
msg: '参数缺少id',
code: myCode.err
}
return
}
await msql.query(ctx,`SELECT *,DATE_FORMAT(time,'%Y-%m-%d') as time FROM news WHERE id=${id}`)
})
我们再写一个新增接口,使用post传参,并生成唯一id
先封装一个生成随机id的js文件
在utils文件夹中新建snowflake.js文件,代码如下
module.exports=function getId(pre='',randomLength=10,) {
let id= Number(Math.random().toString().substr(3,randomLength)).toString(36)
id=`${pre}${id}`
return id
}
给news表添加数据
router.post('/add',async (ctx,next) => {
let data = {...ctx.request.body}
if(!Object.keys(data).length) {
ctx.body = {
msg: '参数缺少',
code: myCode.err
}
return
}
for(let i in data){
if(!data[i]){
ctx.body = {
msg: `${i}参数缺少`,
code: myCode.err
}
return
}
}
await msql.add(ctx,`INSERT INTO news SET ?`,{params: {...ctx.request.body,id:0}})
})
修改操作代码
router.post('/add',async (ctx,next) => {
let data = {...ctx.request.body}
if(!Object.keys(data).length) {
ctx.body = {
msg: '参数缺少',
code: myCode.err
}
return
}
for(let i in data){
if(!data[i]){
ctx.body = {
msg: `${i}参数缺少`,
code: myCode.err
}
return
}
}
let id = ctx.request.body.id
if(id){
let params = {...ctx.request.body}
delete params.id
params = sqlQs.stringify(params)
await msql.update(ctx,`UPDATE news SET ${params} WHERE id=${id}`)
} else {
await msql.add(ctx,`INSERT INTO news SET ?`,{params: {...ctx.request.body,id:0}})
}
})
删除操作
router.get('/del',async (ctx,next) => {
let {id}=ctx.request.query
if(id) {
await msql.del(ctx,`DELETE FROM news WHERE id=${id}`)
} else {
ctx.body = {
data:null,
msg:'删除失败',
code:myCode.err
}
}
})
至此,增删改查的操作已经完成