基于小程序·云开发构建高考查分小程序丨实战

2019高考报名人数达到了 1031 万的新高,作为一名三年前参考高考的准程序猿,赶在高考前,加班加点从零开始做了一款高考查分小程序,算是一名老学长送给学弟学妹们的高考礼。上线仅 1 个月,用户数就突破了 1k,关于小程序的介绍就不多说了,可以去搜【历年高考分数线查询】体验,今天主要谈谈技术原理和实现细节。

1649686-20190906174340371-468013304.png

数据来源

小程序后台共收录近 30w 条数据,包含 2008-2017 年所有重点高校的各个批次的文理分科录取分数线以及 2008-2018 所有采用新课标一卷、新课标二卷、新课标三卷以及部分自主命题省份的从提前批到高职专科批的录取分数线,勉强称得上内容翔实。

1649686-20190906160923390-1588666080.png

所有数据均采集自各大院校和各高考相关网站,由于数据量巨大,为提高速度,使用了 concurrent.futures (需要 Python3.5+) 模块里的 ThreadPoolExecutor 来构建线程池来并发执行多任务。

数据库采用的是 PgSQL,一款号称世界上最强大的开源数据库产品,所有数据均存在新建的 gaokao 数据库中,其下有两个表,university(院校的录取分)和 province(省份的批次线)

university 表说明

字段解释
name院校名称
stu_loc生源地
stu_wl文理科
pc录取批次
year年份
score录取平均分

province 表说明

字段解释
year年份
stu_loc考生所在地
stu_wl文理科
pc批次
control本批次最低控制线

30w 的数据量,多个站点,并发爬取,数据冲突是不可避免地,在执行插入之前,首先过滤掉残缺不全的数据,比如在插入 university 表时某条数据缺少 pc 字段,那么这条记录就应该被舍弃,最严重的是数据重复,我采用的解决办法是:先查询待插入的数据是否已经存在, university 表的主码是(name,stu,stu_wl,pc,year),因为现实约束一个院校只能在一个年份在一个类别一个批次只能有一个录取平均分,如果不存在,才执行最后的插入,并 commit 提交事务。

后台搭建

在 30w 条数据拿到后,我打算后台采用 Flask+PgSQL 的模式实现,甚至在后台在阿里云服务器部署好,小程序端在开发者工具联调通过之后,小程序上线遇到到一个大麻烦,因为小程序要求线上运行不能通过 ip 地址访问后台,必须通过备案的域名访问,域名购买一个倒不麻烦,只是域名备案比较耗时间,需要一周多时间,而当时距离高考也就不到 5 天,在手足无措之时,无意间看到小程序云开发,关于小程序云开发,官网的介绍是:

开发者可以使用云开发开发微信小程序、小游戏,无需搭建服务器,即可使用云端能力。

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

也就是说,只要把数据导入小程序自带的后台,就能通过小程序平台的 API 访问到这些数据,以前了解过第三方的 LeanCloud云 和 Bomb 云,没想到小程序现在集成了这些功能,不得不佩服一下腾讯。

也就是,接下来的后台的工作是主要是导入数据,查询小程序后台可知,后台支持导入 json 或者 csv 格式的数据。于是我就写了个脚本,把数据从本地数据库导出到 json 文件中:

import psycopg2
import json# 连接 pgsql 数据库,为保证隐私,密码已隐藏
conn = psycopg2.connect(database="gaokao", user="postgres", password="*******", host="127.0.0.1", port="5432")
cur = conn.cursor()cur.execute('select stu_loc,year,stu_wl,pc,control from province')
result = []
query_res = cur.fetchall()
for i in query_res:item = {}item['stu_loc'] = i[0]item['year'] = i[1]item['wl'] = i[2]item['pc'] = i[3]item['score'] = i[4]result.append(item)
# indent=2 控制 json 格式的缩进
# ensure_ascii 控制中文的正常显示
with open("province.json", 'w', encoding="utf-8") as f:f.write(json.dumps(result, indent=2, ensure_ascii=False))

这里还有有个坑需要说明一下,小程序后台要求的 json 格式和我们平常意义上的 json 格式还有点区别,首先,json 的所有内容不能被 [ 和 ] 包括起来,而且每个被 {} 所包括得数据项之间不能有逗号。

1649686-20190906160939367-2069438937.png

选用 notepad++ 打开原来的 json 文件,使用替换功能就能解决,把 [ 和 ] 替换成空格,把 },替换成 } 即可。

修改之后,在小程序后台通过导入该 json 文件,后台搭建就基本完成了。

小程序端编写

关于小程序端的编写,我主要谈谈两点经验,第一是页面的编写,比如下面这个界面。

1649686-20190906161006404-1121165425.jpg

最开始想实现这样的效果,完全没有思路,最后在从自定义模态弹窗那得到了思路,一开始地区院校这个下拉框对应的布局是隐藏的,在 wxml 文件中通过 hidden=true 控制,一点击 地区/院校 下拉框,就把 hidden 置为 false,如果开始有其他下拉框对应的布局的 hidden 属性是 false 的话,同时要把这些布局的 hidden 属性置为 true 来隐藏其他布局,当然,这里的 true or false 需要在 js 里通过 setData() 动态修改,把修改后的数据从数据层渲染到视图层。

第二是关于小程序云开发的原生 Bug,查询后台时一次只能最多查询到 20 条数据,要实现一次得到所有匹配的结果,需要解决两个问题,第一个问题很自然而然就能想到,第一次查到 20 条数据后,第二次跳过前 20 条再取 20 条,第三次跳过前 40 条再取 20 条,以此类推;还有一个更为致命的问题,查询后台的 API 获取结果的回调函数的 异步 的,也就是说,为了保证获得完整数据,第二次查询需要写在第一次查询的回调里,第三次查询需要写在第二次查询的回调里,而且你还不能显式地知道要查询多少次,需要写多少层这样的嵌套,以及烦人的同名变量覆盖问题,这就是所谓的 异步地狱。为了解决这个问题,需要我们编写代码把这个异步方法转成同步的,具体做法是:

先在所要添加功能的js页面中导入 runtime.js 文件,同时把runtime.js文件放入相应文件夹

const regeneratorRuntime = require("../runtime");

runtime.js 下载地址:https://github.com/inspurer/CampusPunchcard/blob/master/runtime.js

同时模仿下例代码完成业务逻辑:

// 查询可能较慢,最好加入加载动画​
wx.showLoading({title: '加载中',})const countResult = await db.collection('province').where({stu_loc: name,pc: pici,}).count()const total = countResult.total//计算需分几次取const batchTimes = Math.ceil(total / MAX_LIMIT)// 承载所有读操作的 promise 的数组//初次循环获取云端数据库的分次数的promise数组for (let i = 0; i < batchTimes; i++) {const promise = await db.collection('province').where({stu_loc: name,pc: pici,}).skip(i * MAX_LIMIT).limit(MAX_LIMIT).get()//二次循环根据​获取的promise数组的数据长度获取全部数据push到newResult数组中for (let j = 0; j < promise.data.length; j++) {var item = {};item.code = i * MAX_LIMIT + j;item.name = promise.data[j].stu_loc;item.year = promise.data[j].year;item.wl = promise.data[j].wl;item.pc = promise.data[j].pc;item.score = promise.data[j].score;console.table(promise.data)newResult.push(item)}}if (newResult.length != 0) {that.setData({hasdataFlag: true,resultData: newResult})} else {that.setData({hasdataFlag: false,resultData: newResult})}// 隐藏加载动画wx.hideLoading()

以上就是我本次开发的一些心得体会,欢迎批评指正。

课程完整源码

https://github.com/TencentCloudBase/Good-practice-tutorial-recommended

联系我们

更多云开发使用技巧及 Serverless 行业动态,扫码关注我们~

1649686-20190906161107408-1323716179.png

转载于:https://www.cnblogs.com/CloudBase/p/11475427.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/423486.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

浅谈 DML、DDL、DCL的区别

一、DML DML&#xff08;data manipulation language&#xff09;数据操纵语言&#xff1a;就是我们最经常用到的 SELECT、UPDATE、INSERT、DELETE。 主要用来对数据库的数据进行一些操作。 SELECT 列名称 FROM 表名称 UPDATE 表名称 SET 列名称 新值 WHERE 列名称 某值 IN…

前端学习(3):vs code编辑器

下载地址 https://code.visualstudio.com 下载安装教程 变成中文 在编辑器中运行我们的网页 open in browser view in browser 选中文件----首选项----设置 常用快捷键

QuickPart应用系列

在上一篇解决方案包部署与收回篇章中&#xff0c;我只是稍微提了下QuickPart.也许刚接触这块内容的朋友&#xff0c;可能还不是很清楚&#xff0c;QuickPart具体的功能能实现什么。首先要告诉你的是QuickPart的人性化之处&#xff0c;那就是给开发人员开发webpart提供更简洁的方…

spring----IOC知识点

//可以修改Bean定义的属性(不是修改Bean) Component public class TulingBeanFactoryProcessor implements BeanFactoryPostProcessor {Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {beanFactory.getBean…

Hive分析窗口函数(五) GROUPING SETS,GROUPING__ID,CUBE,ROLLUP

GROUPING SETS 该关键字可以实现同一数据集的多重group by操作。事实上GROUPING SETS是多个GROUP BY进行UNION ALL操作的简单表达&#xff0c;它仅仅使用一个stage完成这些操作。GROUPING SETS的子句中如果包含()数据集&#xff0c;则表示整体聚合。 Aggregate Query with GRO…

前端学习(4):chome浏览器

一、认识浏览器 浏览器是网页显示、运行的平台&#xff0c;常用的浏览器有IE、火狐&#xff08;Firefox&#xff09;、谷歌&#xff08;Chrome&#xff09;、Safari和Opera等。我们平时称为五大浏览器。IE最新版为Edge。 常用浏览器 二、浏览器市场份额 可以通过百度的统计网…

JS的IE和Firefox兼容性总结

JS的IE和Firefox兼容性汇编(原作:hotman_x) 以下以 IE 代替 Internet Explorer&#xff0c;以 MF 代替 Mozzila Firefox 1. document.form.item 问题 (1)现有问题&#xff1a; 现有代码中存在许多 document.formName.item(&q…

spring----注解

以后想到了在写 1、DependsOn("xx") User bean被创建之前&#xff0c;先创建xx bean; DependsOn("xx") public class User{private int id; }转载于:https://www.cnblogs.com/yanxiaoge/p/11479628.html

Hive分析窗口函数 NTILE,ROW_NUMBER,RANK,DENSE_RANK

本文中介绍前几个序列函数&#xff0c;NTILE,ROW_NUMBER,RANK,DENSE_RANK&#xff0c;下面会一一解释各自的用途。Hive版本为 apache-hive-0.13.1 数据准备&#xff1a; cookie1,2015-04-10,1cookie1,2015-04-11,5cookie1,2015-04-12,7cookie1,2015-04-13,3cookie1,2015-04-14,…

前端学习(5):深入了解网站开发

要了解web前后端的区别&#xff0c;首先必须得清楚什么是web前端和web后端。 首先&#xff1a;web的本意是蜘蛛网和网的意思&#xff0c;在网页设计中我们称为网页的意思。现广泛译作网络、互联网等技术领域。表现为三种形式&#xff0c;即超文本(hypertext)、超媒体(hypermed…

实战 IE8 开发人员工具

今天整理我收藏的漫画的时候发现 风云3 少了两集&#xff08;486、487&#xff09;&#xff0c;这对于收藏者来说基本是不可忍受的&#xff1b; 从风云一到三&#xff0c;应该一集也不能少的&#xff1b; 决定上网去找找&#xff0c;不过溜达一圈常去的分享论坛&#xff0c;由于…

spring----Bean的生命周期和循环依赖

循环依赖&#xff1a; A类引用了B&#xff0c;B类引用了A&#xff0c;像这种循环着依赖就是循环依赖&#xff1b; 对于这种配置不会报错 <bean id"instanceA" class"com.zy.entities.InstanceA"><property name"instanceB" ref"in…

SQL count和case when配合统计给定条件下不重复的记录数

Iamlaosong文 1、我们知道&#xff0c;SQL语句中用count函数统计记录数量&#xff0c;配合distinct关键字可以统计非重复的记录数量。例如&#xff1a; select count(*), count(city_name), count(distinct city_name) from tb_county 查询结果是&#xff1a; 2534 2534 …

前端学习(6):javascript简介

我们需要思考以下六个问题&#xff1a; 1、javaScript是什么&#xff1f; 2、javaScript的用途是什么&#xff1f; 3、javaScript和ECMAScript的关系是什么&#xff1f; 4、javaScript由哪几部分组成&#xff1f; 5、javaScript的执行原理是怎样的&#xff1f; 6、在页面…

提高系统性能

1.Cache缓存 对象有生命周期&#xff0c;有容量限制&#xff0c;适合保存有状态属性的对象。 有状态的session bean运行在EJB容器的Cache中 2.Pool池 对象池&#xff0c;实现对象的大量并行访问 无状态的session bean运行在EJB容器的Pool中。转载于:https://www.cnblogs.com/cx…

2019 徐州icpc网络赛 E. XKC's basketball team

题库链接&#xff1a; https://nanti.jisuanke.com/t/41387 题目大意 给定n个数&#xff0c;与一个数m&#xff0c;求ai右边最后一个至少比ai大m的数与这个数之间有多少个数 思路 对于每一个数&#xff0c;利用二分的方法求他右边大于等于aim的数的最后一个值。 关键在于怎么二…

Hive中COUNT的高级用法(条件过滤等)

在HIVE中&#xff0c;除了COUNT(*)外&#xff0c;COUNT还可以有很多高级用法。 SELECTtype, count(*), count(DISTINCT u), count(CASE WHEN plat1 THEN u ELSE NULL END), count(DISTINCT CASE WHEN plat1 THEN u ELSE NULL END), count(CASE WHEN (type2 OR type6) THEN u E…

前端学习(7):web的三大技术

HTML(5) 是一门标记型语言&#xff0c;主要由一些具备特殊含义的标签构成&#xff08;建筑物结构&#xff09; 所谓HTML是“超文本标记语言”的英文缩写。我们上网所看到网页&#xff0c;多数都是由HTML写成的。“超文本”是指页面内可以包含图片、链接&#xff0c;甚至音乐、…

SQL 关键字

Table B-1 列出了所由在 SQL 标准和 PostgreSQL 7.2 里是关键字的记号&#xff0e; 你可以在 Section 1.1.1 里找到 相关的背景信息&#xff0e; SQL 里有保留字(保留)和 非保留字之分&#xff0e;根据标准&#xff0c; 保留字是那些真正的关键字&#xff1b;我们决不能用它们…

scala的foreach和for

一句印象深刻的话&#xff0c;Alan Kay&#xff08;Smalltalk发明者&#xff09;说得一句话&#xff1a;“I’m not against types, but I dont know of any typesystems that arent a complete pain, so I still like dynamic typing”。 并不是静态类型不好&#xff0c;只是静…