日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

在此前寫的文章“從零基礎入門進行小程序開發實戰”中,已經介紹過背單詞的小程序,因為沒有備案的服務器資源只能使用系統后臺提供的緩存功能存儲用戶數據。緩存有大小限制,而且只提供key-value的存儲方式,使用起來也很不方便。

最近域名和服務器已經申請下來,網站備案也在進行中,準備自己搭建數據庫服務器和開發一套實現restful api的后臺代碼。關于技術棧的選擇也頗花費了一些功夫,傳統的技術路線JAVA和.net core都能提供相關的成熟的框架,我本人技術背景對這方面也很熟悉,可是既然是自己興趣又不是公司的項目,當然還是想要嘗試一下新的不一樣的技術實現。

研究了Python的Flask框架和基于nodejs的koa2框架,都是大名鼎鼎,可之前接觸不多,最后選擇了koa2框架,寫小程序的后臺,順便也學習一下這方面的開發。

介紹

koa2是由 Express 原班人馬打造的,致力于成為一個更小、更富有表現力、更健壯的 Web 框架。 使用 koa 編寫 web 應用,可以免除重復繁瑣的回調函數嵌套, 并極大地提升錯誤處理的效率。koa 不在內核方法中綁定任何中間件, 它僅僅提供了一個輕量優雅的函數庫,使得編寫 Web 應用變得得心應手。

node基礎知識介紹

在開始項目前,先簡單介紹下node相關的一些基礎知識,通過npm init初始化一個node項目時,會生成一個package.json的配置文件,包括項目名稱、版本、作者、依賴等相關信息,主要說一下其中的bin字段。
很多包都有一個或多個可執行的文件,希望放在PATH中,(實際上,就是這個功能讓npm可執行的)。
當你要用這個功能時,需要給package.json中的bin字段添加一個命令名,并指向需要執行的文件(即后文的入口文件)。初始化的時候npm會將他鏈接到prefix/bin(全局初始化)或者./node_modules/.bin/(本地初始化)。

開發環境搭建和腳手架安裝

如果還沒有nodejs和npm,首先需要安裝這兩個軟件,注意最低版本要求。

腳手架對于前端程序員并不陌生,像vue-cli,react-native-cli等,全局安裝后,只需要在命令行中敲入一個簡單的命令,便可幫我們快速的生成一個初始項目,如vue init webpack projectName,即可生成一個初始的vue項目。

安裝Koa2腳手架非常簡單:

先執行下面命令:
npm install -g koa-generator

使用koa-generator生成koa2項目

在你的工作目錄下,輸入:

$ koa2 HelloKoa2

成功創建項目后,進入項目目錄(安裝項目依賴) :

npm install

啟動運行項目:

$ npm start

項目啟動后,默認端口號是3000,在瀏覽器中運行就能看到頁面。

 

項目結構介紹

├─src           應用目錄(可設置)
│  ├─controller                 控制器
│  ├─config                      配置文件
│  ├─db                           數據庫相關配置
    ├─ model                     各個數據模型
    ├─ index.js                   數據庫配置頁面
│  ├─middleWares           中間件
│  ├─routes                      路由
    ├─ index.js                   路由入口文件
    ├─ users.js                  用戶路由
│  ├─service                    服務
│  ├─App.js                   入口文件
基于NodeJS的KOA2框架實現restful API網站后臺

 

package.json文件

每個Nodejs項目的根目錄下面,一般都會有一個package.json文件。該文件可以由npm init生成,定義了項目所需要的各種模塊,以及項目的配置信息(比如名稱、版本、許可證等元數據)。 package.json文件內部就是一個JSON對象,該對象的每一個成員就是當前項目的一項設置。

 

連接MySQL數據庫

mysql模塊是node操作MySQL的引擎,可以在node.js環境下對MySQL數據庫進行建表,增、刪、改、查等操作。

  "dependencies": {
    "glob": "^7.1.3",
    "jsonwebtoken": "^8.4.0",
    "koa": "^2.6.2",
    "koa-body": "^4.0.4",
    "koa-bodyparser": "^4.2.1",
    "koa-cors": "0.0.16",
    "koa-jwt": "^3.5.1",
    "koa-router": "^7.4.0",
    "koa-session": "^5.10.0",
    "koa-static": "^5.0.0",
    "mysql": "^2.16.0"
  }

在package.json依賴中設置"mysql": "^2.16.0"

const config = require('../config').database
const mysql = require('mysql')
const pool = mysql.createPool(config)
const query = function(sql,succCb,errCb){
  pool.getConnection(function(err,conn){
    if (err) {
      let data = {
        code:500,
        message:"請求失敗",
        data:err
      };
      errCb(data);
    }else {
      conn.query(sql,function(err,result){
        if (err) {
          let data = {
            code:500,
            message:"請求失敗",
            data:err
          };
          errCb(data);
        }else {
          succCb(result);
          conn.release();
        }
      })
    }
  })
}
module.exports = query;
const query = require('./query')
const Tools = require('./tools')
const mysql = require('mysql')
const config = require('../config').database
const pool = mysql.createPool(config)
const getByPage = function(tb,page,limit){
  return new Promise((resolve,reject)=>{
    let start = (page-1)*limit;
    let command = `select * from ${tb} limit ${start},${limit}`;
    query(command,function(res){
      let data = {
        code:200,
        message:'獲取成功',
        data:{
          list:res,
          pagination:{
            size:res.length,
            currentPage:parseInt(page)
          }
        }
      }
      query(`select count(*) from ${tb}`,function(res){
        data.data.pagination['total'] = res[0]["count(*)"];
        data.data.pagination['totalPage'] = parseInt(res[0]["count(*)"]/limit) + ((res[0]["count(*)"]%limit)>0?1:0);
        resolve(data);
      },function(err){
        resolve(data)
      })
    },function(err){
      resolve(err);
    })
  })
}
const getForeignInfo = function(tb,filter,foreign){//主表,篩選條件,外鍵信息
  let queryStr = '';//查詢條件
  for (let key in filter) {
    queryStr += `${tb}.${key}=${filter[key]}&`;
  }
  queryStr = queryStr.substr(0,queryStr.length-1);
  let as = '';
  let join = '';
  let tables = ` from ${tb} ${tb}`;
  for (let key1 in foreign) {
    let table = foreign[key1].table;
    let data = foreign[key1].data;
    let key = key1;
    join += ` join ${table} ${table} on ${tb}.${key}=${table}.id `;
    for(let key2 in data){
      as += `,${table}.${key2} as ${data[key2]}`
    }
  }
  let str = `select ${tb}.*`+as+tables+join+(queryStr==''?'':'where '+queryStr);
  console.log(str);
  return str;
}
const Sql = {
  queryAll:function(tb,filter,foreign){  //獲取表的全部記錄
    if (filter && !Tools.isEmptyObject(filter)) { //分頁
      return getByPage(tb,filter.page,filter.limit,foreign)
    }else {  //全部
      return new Promise((resolve,reject)=>{
        let str = `select * from ${tb}`;
        if (foreign) {
          str = getForeignInfo(tb,filter,foreign);
        }
        query(str,function(res){
          let data = {
            code:200,
            message:'獲取成功',
            data:{
              list:res,
              size:res.length
            }
          }
          resolve(data);
        },function(err){
          resolve(err);
        })
      })
    }
  },
  query:function(tb,id,foreign){ //根據id獲取
    return new Promise((resolve,reject)=>{
      query(`select * from ${tb} where id=${id}`,function(res){
        let data = {
          code:200,
          message:res.length==0?'查無數據':'獲取成功',
          data:res.length==0?{}:res[0]
        }
        resolve(data);
      },function(err){
        resolve(err);
      })
    })
  },
  queryByField:function(tb,fieldName,fieldValue){ //根據field獲取
    return new Promise((resolve,reject)=>{
      query(`select * from ${tb} where ${fieldName}="${fieldValue}"`,function(res){
        let data = {
          code:200,
          message:res.length==0?'查無數據':'獲取成功',
          data:res.length==0?{}:res[0]
        }
        resolve(data);
      },function(err){
        resolve(err);
      })
    })
  },
  insert:function(tb,data){  //插入一條記錄
    return new Promise((resolve,reject)=>{
      let [keys,values] = [[],[]];
      for (let key in data) {
        if (data.hasOwnProperty(key)) {
          keys.push(key);
          if (Object.prototype.toString.call(data[key]) == '[object String]') {
            values.push(`"${data[key]}"`)
          }else {
            values.push(data[key])
          }
        }
      }
      query(`insert into ${tb} (${keys}) values (${values})`,function(res){
        let id = res.insertId;
        let data = {
          code:200,
          message:'添加成功',
          data:res
        }
        query(`select * from ${tb} where id=${id}`,function(res){
          data.data = res[0];
          resolve(data);
        },function(err){
          resolve(data);
        })
      },function(err){
        resolve(err);
      })
    })
  },
  insertRows:function(tb,arr){ //插入多條記錄
    return new Promise((resolve,reject)=>{
      let [keys,values] = [[],[]];
      for (let i = 0; i < arr.length; i++) {
        let [data,value] = [arr[i],[]];
        for (let key in data) {
          if (data.hasOwnProperty(key)) {
            if (i==0) {
              keys.push(key);
            }
            if (Object.prototype.toString.call(data[key]) == '[object String]') {
              value.push(`"${data[key]}"`)
            }else {
              value.push(data[key])
            }
          }
        }
        values.push(`(${value})`);
      }
      query(`insert into ${tb} (${keys}) values ${values}`,function(res){
        let data = {
          code:200,
          message:'添加成功',
          data:res
        }
        let ids = [];
        for (let i = 0; i < res.affectedRows; i++) {
          ids.push(res.insertId+i);
        }
        query(`select * from ${tb} where id in (${ids})`,function(res){
          data.data = {
              list:res,
              size:res.length
          };
          resolve(data);
        },function(err){
          resolve(data);
        })
      },function(err){
        resolve(err);
      })
    })
  },
  update:function(tb,id,data){ //根據id修改單條記錄
    return new Promise((resolve,reject)=>{
      let [str,index] = ['',0];
      for (let key in data) {
        if (data.hasOwnProperty(key)) {
          if (index!=0) {
            str += ','
          }
          if (Object.prototype.toString.call(data[key]) == '[object String]'){
            str += `${key}="${data[key]}"`
          }
          else {
            str += `${key}=${data[key]}`
          }
          index++;
        }
      }
      query(`update ${tb} set ${str} where id=${id}`,function(res){
        let data = {
          code:200,
          message:'修改成功',
          data:res
        }
        query(`select * from ${tb} where id=${id}`,function(res){
          data.data = res[0];
          resolve(data);
        },function(err){
          resolve(data);
        })
      },function(err){
        resolve(err);
      })
    })
  },
  updateRows:function(tb,arr){  //修改多條記錄
    return new Promise((resolve,reject)=>{
      let [str,ids,len,keys] = ['',[],arr.length,Object.keys(arr[0])];
      for (let x = 0; x < len; x++) {
        ids.push(arr[x].id);
      }
      for (let i = 0; i < keys.length; i++) {
        let k = keys[i];
        if (k!='id') {
          str += `${k} = case id `;
          for (let j = 0; j < len; j++) {
            str += `when ${arr[j].id} then `;
            if (Object.prototype.toString.call(arr[j][k]) == '[object String]'){
              str += `"${arr[j][k]}" `
            }
            else{
              str += `${arr[j][k]} `
            }
          }
          str += 'end'
          if (i<keys.length-1) {
            str += ','
          }
        }
      }
      query(`update ${tb} set ${str} where id in (${ids})`,function(res){
        let data = {
          code:200,
          message:'修改成功',
          data:res
        }
        query(`select * from ${tb} where id in (${ids})`,function(res){
          data.data = {
              list:res,
              size:res.length
          };
          resolve(data);
        },function(err){
          resolve(data);
        })
      },function(err){
        resolve(err);
      })
    })
  },
  delete:function(tb,id){ //根據id刪除單條記錄
    return new Promise((resolve,reject)=>{
      query(`delete from ${tb} where id=${id}`,function(res){
        let data = {
          code:200,
          message:'刪除成功',
          data:res
        }
        resolve(data);
      },function(err){
        resolve(err);
      })
    })
  },
  deleteRows:function(tb,data){ //根據id數組刪除多條記錄
    return new Promise((resolve,reject)=>{
      query(`delete from ${tb} where id in (${data})`,function(res){
        let data = {
          code:200,
          message:'刪除成功',
          data:res
        }
        resolve(data);
      },function(err){
        resolve(err);
      })
    })
  },
  search:function(tb,data,foreign){ //根據條件準確查詢
    let queryStr = '';//查詢條件
    for (let key in data) {
      queryStr += `${key}=${data[key]}&`;
    }
    queryStr = queryStr.substr(0,queryStr.length-1);
    let str;
    if (foreign) {
      str = getForeignInfo(tb,data,foreign);
    }else {
      str = `select * from ${tb} where ${queryStr}`
    }
    return new Promise((resolve,reject)=>{
      query(str,function(res){
        resolve({
          code:200,
          message:'獲取成功',
          data:res
        });
      },function(err){
        resolve(err);
      });
    })
  },
  searchVague:function(tb,val,fields,foreign){//根據條件模糊查詢
    let str = `select * from ${tb} where concat(`;
    for (let i = 0; i < fields.length; i++) {
      str += `${fields[i]},`;
    }
    str = str.substring(0,str.length-1);
    str += `) like %${val}%`;
    if (fields.length==1){
      str = `select * from ${tb} where ${fields[0]} like '%${val}%'`;
    }
    return new Promise((resolve,reject)=>{
      query(str,function(res){
        resolve({
          code:200,
          message:'獲取成功',
          data:res
        });
      },function(err){
        resolve(err);
      });
    })
  }
}

module.exports = Sql;

 

登錄和JWT認證實現

引入 "jsonwebtoken": "^8.4.0",模塊

const jwt = require('jsonwebtoken');
const Token = {
  encrypt:function(data,time){ //data加密數據,time過期時間
    return jwt.sign(data, 'token', {expiresIn:time})
  },
  decrypt:function(token){
    try {
      let data = jwt.verify(token, 'token');
      return {
        token:true,
        id:data.id
      };
    } catch (e) {
      return {
        token:false,
        data:e
      }
    }
  }
}
module.exports = Token

登錄成功返回token代碼:

token = jwt.sign({id:res[0].id}, 'token', {expiresIn: '15d'})

restful api實現示例

需求:小程序用戶輸入單詞,返回這個單詞的詳細介紹,包含中文釋義和常用例句。

建立wordDesc表

基于NodeJS的KOA2框架實現restful API網站后臺

 

添加一個routers文件

wordDesc.js

const router = require('koa-router')();   //路由
const Sql = require('../utils/sql');
const query = require('../utils/query');
const Tools = require('../utils/tools');
const jwt = require('jsonwebtoken');
const Token = require('../utils/token')
const tbName = 'worddesc';
const preUrl = '/api/worddesc';
let codeList = {};

api/worddesc/test

.get(`${preUrl}/:word`,async(ctx,next)=>{ //獲取word desc
   let word = ctx.params.word;
   let data = Token.decrypt(ctx.header.authorization);
   if (data.token) {
     let res = await Sql.queryByField(tbName,"word", word);
     ctx.body = res;
   }else {
     ctx.body = {
       code:401,
       message:'failed',
       data:data
     };
   }
 })
{
    "code": 200,
    "message": "獲取成功",
    "data": {
        "id": 2,
        "word": "test",
        "description": "this is a test.",
        "bookid": "2",
        "createdtime": null,
        "lastupdatetime": null,
        "maxl": 2
    }

分頁獲取列表數據

/api/worddesc?page=2&count=2

.get(`${preUrl}`,async(ctx,next)=>{ //獲取word desc

   let data = Token.decrypt(ctx.header.authorization);
   if (data.token) {

     let page = ctx.query.page;
     if(page == undefined){
         page = 1;
     }
     let count = ctx.query.count;

     if(count ==undefined){
         count = 500;
     }

     let filter = {
         page:page,
         limit:count
     }
     

     let res = await Sql.queryAll(tbName,filter);
     ctx.body = res;
   }else {
     ctx.body = {
       code:401,
       message:'failed',
       data:data
     };
   }
 })
{
    "code": 200,
    "message": "獲取成功",
    "data": {
        "list": [
            {
                "id": 2,
                "word": "test",
                "description": "this is a test.",
                "bookid": "2",
                "createdtime": null,
                "lastupdatetime": null,
                "maxl": 2
            },
            {
                "id": 3,
                "word": "year3",
                "description": "year3",
                "bookid": "3",
                "createdtime": null,
                "lastupdatetime": null,
                "maxl": 3
            },
            {
                "id": 4,
                "word": "ljtest",
                "description": "desc........",
                "bookid": "2",
                "createdtime": null,
                "lastupdatetime": null,
                "maxl": null
            },
            {
                "id": 6,
                "word": "lj2",
                "description": null,
                "bookid": null,
                "createdtime": null,
                "lastupdatetime": null,
                "maxl": null
            },
            {
                "id": 7,
                "word": "lj3",
                "description": null,
                "bookid": null,
                "createdtime": null,
                "lastupdatetime": null,
                "maxl": null
            },
            {
                "id": 8,
                "word": "lj4",
                "description": null,
                "bookid": null,
                "createdtime": null,
                "lastupdatetime": null,
                "maxl": null
            }
        ],
        "pagination": {
            "size": 6,
            "currentPage": 1,
            "total": 6,
            "totalPage": 1
        }
    }
}

同樣增加添加、修改、刪除api

 .post(`${preUrl}`,async(ctx,next)=>{ //添加信息
   let data = Token.decrypt(ctx.header.authorization);
   
   let word = ctx.request.body.word;

   if (data.token) {
     let wordRes = await  Sql.queryByField(tbName,"word",word);
     console.log("------------");
     console.log(wordRes);
     if(wordRes.data.id != undefined)
     {
        let res = await Sql.update(tbName,wordRes.data.id,ctx.request.body);
        ctx.body = res;
     }else{
        
        let res = await Sql.insert(tbName,ctx.request.body);
        ctx.body = res;
     }
     
     
    
   }else {
     ctx.body = {
       code:401,
       message:'failed',
       data:data
     };
   }
  })

  .delete(`${preUrl}/:word`,async(ctx,next)=>{ //修改信息
    let data = Token.decrypt(ctx.header.authorization);
    
    let word = ctx.params.word;

    if (data.token) {
        let wordRes = await  Sql.queryByField(tbName,"word",word);
        if(wordRes.data.id != undefined)
        {

            let res = await Sql.delete(tbName,wordRes.data.id );
            ctx.body = res;
        }else{

        ctx.body = {
        code:200,
        message:'no record',
        data:''
        };
    }
        
        
        
    }else {
        ctx.body = {
        code:401,
        message:'failed',
        data:data
        };
    }

   })

  .put(`${preUrl}/:word`,async(ctx,next)=>{ //修改信息
   let data = Token.decrypt(ctx.header.authorization);
   
   let word = ctx.params.word;
   console.log(word);

   if (data.token) {
     let wordRes = await  Sql.queryByField(tbName,"word",word);
     console.log("------------");
     console.log(wordRes);
     if(wordRes.data.id != undefined)
     {
        console.log("id------------");
        console.log(wordRes.data.id);
        console.log(ctx.request.body);
        let res = await Sql.update(tbName,wordRes.data.id ,ctx.request.body);
        ctx.body = res;
     }else{

       ctx.body = {
       code:200,
       message:'no record',
       data:''
     };
     }
     
     
    
   }else {
     ctx.body = {
       code:401,
       message:'failed',
       data:data
     };
   }
 })

管理和發布api

開發過程中命令行輸入 node app.js 可以打開命令窗口啟動運行,窗口中顯示調試或錯誤信息,關閉窗口則結束進程。

生產環境中可以使用pm2來啟動進程,M2是可以用于生產環境的Nodejs的進程管理工具,并且它內置一個負載均衡。它不僅可以保證服務不會中斷一直在線,并且提供0秒reload功能,還有其他一系列進程管理、監控功能。并且使用起來非常簡單。

安裝pm2

npm install -g pm2

下面列出常用命令

$ npm install pm2 -g     # 命令行安裝 pm2 
$ pm2 start app.js -i 4 #后臺運行pm2,啟動4個app.js 
                                # 也可以把'max' 參數傳遞給 start
                                # 正確的進程數目依賴于Cpu的核心數目
$ pm2 start app.js --name my-api # 命名進程
$ pm2 list               # 顯示所有進程狀態
$ pm2 monit              # 監視所有進程
$ pm2 logs               #  顯示所有進程日志
$ pm2 stop all           # 停止所有進程
$ pm2 restart all        # 重啟所有進程
$ pm2 reload all         # 0秒停機重載進程 (用于 NETWORKED 進程)
$ pm2 stop 0             # 停止指定的進程
$ pm2 restart 0          # 重啟指定的進程
$ pm2 startup            # 產生 init 腳本 保持進程活著
$ pm2 web                # 運行健壯的 computer API endpoint (http://localhost:9615)
$ pm2 delete 0           # 殺死指定的進程
$ pm2 delete all         # 殺死全部進程

 

總結

對于nodejs能夠流行起來一點都不感到意外,開發起來太簡單和方便了。跟java這些傳統的技術相比,寫nodejs腳本甚至感覺不像是在編程,真的像玩一樣,極大了拉低了程序員的門檻。

還有一個事實就是JavaScript是Web開發者們熟知的語言,大部分人都了解JavaScript或多少使用過它。所以說,從其他技術轉型到Node.js是很簡單的。

跟java、.net這些傳統的技術路線相比,nodejs項目在安裝、調試、部署和發布都很方便,很多Web服務器和云服務提供商都支持Node.js的Web應用。

分享到:
標簽:框架 KOA2
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定