天天看点

小程序云开发:菜鸟也能全栈做产品

我想独立实现一个全栈产品为什么这么难

日常生活中,我们会使用很多软件产品。在使用这些产品的时候,我们看得见的东西称为“前端界面”如一个输入框、一个按钮,点击按钮之后发生的一切看不见的东西称为“后端服务”。与之对应的创造者分别称为“前端程序员”、“后端程序员”,然而,一个完整产品的开发不仅仅是只有前端和后端,还有设计师,架构师,运维等。有没有可能这些所有的事情都一个人干呢?有可能,事实上如今就有很多的“全栈工程师”,他们身兼数职,是多面手。能独立完成一个产品的方方面面。这种人固然十分了得,他们通常具有多年的经验,涉猎广泛,是老手,也是高手,当有一个产品想法的时候,他们可以用自己的全面专业技能,尽情的发挥去实现自己的想法。所以,从某种意义上讲“全栈也是一种自由”,你可以自由的实现你的想法,这简直太美妙了!

然而,很多时候当我们有一个产品想法的时候,我们往往发现,前端写完了,后端怎么搞?数据库怎么搞?域名怎么搞?域名还要备案?应用部署怎么搞?我的买什么样的服务器啊?静态资源 CDN 怎么搞?文件上传服务器怎么搞?万一访问用户多了能撑住吗?等等……问题很多,导致你的一个个想法,都只是在脑海中昙花一现,从来都无法将她们实现,或者说你激情饱满的实现了其中自己最擅长的一部分,当碰到其他难题的时候就止步了。于是仰天长啸:我就想独立做一个完整的产品为什么这么难?年轻人,这一切都不怪你……

破局:小程序云开发

为什么使用小程序云开发来破局?

为啥是用“小程序云开发”来破局?首先,我们的目的是全栈实现一个产品。全栈可以有多种技术方案,你可用任何你能会的技能来达到全栈的目的。你可以开发安卓,IOS,或者 PC 站,然而小程序是最实际的!为啥?手机上能做的事情为啥要用 PC 版?OK,既然手机版比较好,那能不能再简单一点?能,就是小程序,不需要开发IOS,安卓两个版本。可以快速产出,快速试错。

其次,前面说到了,全栈实现一个产品并不容易,对很多人来说甚至是巨难!选择了小程序已经是比较划算的方案。而再集成云开发,全栈立马就有了。这就是为什么选择“小程序云开发”来破局。

小程序云开发是什么?

小程序云开发是什么?官方文档是这么说的:开发者可以使用云开发开发微信小程序、小游戏,无需搭建服务器,即可使用云端能力。云开发为开发者提供完整的原生云端支持和微信服务支持,弱化后端和运维概念,无需搭建服务器,使用平台提供的 API 进行核心业务开发,即可实现快速上线和迭代,同时这一能力,同开发者已经使用的云服务相互兼容,并不互斥。

看完上面的描述,也许你仍然无法非常清楚的知道什么是“小程序云开发”,没关系,你只需要注意加粗的部分,大概知道它“无需搭建服务器”,从传统观念将,这个似乎“毁三观”咋可能没服务器啊?是的,可以没有传统意义上的服务器,这种模式是 serveless 的。

那么,小程序云开发提供了哪些东西来破局呢?且看下面的表格:

能 力 作 用 说 明
云函数 无需自建服务器 在云端运行的代码,微信私有协议天然鉴权,开发者只需编写自身业务逻辑代码
数据库 无需自建数据库 一个既可在小程序前端操作,也能在云函数中读写的 JSON 数据库
存储 无需自建存储和 CDN 在小程序前端直接上传/下载云端文件,在云开发控制台可视化管理
云调用 原生微信服务集成 基于云函数免鉴权使用小程序开放接口的能力,包括服务端调用、获取开放数据等能力

上面的表格中提到了“云开发”中的一些能力:“云函数”,“数据库”,“存储”,“云调用”,我们可以将这些词带入你曾经开发过的应用,看看它们分别代表了哪些部分。对于程序员来说,如果有疑问的话,没有什么是一个 helloword 解决不了的。

实战:独立开发一个简易的零售小程序

哆嗦再多,不如实战。下面我们就来使用小程序云开发实现一个简单的零售小程序。

项目构思

既然是一个零售小程序,那么我们可以思考一下零售小程序的大致业务流程,以及粗略的梳理一下,其功能点。现根据自己的想法,大致画一下草图,如果没有灵感可以参考一下别的 APP 是如何设计的。

我根据自己的想法设计之后是这样的:

功能模块:首页,商品列表页,购物车,确认订单,个人中心,个人订单,管你模块(商品添加,分类添加)其中商品需要上传图片。

梳理完功能之后,我们对于要实现的东西已经有个初步的概念了。接下来,我们需要大概画一下页面设计、及功能流转。初次设计可能没有太多经验,没关系,开始做就行了,做着做着就会想法越来越多,然后优化的越来越好。。我也是经过了多番修改调整,最终找到了一些思路。我的(拙劣)设计如下,图片如果看不清楚可复制图片链接在新窗口打开查看:

小程序云开发:菜鸟也能全栈做产品

说明,以上图片是根据成品(我真的开发了一个云小程序并上线使用了)截图的,而实际我再设计的时候也是经过几番修改才最终定成这样。

同时,补充说明一下,这里前端页面使用的是 vant-weapp控件,非常好用。推荐!如果你和我一样是一个纯后端程序员,建议使用 vant-weapp 来作为 ui,非常方便。否则自己写页面样式的话可能就做不出来了。全栈不是那么好干的啊。选择自己能驾驭的,能实现最终功能,就是一个合格的全栈。

创建小程序云开发项目

我们先下载微信小程序开发工具,下载地址在这里,安装好了之后,新建项目,界面如下,APPID 需要你自己去注册一个。然后注意,选择“小程序云开发”,如下图所示:

小程序云开发:菜鸟也能全栈做产品

创建好了之后,项目目录如下,先看 1 标注的地方:

小程序云开发:菜鸟也能全栈做产品

如果你曾经有过小程序的开发经验,那么

miniprogram

文件夹下面的结构你肯定熟悉了,

miniprogram

下面的子目录分别是小程序对应的组件、图片、页面、样式以及

app.js

,

app.json

sitemap.json

,其中

components

下面的

vant-weapp

就是上面提到的 ui 组件。

最后一个比较重要的文件夹就是

cloudfunctions

,这个目录是用来存放“云函数的”,云函数就是我们的后端。每一个云函数提供一个服务。一个个的云函数组成了我们整体的后端服务。云函数可以看做是 FaaS(function as a service)。途中,2 标记的位置的“云开发”按钮,我们点进去,就可以看到“云开发的控制台”,如下图所示:

小程序云开发:菜鸟也能全栈做产品

如果上图看不清楚,可以复制链接到新的浏览器窗口查看,如图,小程序云开发默认的免费套餐有一定的额度可供使用。首页便是使用统计。然后我们能看到,有“数据库”,“存储”,“云函数”。

这里的“数据库”其实就是类似于一个 MongoDB,你可以点进去创建一个个的 collection(即:关系型数据库中的table);这里的“存储”其实就是“文件夹”,我们可以通过微信提供的 api把图片上传到“存储”中;这里的“云函数”就是我们需要实现的后端业务逻辑,他就是一个个的函数(函数由我们自己写好后上传)。一般开发过程中我们在开发者工具中的

cloudfunctions

目录下创建云函数(比方说是:user-add)开发完成之后在云函数目录点击右键——上传即可。然后就可以在小程序的代码中调用这个

user-add

云函数。

云开发之——3 分钟实现文件上传

注意:在开始云开发之前,我们现在 小程序代码的 app.js 中加入

wx.cloud.init

,如下:

App({
  onLaunch: function () {
    if (!wx.cloud) {
      console.error('请使用 2.2.3 或以上的基础库以使用云能力')
    } else {
      wx.cloud.init({
        // env 参数说明:
        //   env 参数决定接下来小程序发起的云开发调用(wx.cloud.xxx)会默认请求到哪个云环境的资源
        //   此处请填入环境 ID, 环境 ID 可打开云控制台查看
        //   如不填则使用默认环境(第一个创建的环境)
        env: 'your-env-id',
        traceUser: true,
      })
    }
    this.globalData = {}
  }
})
           

上面的图中,我们已经看到了“商品添加”页面的效果,它需要我们输入商品名称、价格、并上传图片,然后保存。传统架构中,上传图片需要前端页面摆一个控件,然后后端提供一个 api用来接收前端传来的文件,通常来说这个后端 api 接收到图片之后,会将图片文件保存到自己的文件服务器或者是阿里云存储、或者是七牛云存储之类的。然后返回给你一个文件链接地址。非常麻烦,然而,小程序云开发上传文件超级简单,上代码:

页面代码:
<van-notice-bar
  scrollable="false"
  text="发布商品"
/>
  <van-field
    value="{{ productName }}"
    required
    clearable
    label="商品名称"
    placeholder="请输入商品名称"
    bind:change="inputName"
  />
    <van-field
    value="{{ productPrice }}"
    required
    clearable
    label="价格"
    icon="question-o"
     bind:click-icon="onClickPhoneIcon"
    placeholder="请输入价格"
    error-message="{{phoneerr}}"
    border="{{ false }}"
    bind:change="inputPrice"
  />

<van-action-sheet
  required
  show="{{ showSelect }}"
  actions="{{ actions }}"
  close-on-click-overlay="true"
  bind:close="toggleSelect"
  bind:select="onSelect" cancel-text="取消"
/>
  <van-field
    value="{{ productCategory }}"
    center
    readonly
    label="商品分类"
    border="{{ false }}"
    use-button-slot
  >
    <van-button slot="button" size="small" plain type="primary"  
     bind:click="toggleSelect">选择分类</van-button>
  </van-field>
  
  <van-button class="rightside" type="default" bind:click="uploadImage" >上传商品图片</van-button>
  <view class="imagePreview">
    <image src="{{productImg}}" />
  </view>
 <van-submit-bar
  price="{{ totalShow }}"
  button-text="提交"
  bind:submit="onSubmit"
  tip="{{ false }}"
 >
 </van-submit-bar> 
<van-toast id="van-toast" />
<van-dialog id="van-dialog" />
           

这里有个控件,绑定了

uploadImage

方法,其代码为:

uploadImage:function(){
    let that = this;
    wx.chooseImage({
      count: 1,
      sizeType: ['compressed'],
      sourceType: ['album', 'camera'],
      success(res) {
        wx.showLoading({
          title: '上传中...',
        })
        const tempFilePath = res.tempFilePaths[0]
        const name = Math.random() * 1000000;
        const cloudPath = name + tempFilePath.match(/\.[^.]+?$/)[0]
        wx.cloud.uploadFile({
          cloudPath:cloudPath,//云存储图片名字
          filePath: tempFilePath,//临时路径
          success: res => {
            let fileID = res.fileID;
            that.setData({
              productImg: res.fileID,
            });
            wx.showToast({
              title: '图片上传成功',
            })
          },
          fail: e =>{
            wx.showToast({
              title: '上传失败',
            })
          },
          complete:()=>{
            wx.hideLoading();
          }
        });
      }
    })
  }
           

这里,

wx.chooseImage

用于调起手机选择图片(相册/相机拍照),然后

wx.cloud.uploadFile

用于上传图片到上面说到的云开发能力之一的“存储”中。上传图片成功之后返回一个文件 ID,类似:

cloud://release-0kj63.7265-release-0kj63-1300431985/100477.13363146288.jpg	
           

这个链接可以直接在小程序页面展示:

<image src="cloud://release-0kj63.7265-release-0kj63-1300431985/100477.13363146288.jpg	" />
           

也可以通过微信 api,装换成 http 形式的图片链接。

云开发之——操作数据库,1 分钟写完保存商品到数据库的代码

上面我们实现了商品图片上传,但是,商品图片并没有保存到数据库。正常录入商品的时候,我们会填好商品名称,价格等,然后上传图片,最终点击“保存”按钮,将商品保存到数据库。传统模式下,前端仍然是需要调用一个后端接口,通过 post 提交数据,最终由后端服务(比如 java 服务)将数据保存到数据库。小程序云开发使得操作数据库十分简单,首先我们在云开发控制台创建“商品表”,即一个

collection

,取名为:

products

。然后我们就可以保存数据到数据库了,代码如下:

onSubmit:function(){
    // 校验代码,略
    let product = {};
    product.imgId = this.data.productImg;
    product.name= this.data.productName;
    product.categoryId = this.data.productCategoryId;
    product.price = this.data.productPrice;
    // 其他赋值,略
    const db = wx.cloud.database();
    db.collection('products').add({
     data: product,
     success(res) {
       wx.showToast({
         title: '保存成功',
       })
     }
   });
  }
           

以上就实现了数据入库,就这点代码,超简单,1 分钟写完,诚不欺我。其中这里的

products

就是我们的“商品表”,之前说过,类似 MongoDB 数据库,这里操作的是

db.collection

,这和 MongoDB 的语法差不多。

云开发之——使用云函数完成后端业务逻辑,订单创建

小程序云开发提供了几大能力:“数据库”,“存储”,“云函数”,前两项我们已经有所体会了。下面我们能创建一个云函数来实现订单创建。这里说明,云函数其实就是 一段JavaScript 代码,上传至云服务器之后,最终也是运行在 nodejs 环境的,只是这一切,我们不需要关心。我们只需要关心我们这个云函数提供的功能是什么就可以了。

创建云函数很简单,直接在开发工具中右键“新建Node.js 云函数”。然后以创建订单为例,假设我们创建一个云函数名为

c-order-add

,创建好了之后,目录是这样:

小程序云开发:菜鸟也能全栈做产品

云函数的主要代码在 index.js 中,其完整代码是这样:

// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init({
  env: 'release-xxx'// your-env-id
})
const db = cloud.database()

// 云函数入口函数
exports.main = async (event, context) => {
  const wxContext = cloud.getWXContext();
  console.log("云函数 c-order-add : ")  
  // 这里是一些逻辑处理...
  
  return await db.collection('uorder').add({
    data: {
      openid: event.userInfo.openId,
      address: event.address,
      userName: event.userName,
      phone: event.phone,
      shoppingInfo: event.shoppingInfo,
      totlePrice: event.totlePrice,
      shoppingStr: event.shoppingStr,
      remark:event.remark,
      createTime: now,
      // ...
    }
  });
}
           

这个云函数写好之后,需要上传到服务器,直接在云函数目录点击右键,然后点击“上传并部署”即可,这就相当于部署好了后端服务。前端小程序页面调用的写法是这样的:

let orderData={};
orderData.userName = this.data.userName;
orderData.phone = this.data.phone;
orderData.address = this.data.address;
// ....
wx.cloud.callFunction({
      // 云函数名称
      name: 'c-order-add',
      // 传给云函数的参数
      data: orderData,
      complete: res => {
        Dialog.alert({
          title: '提交成功',
          message: '您的订单成功,即将配送,请保持手机通畅。'
        }).then(() => {
          // ....
          wx.redirectTo({
            url: '../uorder/uorder'
          });
        });
      }
})
           

这里,向程序前端,通过

wx.cloud.callFunction

完成了对云函数的调用,也可以理解为对后端服务的调用。至此我们我们介绍完了,小程序云开发的功能。虽然,我只贴出了少量的代码,即保存商品,和提交订单。由于时间和篇幅有限,我不可能把整个完整的程序代码贴出来。但是你可以参照这个用法示例,将剩下的业务逻辑补充完整,最终完成“项目构思”一节中展示的成品截图效果。

小程序审核的一点经验

我开发的小程序审核在提交审核的时候遭遇了两次退回,第一次是因为:“小程序具备电商性质,个人小程序号不支持”。所以,我只好申请了一个企业小程序号,使用的是超市的营业执照。服务类目的选择也被打回了一次,最后选择了食品还提交了食品经营许可证。第二次打回是因为:“用户体验问题”。其实就是“授权索取”的问题,微信不让打开首页就“要求授权”,同时不能强制用户接受授权,得提供拒绝授权也能使用部分功能。

上面两条解决之后,更新新了好几版,都没有出现过被拒的情况。并且,有次我是夜晚 10 左右提价的审核,结果10 点多就提示审核通过,当时没看具体时间,就是接盆水泡了个脚的时间审核通过了。所以,我推断小程序审核初次审核会比较严,之后如果改动不大应该直接机审就过了。

总结及对比

这里我们可以对小程序云开发和传统模式做一个对比:

对比条目 传统模式 云开发
是否需要后端服务 需要 (如一个java应用部署在 Tomcat 中) 不需要 只需要“云函数”
是否需要域名 需要 (还得在微信后台的把域名加入安全域名) 不需要
是否需要购买服务器 需要 (你得部署后端 Java 应用,还得安装数据库)

不需要

开通云开发之后免费套餐够用

不够的话购买套餐按调用量计费

是否需要懂运维

需要

(你得会折腾服务器,数据库之类的

还得配置好相关的用户,端口,启动服务)

图片上传及 CDN 麻烦 简单
获取微信 openID 超级简单,云函数中直接获取
···

就对比这么多吧,总之,我非常喜欢小程序云开发,小程序真的可以让你轻松干全栈。或者咱们别动不动就提“全栈”,姑且说,小程序云开发可以让你更简单、更快速、更便宜的实现你的产品落地。我自己开发的云小程序上线之后,使用了一两个月,没出现任何问题。我也不用操心服务器什么的。所以,我已经给身边很多人安利了小程序云开发了。这里我就不贴出我的小程序码了,因为已经正式给我同学的超市使用了,所以不方便让别人去产生测试数据。如果你感兴趣想看的话,可以联系我。邮件[email protected]

Docker & k8s 系列一:快速上手docker

Docker & k8s 系列二:本机k8s环境搭建

Docker & k8s 系列三:在k8s中部署单个服务实例

小程序云开发:菜鸟也能全栈做产品

感谢您的阅读,欢迎您评论交流。PS:博客园已停更,后续请通过邮件或者公众号联系