一步一步教你完成Koa2接口开发

一、系统环境

操作系统:windows10 64bit

node:v10.15.3

npm:6.4.1

koa:2.7.0

mariadb:10.2.14

二、项目初始化

进入要初始化的项目目录,执行命令

npm init

安装koa核心依赖库

npm install koa

开启服务,在项目根目录下创建app.js文件,代码如下

/*项目依赖*/
const Koa = require('koa');
const http = require('http');
/*应用实例*/
const app = new Koa();
/*web服务*/
http.createServer(app.callback())
    .listen(3000)
    .on('listening', function () {
        console.log(`服务已开启,端口:3000`)
    });

进入项目目录,执行命令,查看结果,如图:

三、数据库(mysql)准备

解压数据库文件到安装目录,此处目录为D:\db\mariadb\10.2.14(已安装好mysql的可以根据情况忽略下面几步)

添加环境变量,如图(我的电脑->右键->属性->高级系统设置->系统变量->选择Path->新建)其他环境请自行百度

创建install.bat文件(用来安装Mariadb服务),文件内容如下:

::指定创建服务的程序

@set mysql_service="D:\db\mariadb\10.2.14\bin\mysqld.exe"

::设置服务名

@set service_name="MariaDB.10"


::开始安装Mariadb服务

%mysql_service% --install %service_name% --defaults-file="D:\db\mariadb\10.2.14\my-medium.ini"


pause

创建uninstall.bat文件(用来卸载Mariadb服务,如果服务处在开启状态,需要先停止服务),文件内容如下:

@set mysql_service="D:\db\mariadb\10.2.14\bin\mysqld"
@set service_name="MariaDB.10"

:: 卸载服务
%mysql_service% --remove %service_name%

pause

创建start.bat文件(用来开启服务),服务名称需要与安装的名称一样

net start MariaDB.10

创建stop.bat文件(用来关闭服务),服务名称需要与安装的名称一样

net stop MariaDB.10

创建完成之后,先执行install.bat文件(只需要执行一次,之后不管重启与否只要没卸载改服务也不需要再次执行),再执行start.bat文件

打开mysql连接工具(此处使用SQLyog,其他工具类似),输入配置信息,输入完成之后点击测试连接(默认root密码为空,连接之后可通过管理工具添加账户或者修改root密码):

创建数据库及表(任意表都行),如图:(account表示账户表,chia表示中国省市区的表)

四、接口开发

项目结构

添加dao文件夹 -- 数据访问层,用来连接数据库,通过sql语句返回数据供service层使用

添加service文件夹 -- 业务服务层,执行业务逻辑并且通过dao层获取数据供controller层使用

添加controller文件夹 -- 控制器层,编写接口,通过service层获取数据供接口返回

添加public/upload文件夹 -- 用来保存上传的文件内容

安装依赖

// koa-json -- get提交数据的中间件
// koa-bodyparser -- post提交数据的中间件
// koa-body -- 文件上传的中间件
// koa-router -- 路由中间件(接口地址)
// mysql -- mysql数据库连接中间件
npm install koa-json koa-bodyparser koa-body koa-router mysql

添加config.js文件,具体代码如下:

module.exports = {
    // 服务器配置
    SERVICE:{
        HOST:"",
        PORT:"3000"
    },
    // 数据库连接配置
    DATABASE:{
        HOST: 'localhost',
        USER: 'root',
        PASSWORD: '123456',
        DATABASE: 'test',
        CONNECTION_LIMIT: 10
    },
    // 接口地址配置
    API:{
        // 项目接口前缀
        PROJECT_INTERFACE_PREFIX:'/testApi',
        // 后台接口前缀
        ADMIN_INTERFACE_PREFIX: '/adminApi',
        // 移动端接口前缀
        MOBILE_INTERFACE_PREFIX:'/mobileApi'
    },
    // 路径配置
    PATH:{
        UPLOAD_PATH:"public/upload"
    },
    // 限制条件配置
    LIMIT:{
        UPLOAD_IMG_SIZE:200*1024*1024
    }

};

添加通用方法文件utilitys.js,具体代码如下

const mysql = require('mysql');
const fs = require("fs");
const path = require("path");
const config = require("./config");
const db = config.DATABASE;


const pool = mysql.createPool({
    host: db.HOST,
    user: db.USER,
    password: db.PASSWORD,
    database: db.DATABASE,
    connectionLimit: db.CONNECTION_LIMIT
});
const utils = {
    // 数据库查询方法
    query: (sql, values) => {
        return new Promise((resolve, reject) => {
            pool.getConnection((err, connection) => {
                if (err) {
                    return reject(err);
                } else {
                    connection.query(sql, values, (err, rows) => {
                        connection.release();
                        if (err) {
                            return reject(err)
                        } else {
                            return resolve(rows);
                        }
                    })
                }
            })
        });
    },
    // 错误JSON
    resultErrorJson:(code=-1,message="失败",data={})=>{
        return {
            code:code,
            data:data,
            message:message
        }
    },
    // 成功JSON
    resultSuccessJson:(code=0,message="成功",data={})=>{
        return {
            code:code,
            data:data,
            message:message
        }
    },
    // 切割文件后缀名
    splitFileName:(text) =>{
        let index = text.lastIndexOf(".");
        return {
            name:text.substring(0,index),
            suffix:text.substring(index+1)
        };
    },
    // 递归创建目录
    mkdirsSync: (dirname)=>{
        if (fs.existsSync(dirname)) {
            return true;
        } else {
            if (utils.mkdirsSync(path.dirname(dirname))) {
                fs.mkdirSync(dirname);
                return true;
            }
        }
    }
};
module.exports = utils;

添加路由文件routes.js,具体代码如下:(读取controller文件夹中的文件)

/*依赖包*/
const path = require("path");
const fs = require("fs");
const router =  require('koa-router')();
/*配置文件*/
const config = require('./config.js');
const projectApiPrefix = config.API.PROJECT_INTERFACE_PREFIX;
// 读取controller文件夹中的文件
fs.readdirSync(path.join(__dirname, 'controller')).forEach((file) => {
    if (~file.indexOf('.js')) {
        let controller = require(path.join(__dirname, 'controller', file));
        // 为接口设置通用前缀
        router.use(`${projectApiPrefix}`, controller.routes(), controller.allowedMethods());
    }
});
module.exports = router;

添加constants.js文件,具体代码如下:(暂无内容,用来保存常量非配置信息)

module.exports = {}

dao层添加china.js,login.js,uploadfile.js文件,具体代码如下:

// china.js
const tableName = "china";
module.exports = {
    getAllData:(ctx)=>{
        return ctx.execSql(`select * from ${tableName}`);
    }
};

 

// login.js
const tableName = "account";
module.exports = {
    adminLogin:(ctx,postData)=>{
        return ctx.execSql(`select * from ${tableName} where phone = ? and password = ?`, [postData.phone, postData.psd]);
    }
};

 

// uploadfile.js
const tableName = "upload_file";
module.exports = {
    uploadFile:(ctx,postData)=>{
        return ctx.execSql(`insert into ${tableName} values (?,?,?)`, [null,postData.url, postData.fileName]);
    },
    getAllFiles:(ctx)=>{
        return ctx.execSql(`select * from ${tableName}`);
    }
};

 

service文件夹中添加文件china.js,login.js,uploadfile.js,具体代码如下:

// china.js
const chinaDao = require("../dao/china");
const util = require("../utilitys");
/**
 * 后台获取所有城市接口逻辑
 * @param ctx
 * @returns {Promise<boolean>}
 * @constructor
 */
exports.getAllCity = async(ctx) => {
    try {
        let result = await chinaDao.getAllData(ctx);
        ctx.body = util.resultSuccessJson(undefined,undefined,result);    } catch (err) {
        ctx.body = util.resultErrorJson(undefined,err,{});    }
};
// login.js
const loginDao = require("../dao/login");
const util = require("../utilitys");
/**
 * 后台登录接口业务逻辑
 * @param ctx
 * @returns {Promise<boolean>}
 * @constructor
 */
exports.adminLogin = async(ctx) => {
    let phone = ctx.request.body.phone || '';
    let psd = ctx.request.body.password || '';
    if (!phone || !psd) {
        ctx.body = util.resultErrorJson(undefined,'手机号码或密码不能为空',{});        return false;
    }
    try {
        let result = await loginDao.adminLogin(ctx,{phone,psd});
        if (result.length > 0) {
            ctx.body = util.resultSuccessJson(undefined,undefined,result);        } else {
            ctx.body = util.resultSuccessJson(undefined,'账号或密码错误',{})        }
    } catch (err) {
        ctx.body = util.resultErrorJson(undefined,err,{});    }
};
/**
 * 后台登出接口业务逻辑
 * @param ctx
 * @returns {Promise<boolean>}
 * @constructor
 */
exports.adminLoginOut = async(ctx) => {
    let phone = ctx.request.body.phone || '';
    let psd = ctx.request.body.password || '';
    if (!phone || !psd) {
        ctx.body = {
            success: false,
            message: '手机号码或密码不能为空'
        };
        return false;
    }
    try {
        let result = await ctx.execSql(`select * from account where phone = ? and password = ?`, [phone, psd]);
        if (result.length > 0) {
            ctx.body = {
                success: true,
                userID: result[0].id,
                message: ''
            };
        } else {
            ctx.body = {
                success: false,
                userID: 0,
                message: '账号或密码错误'
            };
        }
    } catch (err) {
        ctx.body = {
            success: false,
            userID: 0,
            message: err
        };
    }
}

/**
 * 移动端登录接口业务逻辑
 * @param ctx
 * @returns {Promise<boolean>}
 * @constructor
 */
exports.mobileLogin = async(ctx) => {
    let phone = ctx.request.body.phone || '';
    let psd = ctx.request.body.password || '';
    if (!phone || !psd) {
        ctx.body = {
            success: false,
            message: '手机号码或密码不能为空'
        };
        return false;
    }
    try {
        let result = await ctx.execSql(`select * from account where phone = ? and password = ?`, [phone, psd]);
        if (result.length > 0) {
            ctx.body = {
                success: true,
                userID: result[0].id,
                message: ''
            };
        } else {
            ctx.body = {
                success: false,
                userID: 0,
                message: '账号或密码错误'
            };
        }
    } catch (err) {
        ctx.body = {
            success: false,
            userID: 0,
            message: err
        };
    }
}
/**
 * 移动端登出接口业务逻辑
 * @param ctx
 * @returns {Promise<boolean>}
 * @constructor
 */
exports.mobileLoginOut = async(ctx) => {
    let phone = ctx.request.body.phone || '';
    let psd = ctx.request.body.password || '';
    if (!phone || !psd) {
        ctx.body = {
            success: false,
            message: '手机号码或密码不能为空'
        };
        return false;
    }
    try {
        let result = await ctx.execSql(`select * from account where phone = ? and password = ?`, [phone, psd]);
        if (result.length > 0) {
            ctx.body = {
                success: true,
                userID: result[0].id,
                message: ''
            };
        } else {
            ctx.body = {
                success: false,
                userID: 0,
                message: '账号或密码错误'
            };
        }
    } catch (err) {
        ctx.body = {
            success: false,
            userID: 0,
            message: err
        };
    }
}
// uploadfile.js
const path = require("path");
const fs = require("fs");
const uploadFileDao = require("../dao/uploadfile");
const util = require("../utilitys");
const config = require("../config");
const uploadPath = config.PATH.UPLOAD_PATH;
/**
 * 单个上传文件接口
 * @param ctx
 * @returns {Promise<boolean>}
 * @constructor
 */
exports.uploadFile = async(ctx) => {
    // 文件
    const file = ctx.request.files.file; // 获取上传文件
    // 获取文件后缀名
    const fileName = util.splitFileName(file.name).name;
    // 获取文件后缀名
    const suffix = util.splitFileName(file.name).suffix;
    // 新生成的文件名称
    const newFileName =`${new Date().getTime()}.${suffix}`;
    // 文件上传分类
    const category = ctx.request.body.category || '';
    // 创建可读流
    const reader = fs.createReadStream(file.path);
    // 设置上传文件路径及名称
    const filePath = path.join(__dirname, '..',uploadPath,category,`/${newFileName}`);
    // 服务器相对路径
    const serviceUrl = `${uploadPath}/${category}/${newFileName}`;
    // 递归创建目录 同步方法
    util.mkdirsSync(path.join(__dirname, '..',uploadPath,category));
    // 如果文件夹存在,则创建可写流
    const upStream = fs.createWriteStream(filePath);
    try {
        // 可读流通过管道写入可写流
        reader.pipe(upStream);
        let result = await uploadFileDao.uploadFile(ctx,{url:serviceUrl,fileName});
        ctx.body = util.resultSuccessJson(undefined,"上传成功",{});    } catch (err) {
        ctx.body = util.resultErrorJson(undefined,err.message||"error",{});    }
};
/**
 * 获取所有文件信息
 * @param ctx
 * @returns {Promise<void>}
 */
exports.getAllFiles = async(ctx)=>{
    try {
        let result = await uploadFileDao.getAllFiles(ctx);
        ctx.body = util.resultSuccessJson(undefined,undefined,result);    } catch (err) {
        ctx.body = util.resultErrorJson(undefined,err,{});    }
}

 

controller层添加china.js,login.js,uploadfile.js,具体代码如下:

// china.js
/*路由*/
const router = require('koa-router')();
/*接口服务*/
const chinaService = require('../service/china.js');
// 通用获取所有省市区接口
router.get(`/getAllCity`, chinaService.getAllCity);

module.exports = router;
// login.js
/*路由*/
const router = require('koa-router')();
/*接口服务*/
const loginService = require('../service/login.js');
/*配置属性*/
const config = require('../config.js');
const adminPrefix = config.API.ADMIN_INTERFACE_PREFIX;
const mobilePrefix = config.API.MOBILE_INTERFACE_PREFIX;
// 后台-使用登录控制器实现登录接口
router.post(`${adminPrefix}/login`, loginService.adminLogin);
// 后台-使用登录控制器实现登出接口
router.post(`${adminPrefix}/login/out`, loginService.adminLoginOut);

// 移动端-使用登录控制器实现登录接口
router.post(`${mobilePrefix}/login`, loginService.mobileLogin);
// 移动端-使用登录控制器实现登出接口
router.post(`${mobilePrefix}/login/out`, loginService.mobileLoginOut);

module.exports = router;
// uploadfile.js
/*路由*/
const router = require('koa-router')();
/*接口服务*/
const chinaService = require('../service/uploadfile.js');
// 通用上传文件接口
router.post(`/uploadfile`, chinaService.uploadFile);
// 获取所有文件信息接口
router.get(`/getAllFiles`, chinaService.getAllFiles);

module.exports = router;

 

五、修改app.js启动项目

app.js代码如下

/*项目依赖*/
const Koa = require('koa');
const koaJson = require('koa-json');    // get提交数据的中间件
const bodyParser = require('koa-bodyparser'); // post提交数据中间件
const koaBody = require('koa-body');   // 文件上传
const http = require('http');
const routes = require('./routes')
/*工具方法*/
const util = require('./utilitys.js');
/*配置文件*/
const config = require("./config.js");
/*应用实例*/
const app = new Koa();

app.use(bodyParser());
app.use(koaJson());
app.use(koaBody({
    multipart: true,
    formidable: {
        maxFileSize: config.LIMIT.UPLOAD_IMG_SIZE    // 设置上传文件大小最大限制,默认2M
    }
}));
app.use(async (ctx, next) => {
    ctx.execSql = util.query;
    await next();
});
/*配置属性*/
const {SERVICE} = config;
/*路由配置*/
app.use(routes.routes());
/*web服务*/
http.createServer(app.callback())
    .listen(SERVICE.PORT)
    .on('listening', function () {
        console.log(`服务已开启,端口:${SERVICE.PORT}`)
    });

修改package.json文件添加命令,代码如下:

"scripts": {
    "start": "node app.js",
    "debugger-start": "node --inspect-brk app.js"
  },

执行命令

npm start

结果如下:

 

六、后台接口跨域访问其他接口

const proxy = require('koa-server-http-proxy');
// 开启代理
const proxyTable = {
    '/shsApi': {
        target: 'http://www.91vue.com:8081',
        pathRewrite: { '^/shsApi': 'shsApi/' },
        changeOrigin: true
    },
    // '/api': {
    //     target: 'https://news-at.zhihu.com',
    //     pathRewrite: { '^/api': 'api/4/' },
    //     changeOrigin: true
    // }
};
Object.keys(proxyTable).forEach((context) => {
    var options = proxyTable[context];
    app.use(proxy(context, options))
});

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是手把手带你搭建koa2 mysql项目的程。 1. 安装Node.js和npm 首先需要安装Node.js和npm,可以在官网下载安装包进行安装。 2. 初始化项目 在命令行中进入项目目录,运行以下命令初始化项目: ``` npm init ``` 根据提示填项目信息,完成后会生成package.json文件。 3. 安装koa2和koa-router 运行以下命令安装koa2和koa-router: ``` npm install koa koa-router --save ``` 4. 安装mysql模块 运行以下命令安装mysql模块: ``` npm install mysql --save ``` 5. 创建数据库 在mysql中创建一个名为test的数据库,并创建一个名为users的表,包含id、name、age三个字段。 6. 创建连接池 在项目中创建一个db.js文件,用于创建mysql连接池: ```javascript const mysql = require('mysql'); const pool = mysql.createPool({ host: 'localhost', user: 'root', password: '123456', database: 'test' }); module.exports = pool; ``` 7. 创建路由 在项目中创建一个router.js文件,用于创建koa-router路由: ```javascript const Router = require('koa-router'); const pool = require('./db'); const router = new Router(); router.get('/users', async (ctx) => { const conn = await pool.getConnection(); const [rows] = await conn.query('SELECT * FROM users'); conn.release(); ctx.body = rows; }); module.exports = router; ``` 8. 创建服务器 在项目中创建一个app.js文件,用于创建koa2服务器并引入路由: ```javascript const Koa = require('koa'); const router = require('./router'); const app = new Koa(); app.use(router.routes()); app.listen(3000, () => { console.log('Server is running at http://localhost:3000'); }); ``` 9. 运行项目 在命令行中进入项目目录,运行以下命令启动服务器: ``` node app.js ``` 在浏览器中访问http://localhost:3000/users,可以看到数据库中的用户数据。 至此,一个简单的koa2 mysql项目就搭建完成了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值