小程序在2017年1月上线之初,被社会极力吹捧,刻意去将其制造为一个“风口”,透支其价值。可是在以后一个月里,石破天惊迅速归为沉寂。媒体又开始过分消费小程序,大谈其鸡肋之处。css
我的认为小程序的一个分水岭是在12月28日。微信升级到6.6.1版本,将小程序入口移植主界面,下拉主界面便可选择进入,而且支持新类目“小游戏”。小程序逐渐升温,在整个微信生态中扮演愈来愈重要的角色。时至今日,小程序的风潮如日中天,优秀的小程序很容易获得融资。这到底是是另外一轮泡沫,仍是小程序自己真正已经进入了成熟期?我我的更相信后者。html
我我的作过两款小程序,对小程序有必定认识,但理解仍是比较浅的。今天就仅从如何快速搭建一个小程序谈起,揭开小程序的一丝神秘面纱。前端
wxml
+wxss
+json
+js
,我认为本质仍是html
+css
+js
。Java
,Python
,PHP
,Ruby
等等,在这篇文章里我选用Python
的Flask
框架+Gunicorn
+Nginx
来快速搭建。MySQL
,nosql数据库我选择Redis
。固然,你的小程序能够很轻量级,甚至不须要使用到数据库。小程序一大思想“用完即走”。https
域名来进行映射。如今市面上也有一些第三方快速生成小程序的工具,和之前那些快速生成网站的是同一门生意。我我的并不推荐去使用那些,由于那些小程序几乎千篇一概,没法结合你本身的创意,没法定制你须要提供的服务,并且一定存在一些收费。python
固然,这些平台既然存在,那么一定是市场需求,假如确实适合你,能为你带来一些效益,不妨一试。mysql
今天,咱们是以学习者的角度去构建小程序。nginx
ubuntu
com
域名,¥50/年。http
到https
。如今不少SSL证书能够免费申请,下面会详细说下如何配置。咱们的目标是实现一个简单的小程序,可以实现先后端对接。web
Nginx
。Nginx
在同一路径下)Nginx
的配置文件,如图配置(证书路径填写本身的)如今,打开你的小程序开发工具,并使用你的APPID新建一个项目。(我这里没有多余的APPID,因此先使用测试环境)sql
能够先勾选“创建普通快速启动模板”来生成一个官方测试demo,以下图:数据库
让咱们来观察一下目录结构。app.js
,app.json
,app.wxss
分别对应全局的方法,全局配置参数和全局样式。而在具体包下的index.js
,index.wxml
,index.wxss
则对应相应的元素。json
如今让咱们来写一点简单的页面的代码。
<!-- index.wxml -->
<view class="main-card"> <view class="main-card-item" id="toast" wx:if="{{news_flag}}"> <view class="card-item-hd" > <image class="card-item-icon" src="/images/index/toast.png"></image> <text class="card-item-name">大事儿</text> </view> <view class='toast'> Hello,欢迎观看此教程,但愿对你有帮助。 </view> </view> </view>
/* index.wxss */
page {
background-color: #f8f8f8; } .main-card { padding-bottom: 100rpx; } .main-card-item{ display: flex; flex-direction: column; background: #fff; border-top: 1rpx solid #F6F6EF; border-bottom: 1rpx solid #F6F6EF; margin-bottom: 20rpx; background-repeat: no-repeat; background-size: 100% auto; background-position: bottom center; overflow: hidden; margin-left: 12rpx; margin-right: 12rpx; border-radius: 15rpx; } .card-item-hd{ display: flex; align-items: center; height: 75rpx; border-bottom: 1rpx solid #e5e5e5; margin-left: 30rpx; } .card-item-icon{ width: 40rpx; height: 40rpx; margin-right: 10rpx; } .card-item-name{ letter-spacing: 1px; font-size: 25rpx; } .toast{ letter-spacing:3rpx; line-height: 50rpx; font-size: 28rpx; margin-left: 20rpx; margin-top: 20rpx; margin-bottom: 40rpx; }
此时,一个简单的页面已经生成了,让咱们来看看效果。
很简单,可是能够看出来「大事儿」里的内容是写死的,此时咱们须要后端来提供数据。
###服务器环境
在编写后端以前,咱们先把服务器的环境部署一下。
apt-get install python-dev
pip install flask
pip install uwsgi
apt-get install nginx
pip install gunicorn
首先在你的/var/www/
目录下建立一个测试目录,好比/var/www# mkdir test
而后使用chmod
更改此目录的权限chmod 777 /var/www/test
这里讲一下chmod
的规则,由于这里是测试用例,因此为了方便,直接使用777。
Ubuntu下的Nginx的目录结构大体以下:
/etc/nginx
下,每一个虚拟主机已经安排在了/etc/nginx/sites-available
目录下/usr/sbin/nginx
/var/log/nginx
中,分别是access.log
和error.log
/etc/init.d/
下建立了启动脚本nginx/usr/share/nginx/www
启动服务:/etc/init.d/nginx start
,重启服务:/etc/init.d/nginx restart
如今,咱们须要进入到Nginx的配置中,改动配置文件。vim /etc/nginx/site-avalidable/default
更改配置文件后重启服务/etc/init.d/nginx restart
,或者service nginx restart
Gunicorn 绿色独角兽 是一个Python WSGI UNIX的HTTP服务器。这是一个pre-fork worker的模型,从Ruby的独角兽(Unicorn )项目移植。该Gunicorn服务器大体与各类Web框架兼容,只需很是简单的执行,轻量级的资源消耗,以及至关迅速。
此时须要在“准备”步骤中建立的测试目录下放入咱们的测试运行项目,我选择的FTP工具是:xftp。我传入了一个简单的用来测试的Python文件wsgi.py
,使用命令/var/www/myflask# vim wsgi.py
预览。
此时在测试目录下键入命令gunicorn -w 4 -b 127.0.0.1:8000 wsgi:app
运行。
此时,访问服务器,能够看到“Hello World”已经能够正常显示了。
后端咱们采用Python
的Flask
框架+Gunicorn
+Nginx
来快速搭建。首先须要一些Python
的基础知识,相信你们在菜鸟学Python学了这么久,这彻底不是问题。如今,让咱们了解一下Flask
如何使用。
一位使用多种语言开发复杂程序而且拥有十多年经验的软件工程师,曾经用 PHP, Ruby, Smalltalk 甚至 C++ 写过 web 应用,他认为,在全部这些中,Python/Flask 组合是最为自由的一种。
在使用了Flask
以后,我也不得不认可,它确实很便捷快速。固然也会有必定的缺点,这是后话。
回归正题。
from flask import Flask
app = Flask(__name__)
@app.route('/') def hello_world(): return 'Hello World' if __name__ == '__main__': app.run()
这是一个最简单的Demo。
执行流程为:从flask模块获取对象app,经过路由,执行方法,返回内容。
此时在浏览器访问(默认端口5000):127.0.0.1:5000/ ,能够看到国际惯例Helloworld的界面。
@app.route('/hello') @app.route('/hello/') #这两种须要区分 # @app.route('/hello/') #在使用这种尾部带斜线的url时,假如用户没有输入尾部/,也将访问到正确的页面 # @app.route('/hello') #在使用这种尾部不带斜线的url时,假如用户在尾部输入了/,将返回404
这个规则彷佛有点拗口,但其实也不能理解。优势是:
若是实在记不清,最好的方法是破罐子破摔:统一不带尾部“/”
@app.route('/var/<name>') def var(name): return 'hello'+' '+name
这点就不赘述了,能够看一下演示效果:
大部分时候,在用户访问了一个URL的时候,咱们都须要给他/她返回一个界面,咱们固然不会用Python自己去渲染HTML,为此,Flask 配备了Jinja2 模板引擎。
看完如下代码示例,相信你就能理解。
首先,咱们建立“templates”文件夹用于保存模板。
Flask 会在 templates 文件夹里寻找模板。因此,若是你的应用是个模块,这个文件夹应该与模块同级;若是它是一个包,那么这个文件夹做为包的子目录:
#状况 1: 模块: /application.py /templates /hello.html #状况 2: 包: /application /__init__.py /templates /hello.html
@app.route('/redi/') def redi(): return render_template('hello.html')
@app.route('/redi2/<name>') def redi2(name): return render_template('hello2.html',name=name)
请求方式不止这个两种,可是最经常使用的是这两种,若是对这两种不熟悉,能够先去查一下HTTP方法的资料,这里只演示在flask中的用法。
@app.route('/met',methods=['GET','POST']) def met(): if request.method=='GET': return '这是get方法' if request.method=='POST': return '这是post方法'
打开Postman这款软件(Web神器),模拟发送HTTP请求。
下面我来模拟一个简单的登陆操做。
首先是控制器:
@app.route('/login',methods=['POST','GET']) def login(): error=None if request.method=='POST': print (request.form['username']+' '+request.form['password']) if func.login_func.valid_login(request.form['username'], request.form['password']): return func.login_func.login_success(request.form['username']) else: error='Invalid username/password' return render_template('login_error.html',error=error)
能够看到执行流程:
下面是上述用到的两个方法:
def valid_login(username,password):
if username=='admin' and password=='admin': return True
def login_success(username):
return render_template('login_success.html',username=username)
下面使用Postman来模拟请求,看看能不能返回设想的结果。
这是一些简单的Flask
操做,好了,咱们如今对web有了必定的了解了。如今开始编写咱们的代码。
###后端 万事俱备,只欠东风。 首先咱们来写两个路由,一个用于更新通知,一个用于获取通知。
@app.route("/updateToast",methods=['POST']) @allow_cross_domain def update_toast(): data=db_util.update_toast(request.form['toastUpdateInfo']) return jsonify(data) @app.route("/getToast",methods=['GET']) @allow_cross_domain def get_toast(): data = db_util.get_toast_info() return jsonify(data)
而后写一个工具类,用于直接操做数据库(这种设计并不规范,只是为了快速演示)
#db_util.py def get_toast_info(): db = pymysql.Connect( host='xxx', port=3306, user='xxx', passwd='xxx', db='xxx', charset='utf8' ) cursor = db.cursor() sql = "select content from guohe_lite_toast order by id desc limit 1 " try: cursor.execute(sql) result = cursor.fetchone() return response_info.success('小程序通知查询成功', result) except: return response_info.error('2', '小程序通知查询失败', result) # 关闭数据库链接 finally: db.close() def update_toast(toast_update_info): db = pymysql.Connect( host='xxx', port=3306, user='xxxx', passwd='xxx', db='xxxx', charset='utf8' ) cursor = db.cursor() sql = "insert into guohe_lite_toast(content,update_time) values(%s,%s) " try: dt = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") cursor.execute(sql,(toast_update_info,dt)) db.commit() return response_info.success('通知更新成功', toast_update_info) except: db.rollback() return response_info.error("2",'更新失败', toast_update_info) finally: db.close()
如今,让咱们使用postman来测试一下接口。
首先更新一下通知:
而后看能不能成功获取:
这一切都生效了,数据接口已经准备就绪。
那么,如今如何在小程序端获取数据并显示呢?咱们去简要读下小程序的官方文档。
请注意,小程序是纯异步方式来发送请求的。
依葫芦画瓢,咱们来模仿一下:
#index.js wx.request({ url: 'https://example.com/getToast', method: 'GET', header: { 'content-type': 'application/x-www-form-urlencoded' // 默认值 }, success: function (res) { var message = res.data.info[0] console.log(message) that.setData({ toast: message }) } })
咱们将获取的数据已经保存在"toast"这个变量中了,再去读文档,看看小程序是如何进行数据绑定的。而后咱们将以前写死的文本换成"{{toast}}",这时再刷新,能够看到,数据已经显示了。
<!-- index.wxml -->
<view class="main-card"> <view class="main-card-item" id="toast" wx:if="{{news_flag}}"> <view class="card-item-hd" > <image class="card-item-icon" src="/images/index/toast.png"></image> <text class="card-item-name">大事儿</text> </view> <view class='toast'> {{toast}} </view> </view> </view>
此时,一套完整的流程已经结束,虽然实现了一个微小的功能,但麻雀虽小,五脏俱全。接下来,就是去进一步学习,去如何改造以及丰富咱们的项目了。
好比稍微努力一下: