I. System environment
Operating system: Windows10 64bit
Node: v10.15.3
NPM: 6.4.1
Koa: 2.7.0
Mariadb: 10.2.14
2. Project initialization
- Go to the project directory you want to initialize and execute the command
npm initCopy the code
- Install the KOA core dependency libraries
npm install koaCopy the code
- Start the service and create the app.js file in the root directory of the project
/* project dependencies */ const Koa = require('koa'); const http = require('http'); /* const app = new Koa(); /* Web services */ http.createserver (app.callback()).listen(3000).on('listening'.function() {console.log(' service started, port: 3000 ')});Copy the code
- Enter the project directory, execute the command, and view the result, as shown in the figure:
3. Prepare database (mysql)
- Unzip the database files to the installation directory D:\db\ Mariadb \10.2.14 (if you have installed mysql, skip the following steps).
- Add environment variables, as shown in the picture (My computer -> right-click -> Properties -> Advanced System Settings -> System Variables -> Select Path-> New) Other environment please search for yourself
- Create the install.bat file to install the Mariadb service with the following contents:
:: Specifies the program that creates the service @set mysql_service="D: \ db \ mariadb \ 10.2.14 \ bin \ mysqld exe":: Set the service name @set service_name="MariaDB.10"Mariadb service% mysql_service% --install %service_name% --defaults-file="D: \ db \ mariadb \ 10.2.14 \ my - medium ini" pauseCopy the code
- Uninstall. bat file is used to uninstall the Mariadb service. If the service is enabled, you need to stop the service first.
@set mysql_service="D: \ db \ mariadb \ 10.2.14 \ bin \ mysqld" @set service_name="MariaDB.10":: Uninstall service% mysql_service% --remove %service_name% pauseCopy the code
- Create the start.bat file to start the service with the same name as the installation
net start MariaDB.10Copy the code
- Create a stop.bat file (to close the service) with the same service name as the installation
net stop MariaDB.10Copy the code
- After the installation is complete, execute the install.bat file (only need to execute it once, and do not need to execute it again if the service is not uninstalled after restart or not) and then execute the start.bat file
- Open the mysql connection tool (use SQLyog here, similar to other tools), enter the configuration information, and click Test connection (default root password is empty, after connecting to the admin tool can add account or change the root password) :
- Create a database and table (any table will do), as shown in figure (Account represents the account table, chia represents the Chinese province table)
4. Interface development
The project structure
- Add the DAO folder — the data access layer, which connects to the database and returns data via SQL statements for use by the Service layer
- Add the Service folder — the business services layer, which executes the business logic and fetches data through the DAO layer for use by the Controller layer
- Add the Controller folder — the controller layer, write the interface, and fetch data from the Service layer for the interface to return
- Add a public/upload folder to save the contents of uploaded files
- Install dependencies
// koa-bodyParser -- middleware for post data submission // KOa-body -- middleware for file uploading // koa-router -- Middleware for routing (interface address) // NPM install koa-json koa-bodyParser koa-body koa-router mysqlCopy the code
- Add the config.js file as follows:
Module. exports = {// server config SERVICE:{HOST:"", PORT:"3000"}, // configure the DATABASE connection.'localhost', USER: 'root', PASSWORD: '123456', DATABASE: 'test', CONNECTION_LIMIT: 10}, // Interface address configuration API:{// Project interface prefix PROJECT_INTERFACE_PREFIX:'/testApi'// Background interface prefix ADMIN_INTERFACE_PREFIX:'/adminApi'// Mobile interface prefix MOBILE_INTERFACE_PREFIX:'/mobileApi'}, // UPLOAD_PATH: {UPLOAD_PATH:"public/upload"}, // LIMIT:{UPLOAD_IMG_SIZE:200*1024*1024}};Copy the code
- Add the utility method file utilitys.js with the following code
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 { returnresolve(rows); }})}}); // error JSON resuljson :(code=-1,message="Failure",data={})=>{ return{code:code, data:data, message:message}}, // success JSON resultSuccessJson:(code=0,message="Success",data={})=>{ return{code:code, data:data, message:message}}, // cut file suffix splitFileName:(text) =>{let index = text.lastIndexOf("."); return{ name:text.substring(0,index), suffix:text.substring(index+1) }; }, // create directory mkdirsSync recursively: (dirname)=>{if (fs.existsSync(dirname)) { return true; } else { if (utils.mkdirsSync(path.dirname(dirname))) { fs.mkdirSync(dirname); return true; }}}}; module.exports = utils;Copy the code
- Add routing file routes.js as follows :(read file in controller folder)
/* dependencies */ const path = require("path"); const fs = require("fs"); const router = require('koa-router') (); /* config file */ const config = require('./config.js'); const projectApiPrefix = config.API.PROJECT_INTERFACE_PREFIX; Fs.readdirsync (path.join(__dirname,'controller')).forEach((file) => { if (~file.indexOf('.js')) { let controller = require(path.join(__dirname, 'controller', file)); // Set the generic prefix router.use(' for the interface${projectApiPrefix}`, controller.routes(), controller.allowedMethods()); }}); module.exports = router;Copy the code
- Add constants.js file with the following code :(no content at present, used to store constant non-configuration information)
module.exports = {}Copy the code
- Add china.js, login.js, uploadfile.js files to dao layer, the specific code is as follows:
// china.js const tableName = "china"; module.exports = { getAllData:(ctx)=>{ return ctx.execSql(`select * from ${tableName}`); }};Copy the code
// login.js const tableName = "account"; module.exports = { adminLogin:(ctx,postData)=>{ return ctx.execSql(`select * from ${tableName} where phone = ? and password = ?`, [postData.phone, postData.psd]); } };Copy the code
// 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}`); }};Copy the code
- Add documentation service folder China. Js, login. Js, uploadfile. Js, specific code is as follows:
// china.js const chinaDao = require(".. /dao/china"); const util = require(".. /utilitys"); Returns {Promise< Boolean >} * @constructor */ exports. GetAllCity = async(CTX) => {try {letresult = await chinaDao.getAllData(ctx); ctx.body = util.resultSuccessJson(undefined,undefined,result); } catch (err) { ctx.body = util.resultErrorJson(undefined,err,{}); }};Copy the code
// login.js const loginDao = require(".. /dao/login"); const util = require(".. /utilitys"); 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,'Mobile phone number or password cannot be empty'{});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,'Wrong account or password',{}) } } catch (err) { ctx.body = util.resultErrorJson(undefined,err,{}); }}; /** * @return {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: 'Mobile phone number or password cannot be empty' }; return false; } try { let result = await ctx.execSql(`select * from account wherephone = ? 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: 'Wrong account or password' }; } } catch (err) { ctx.body = { success: false, userID: 0, message: err }; } /** * @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: 'Mobile phone number or password cannot be empty' }; return false; } try { let result = await ctx.execSql(`select * from account wherephone = ? 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: 'Wrong account or password' }; } } catch (err) { ctx.body = { success: false, userID: 0, message: err }; } /** * @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: 'Mobile phone number or password cannot be empty' }; return false; } try { let result = await ctx.execSql(`select * from account wherephone = ? 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: 'Wrong account or password' }; } } catch (err) { ctx.body = { success: false, userID: 0, message: err }; }}Copy the code
// 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; Returns {Promise< Boolean >} * @constructor */ exports. UploadFile = async(CTX) => {// file const file = ctx.request.files.file; Const fileName = util.splitfilename (file.name).name; Const suffix = util.splitfilename (file.name).suffix; // The name of the newly generated file const newFileName = '${new Date().getTime()}.${suffix}`; / / file upload classification const category = CTX. Request. Body. The category | |' '; // Create a readable stream const reader = fs.createreadStream (file.path); Const filePath = path.join(__dirname,'.. ',uploadPath,category,`/${newFileName}`); // Server relative path const serviceUrl = '${uploadPath}/${category}/${newFileName}`; Util. MkdirsSync (path.join(__dirname,'.. ',uploadPath,category)); Const upStream = fs.createWritestream (filePath); // If folder exists, create writable stream const upStream = fs.createWritestream (filePath); Try {// The readable stream writes to the writable stream through the pipe.let result = await uploadFileDao.uploadFile(ctx,{url:serviceUrl,fileName}); ctx.body = util.resultSuccessJson(undefined,"Upload successful"{}); } catch (err) { ctx.body = util.resultErrorJson(undefined,err.message||"error"{}); }}; / / returns {Promise<void>} */ exports.getallFiles = async(CTX)=>{try {letresult = await uploadFileDao.getAllFiles(ctx); ctx.body = util.resultSuccessJson(undefined,undefined,result); } catch (err) { ctx.body = util.resultErrorJson(undefined,err,{}); }}Copy the code
- Controller layer added China. Js, login. Js, uploadfile. Js, specific code is as follows:
// china.js /* router */ const router = require('koa-router') (); /* const chinaService = require('.. /service/china.js'); Router. get(' /getAllCity ', chinaservice.getallCity); module.exports = router;Copy the code
// login.js /* router */ const router = require('koa-router') (); /* const loginService = require('.. /service/login.js'); /* config */ 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); // Mobile - Use the login controller to implement the login interface router.post('${mobilePrefix}/login`, loginService.mobileLogin); // Mobile - Use the login controller to implement the logout interface router.post('${mobilePrefix}/login/out`, loginService.mobileLoginOut); module.exports = router; Copy the code
// uploadfile.js /* router */ const router = require('koa-router') (); /* const chinaService = require('.. /service/uploadfile.js'); Router.post (' /uploadfile ', chinaService. Uploadfile); Router. get(' /getAllFiles', chinaservice.getallfiles); module.exports = router;Copy the code
5. Modify the app.js startup project
The app.js code is as follows
/* project dependencies */ const Koa = require('koa');
const koaJson = require('koa-json'); // get middleware that submits data const bodyParser = require('koa-bodyparser'); // post data middleware const koaBody = require('koa-body'); // file upload const HTTP = require('http');
const routes = require('./routes'/* const util = require()'./utilitys.js'); /* config file */ 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 // Set maximum file size LIMIT, default 2M}})); app.use(async (ctx, next) => { ctx.execSql = util.query; await next(); }); /* Config attribute */ const {SERVICE} = config; /* routes */ app.use(routes.routes()); /* Web services */ http.createserver (app.callback()).listen(service.port).on()'listening'.function() {console.log(' Service started, port:${SERVICE.PORT}`)});Copy the code
Modify package.json file to add command as follows:
"scripts": {
"start": "node app.js"."debugger-start": "node --inspect-brk app.js"
},Copy the code
Execute the command
npm startCopy the code
The results are as follows:
Background interface Cross-domain access to other interfaces
const proxy = require('koa-server-http-proxy'); // enable 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)) });Copy the code