传送门

一、前期框架的搭建

后台采用的框架为Koa2框架,编程软件为vs code,node环境

  • 步骤一:创建一个空文件
  • 步骤二:在vs code打开该文件,并按ctrl+`打开终端
  • 步骤三:输入命令npm init(初始化package.json),也可以用npm init -y(直接默认初始化package.json)
  • 步骤四:输入命令npm install koa(下载koa)

二、获取AcessToken(接口调用凭证)

获取小程序全局唯一后台接口调用凭据(access_token)。调用绝大多数后台接口时都需使用 access_token,开发者需要进行妥善保存。
      由于,我是调用云函数,所以必须需要接口调用凭证。

注意:

中控服务器是自己搭建的后台

请求地址及参数
GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET


因为要不断使用接口调用凭证,所以将其封装成一个方法,再向外抛出接口。

代码实现:

  • 在实现前,因为需要向第三方请求数据(请求接口调用凭证),故需要下载第三方库,我使用的是request-promise(依赖于request)
  • 在终端输入先输入命令npm install request 下载成功后再输入命令npm install request-promise
  • 也可以使用axios第三方库进行请求数据
const rp = require('request-promise')
const fs = require('fs')//自带的
const path = require('path')//自带的
const fileName = path.resolve(__dirname, './access_token.json')//创建文件并获取绝对路径
const APPID = '您的小程序ID'
const APPSECRET = '您的小程序密钥'//不能泄露
const URL = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${APPSECRET}`//更新AccessToken
const updateAccessToken = async () => {//发送请求获取AccessTokenconst resStr = await rp(URL)const res = JSON.parse(resStr)//  将AccessToken写入文件if (res.access_token) {//JSON.stringify()将对象转化成字符串fs.writeFileSync(fileName, JSON.stringify({access_token: res.access_token,createTime: new Date()}))} else {//如果AccessToken不存在,再次更新AccessTokenawait updateAccessToken()}
}//获取AccessToken
const getAccessToken = async () => {//读取文件获取AccessTokentry {//读取文件,编码为utf-8const readRes = fs.readFileSync(fileName, 'utf8')const readobj = JSON.parse(readRes)const createTime=new Date(readobj.createTime).getTime()const nowTime=new Date().getTime()if((nowTime-createTime)/1000/60/60>=2){//判断是否已经超过俩个小时,超过俩个小时再次调用updateAccessToken方法await updateAccessToken()}return readobj.access_token} catch (error) {//文件不存在,说明AccessToken没有被更新await updateAccessToken()getAccessToken()}
}// 定时器(定时获取AccessToken 提前5分钟)
setInterval(async () =>{await updateAccessToken()
},6900*1000)//导出接口(给调用方使用)
module.exports=getAccessToken

运行测试

  • 在终端进入到该文件夹中(cd …返回到上级目录或者cd 目标目录)
  • 输入命令编译文件 node 文件名

三、搭建后台,并返回数据到前端(重点)

前期准备
(1)由于我前端和后台都是在本地运行,但端口号不同,此时会产生跨域问题。

  • 解决方法:
    我采用的方法时用cors来解决,首先在项目中打开终端,输入命令npm install koa2-cors

    然后在项目的入口文件(app.js)中,导入该第三方库,解决跨域问题
const cors=require('koa2-cors')
//解决跨域问题
app.use(cors({//配置允许访问后台的URL地址(前端地址)origin:['http://localhost:9528'],credentials:true
}))

在实现前后端分离,都会出现跨域问题,有以下几种形式

  • http://www.a.com http://www.b.com 域名不一样
  • http://www.a.com:8080 http://www.a.com:8081 端口不一样
  • http://www.a.com http://news.a.com 主域和子域之间
  • http://www.a.com https://www.a.com 协议不一样

(2)配置后端路由,我使用的是koa-router,打开项目终端,输入命令npm install koa-router

(3)下载第三请求库request-promise,由于前面部分已经下载了,所以直接导入即可。

代码实现

知识点一:调用云函数 我这里是通过调用云函数实现从云数据库中获取歌单信息,下面是我部署的云函数(云函数名为music,路由名(地址)为playlist)

app.router('playlist', async (ctx, next) => {ctx.body = await cloud.database().collection('playlist').skip(event.start).limit(event.count).orderBy('createTime', 'desc').get().then((res) => {return res})})

后台调用云函数

const Router=require('koa-router')
const router=new Router()const getAccessToken=require('../utils/getAccessToken.js')
const rp=require('request-promise')// /list是后台路由地址
router.get('/list',async(ctx,next)=>{// 获取调用接口凭证const access_token= await getAccessToken()//云数据库运行环境const ENV='您的云开发环境ID'//调用云函数地址(参数name是您的云函数名字)const URL=`https://api.weixin.qq.com/tcb/invokecloudfunction?access_token=${access_token}&env=${ENV}&name=music`//获取前端的发送过来的请求数据const query=ctx.request.query//调用云函数的请求参数(封装成对象)const option={method:'POST',//必须是POST请求url:URL,body:{$url:'playlist',//云函数的路由名(地址)start:parseInt(query.start),count:parseInt(query.count)},json:true//返回格式为JSON格式};//发送请求const data=await rp(option).then((res)=>{//console.log(res)return JSON.parse(res.resp_data).data}).catch((err)=>{console.log(err)})//返回数据给前端ctx.body={data,code:20000}
})
module.exports=router//将路由抛出

在返回数据中,一个数据code:20000 目的是:因为我前端采用的是vue-admin-template搭建的前端管理系统,必须返回code:20000。

优化代码
由于后台大部分功能是调用云函数,所以说调用云函数的代码内容基本是一样的。可以将调用云函数的方法进行封装,下面是封装的代码

const getAccessToken = require('./getAccessToken.js')
const rp = require('request-promise')const callCloudFn = async (ctx, fnName, params) => {const ACCESS_TOKEN = await getAccessToken()const options = {method: 'POST',uri: `https://api.weixin.qq.com/tcb/invokecloudfunction?access_token=${ACCESS_TOKEN}&env=${ctx.state.env}&name=${fnName}`,//ctx.state.env通过全局中间件获取云开发环境,在入口文件(app.js)有配置body: {...params},json: true }return await rp(options).then((res) => {return res//注:返回的格式是字符串}).catch(function (err) {})
}module.exports = callCloudFn

此时需要修改路由list中的代码

const Router=require('koa-router')
const router=new Router()
const rp=require('request-promise')
const callCloudFun=require('../utils/callCloudFn')router.get('/list',async(ctx,next)=>{//获取前端请求的数据const query=ctx.request.query//发送请求const res=await callCloudFun(ctx,'music',{$url:'playlist',start:parseInt(query.start),count:parseInt(query.count)})let data=[]if(res.resp_data){data=JSON.parse(res.resp_data).data}ctx.body={data,code:20000,}
})
module.exports=router

这样的好处就是减少代码的重复率,增加代码的利用率。

知识点二:API调用云数据库

前期准备
(1)下载koa-body,获取post请求数据

在app.js配置以下代码

//接收post参数解析
app.use(koaBody({multipart: true,
}))

(2)创建功能模块

const rp=require('request-promise')
const getAccessToken = require('./getAccessToken.js')
const callCloudDB=async(ctx,fnName,query={})=>{//fnName数据操作的类型 query数据操作语句const access_token=await getAccessToken()const options={method:'POST',uri:`https://api.weixin.qq.com/tcb/${fnName}?access_token=${access_token}`,body:{query,env:ctx.state.env,},json:true}return await rp(options).then((res)=>{return res}).catch((err)=>{console.log(err)})
}
module.exports=callCloudDB

(3)更新数据
因为前端提交更新数据的形式是post,所以后端代码应该为post

router.post('/updatePlaylist',async(ctx,next)=>{//获取请求体const params=ctx.request.body//更新语句const query=`db.collection('playlist').doc('${params._id}').update({data:{name:'${params.name}',copywriter:'${params.copywriter}'}})`const res= await callCloudDB(ctx,'databaseupdate',query)ctx.body={code:20000,data:res}
})
module.exports=router

(4)删除数据

router.get('/deletePlaylist',async(ctx,next)=>{const query=`db.collection('playlist').doc('${ctx.request.query.id}').remove()`const res=await callCloudDB(ctx,'databasedelete',query)ctx.body={code:20000,data:res}
})

(5)增加数据

 const query=`db.collection('swiper').add({data:{fileId:'${fileid}'}})`const res=await callCloudDB(ctx,'databaseadd',query)

(6)查询数据

router.get('/getById',async(ctx,next)=>{const query=`db.collection('playlist').doc('${ctx.request.query.id}').get()`const res=await callCloudDB(ctx,'databasequery',query)//console.log(res)ctx.body={code:20000,data:JSON.parse(res.data)}
})

知识点三:文件的上传、下载和删除

创建功能模块

const getAccessToken = require('./getAccessToken.js')
const callCloudDB = require('./callCloudDB.js')const rp =require('request-promise')
const fs=require('fs')const cloudStore={//下载图片async download(ctx,fileList){const ACCESSTOKEN=await getAccessToken()const options={method:'POST',uri:`https://api.weixin.qq.com/tcb/batchdownloadfile?access_token=${ACCESSTOKEN}`,body:{env:ctx.state.env,file_list:fileList},json:true}return await rp(options).then((res)=>{return res}).catch((err)=>{console.log(err)})},//上传图片到云存储async uploadfile(ctx){//步骤一:发送上传文件的请求,获取相应信息const ACCESSTOKEN=await getAccessToken()const file=ctx.request.files.file//上传文件信息//文件路径(随机)const path=`swiper/${Date.now()}-${Math.random}-${file.name}`const options={method:'POST',uri:`https://api.weixin.qq.com/tcb/uploadfile?access_token=${ACCESSTOKEN}`,body:{env:ctx.state.env,path:path},json:true}const info= await rp(options).then((res)=>{return res}).catch((err)=>{console.log(err)})//console.log(info)//步骤二:上传图片const params={method:"POST",headers:{"content-type":'multipart/form-data',                },uri:info.url,formData:{key:path,Signature:info.authorization,'x-cos-security-token':info.token,'x-cos-meta-fileid':info.cos_file_id,file:fs.createReadStream(file.path)//二进制文件},json:true}await rp(params)return info.file_id//返回文件id到调用方,将其存储在云数据库}//删除文件async delFile(ctx,fileid_list){const ACCESSTOKEN=await getAccessToken()const options={method:'POST',uri:` https://api.weixin.qq.com/tcb/batchdeletefile?access_token=${ACCESSTOKEN}`,body:{fileid_list,env:ctx.state.env,},json:true}return await rp(options).then((res)=>{return res}).catch((err)=>{console.log(err)})}
}module.exports= cloudStore

(2)调用功能模板

//读取图片(获取歌曲链接)
router.get('/list',async(ctx,next)=>{//读取数据库文件信息const query=`db.collection('swiper').get()`const res=await callCloudDB(ctx,'databasequery',query)//获取图片链接(http形式)let fileList=[]const data=res.data//遍历文件信息,封装请求对象for(let i=0,len=data.length;i<len;i++){fileList.push({fileid:JSON.parse(data[i]).fileId,max_age:7200})}//获取下载链接(http形式)const dlRes=await cloudStore.download(ctx,fileList)//封装对象,将所需要的信息返回到前端let returnData=[]for(let i=0,len=dlRes.file_list.length;i<len;i++){returnData.push({download_url:dlRes.file_list[i].download_url,//文件下载链接fileId : dlRes.file_list[i].fileid,_id:JSON.parse(data[i])._id})}ctx.body={code:20000,data:returnData}
})
//上传图片
router.post('/upload',async(ctx,next)=>{//上传图片 返回文件idconst fileid=await cloudStore.uploadfile(ctx)//console.log(fileid)const query=`db.collection('swiper').add({data:{fileId:'${fileid}'}})`//写入数据库const res=await callCloudDB(ctx,'databaseadd',query)ctx.body={code:20000,id_list:res.id_list}
})
//删除文件
export function del(params){return request({params,url:`${baseURL}/swiper/del`,method:'get'})
}

四、配置入口文件(app.js)

const Koa=require('koa')
const Router=require('koa-router')
const cors=require('koa2-cors')
const koaBody=require('koa-body')
const ENV='haocloud-xagb6'
const app=new Koa()
const router=new Router()//解决跨域问题
app.use(cors({//配置允许访问后台的URL地址origin:['http://localhost:9528'],credentials:true
}))//接收post参数解析
app.use(koaBody({multipart: true,
}))//全局中间键
app.use(async(ctx,next)=>{ctx.state.env=ENVawait next()
})// http://localhost:3000/playlist/list(调用获取歌单的URL)
const playlist=require('./controller/playlist.js')
router.use('/playlist',playlist.routes())const swiperList=require('./controller/swiper.js')
router.use('/swiper',swiperList.routes())const blogList=require('./controller/blog.js')
router.use('/blog',blogList.routes())//声明router
app.use(router.routes())
//允许router下的所有方法
app.use(router.allowedMethods())app.listen(8080,()=>{console.log('服务开启在端口为8080')
})

此时,如果前端要获取歌单信息,则需要向后端地址为http://localhost:8080/playlist/list发送请求

  • playlist指的是 routers.use(’/playlist’,playlist.routes())中的playlist
  • list指的是router.get(’/list’,async(ctx,next)=>{}中的list(就是一个叫playlist的router的路由下的名为list的路由 个人理解)

最后启动后端服务,在终端输入命令 node app.js(编译入口文件)

结束编译:ctrl+C即可

微信小程序后台管理系统(后端)笔记相关推荐

  1. (毕设课设)基于SSM的食堂订餐小程序(微信小程序+后台管理系统)

    本系统基于SSM的食堂订餐小程序系统的设计与实现的过程,运用了B/S架构,JAVA的SSM框架,前后端分离等设计模式,使用了mysql管理数据库,微信开发者工具开发小程序前端,eclipse开发系统后 ...

  2. 微信小程序毕业设计健康食谱菜谱系统微信小程序+后台管理系统|前后分离VUE.js

  3. “李记餐厅”微信点餐小程序+后台管理系统

     博主介绍:✌在职Java研发工程师.专注于程序设计.源码分享.技术交流.专注于Java技术领域和毕业设计✌ 项目名称 "李记餐厅"微信点餐小程序+后台管理系统 效果视频 http ...

  4. 微信小程序药店管理系统+后台管理系统|前后分离VUE

    <微信小程序药店管理系统+后台管理系统|前后分离VUE>该项目含有源码.论文等资料.配套开发软件.软件安装教程.项目发布教程等 本系统包含微信小程序前台和Java做的后台管理系统,该后台采 ...

  5. 精品微信小程序预约挂号小程序+后台管理系统|前后分离VUE

    <微信小程序预约挂号小程序+后台管理系统|前后分离VUE>该项目含有源码.论文等资料.配套开发软件.软件安装教程.项目发布教程等 本系统包含微信小程序前台和Java做的后台管理系统,该后台 ...

  6. 【程序源代码】微信小程序商城管理系统(Java后台+微信小程序)最新版

    关键字:微信小程序 商城系统 02 - [技术框架] 微信小程序商城管理系统(Java后台+微信小程序) 基于Spring+Vue+Mysql+Redis主流技术开发框架集成开发的微信商场管理系统:其 ...

  7. 精品微信小程序springboot在线考试系统小程序+后台管理系统

    <微信小程序在线考试系统小程序+后台管理系统|前后分离VUE>该项目含有源码.论文等资料.配套开发软件.软件安装教程.项目发布教程等 本系统包含微信小程序前台和Java做的后台管理系统,该 ...

  8. 微信小程序招聘管理系统+后台管理系统

    <微信小程序招聘管理系统+后台管理系统>该项目含有源码.论文等资料.配套开发软件.软件安装教程.项目发布教程等 本系统包含微信小程序做的招聘管理系统前台和Java做的后台管理系统: 微信小 ...

  9. 【程序源代码】微信小程序商城管理系统(java后台+小程序)

    关键字:微信小程序 商城管理系统 正文 | 内容 01 - [概述] 基于 微信小程序 + springboot + vue 技术构建 ,支持单店铺,多店铺入驻的商城平台.项目包含 微信小程序,管理后 ...

  10. 微信小程序论文管理系统+后台管理系统

    <微信小程序论文管理系统+后台管理系统>该项目含有源码.论文等资料.配套开发软件.软件安装教程.项目发布教程等 本系统包含微信小程序做的论文管理系统前台和Java做的后台管理系统: 微信小 ...

最新文章

  1. 使用 C# + SQLite + PetaPoco + django 快速打造桌面程序
  2. 数据对象类代码的生成小工具
  3. 编译时,输出信息重定向到文件
  4. jq 修改swal的标题_js-jquery-SweetAlert2【一】使用
  5. 自己常用的C/C++小技巧
  6. 华为技术有限公司申请“荣耀视频”、“荣耀钱包”等商标
  7. VisualStudio异常处理 —— LNK1112 模块计算机类型“x64”与目标计算机类型“X86”冲突
  8. 杭电1028Ignatius and the Princess III
  9. 从 2.4 到 2.6:Linux 内核可装载模块机制的改变对设备驱动的影响(二)
  10. 施密特触发器——用于正弦波转方波、脉冲波整形
  11. Flutter报setState() or markNeedsBuild() called during build.错误解决办法
  12. 项目管理知识体系指南 (六)
  13. 零基础想学习大数据?(同样适合有一定基础想进阶的)跟着这几个步骤走
  14. oracle 11g duplicate database基于备份复制数据库(五)
  15. 而洗洁精膜会有效地保持玻璃2小时内不结霜
  16. apache更改网站目录
  17. 微信服务器保留几年记录_你以为微信只是个聊天工具?看完这些刷新对微信的认知...
  18. HanLP极致简繁转换详细讲解 1
  19. Twitter API: Door To Social Media Analysis I
  20. HRBUST1310 火影忍者之~鸣人

热门文章

  1. android gdbserver
  2. 二分(POJ - 3273 )
  3. 计算机语言有哪些面向对象,面向对象的几个概念
  4. 用python逆序输出字符串中的所有元素_Python中逆序输出字符串的六种方法
  5. 数学建模美赛E题数据获取
  6. 小白都能理解的FTRL
  7. 记一次python分布式web开发(利用docker)
  8. python跳出if_python跳出if
  9. stm32是以c语言来编程吗,stm32用什么语言编程
  10. crontab mysql命令_crontab命令使用介绍