创建koa2项目步骤

本文介绍了如何使用Koa2框架结合Mysql数据库,实现包括安装、项目初始化、跨域配置、数据连接、CRUD操作(查询、添加、删除、更新)及参数化查询等功能。涵盖了数据库链接池、API设计和数据格式处理等关键步骤。
摘要由CSDN通过智能技术生成

1.安装koa-generator

npm install -g koa-generator

2.新建项目

koa2 -e my-server

3.安装依赖,启动项目

// cd my-server
npm  install
npm  run dev

项目默认运行在3000端口

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
        }
    }
    
})

至此,增删改查的操作已经完成

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七柒蕲

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值