當(dāng)前位置:首頁(yè) > IT技術(shù) > 微信平臺(tái) > 正文

高考查分小程序開(kāi)發(fā)心得
2021-07-22 17:51:24

?

?

?

明天就是一年一度的高考了,今年的高考報(bào)名人數(shù)達(dá)到了 1031w?的新高,作為一名三年前參考高考的準(zhǔn)程序猿,趕在高考前,加班加點(diǎn)從零開(kāi)始做了一款高考查分小程序,算是一名老學(xué)長(zhǎng)送給學(xué)弟學(xué)妹們的高考禮。關(guān)于小程序的介紹,可以參考我上一篇文章,今天主要談?wù)劶夹g(shù)原理和實(shí)現(xiàn)細(xì)節(jié)。

?

高考查分小程序開(kāi)發(fā)心得_學(xué)習(xí)

數(shù)據(jù)來(lái)源

?

小程序后臺(tái)共收錄近 30w 條數(shù)據(jù),包含 2008-2017 年所有重點(diǎn)高校的各個(gè)批次的文理分科錄取分?jǐn)?shù)線以及 2008-2018 所有采用新課標(biāo)一卷、新課標(biāo)二卷、新課標(biāo)三卷以及部分自主命題省份的從提前批到高職專科批的錄取分?jǐn)?shù)線,勉強(qiáng)稱得上內(nèi)容翔實(shí)。

高考查分小程序開(kāi)發(fā)心得_學(xué)習(xí)_02

所有數(shù)據(jù)均采集自各大院校和各高考相關(guān)網(wǎng)站,由于數(shù)據(jù)量巨大,為提高速度,使用了 concurrent.futures (需要 Python3.5+) 模塊里的 ThreadPoolExecutor 來(lái)構(gòu)建線程池來(lái)并發(fā)執(zhí)行多任務(wù)。

數(shù)據(jù)庫(kù)采用的是 PgSQL,一款號(hào)稱世界上最強(qiáng)大的開(kāi)源數(shù)據(jù)庫(kù)產(chǎn)品,所有數(shù)據(jù)均存在新建的 gaokao 數(shù)據(jù)庫(kù)中,其下有兩個(gè)表,university (院校的錄取分)和 province (省份的批次線)

?

university 表說(shuō)明

?

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

?

province 表說(shuō)明

?

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

?

30w 的數(shù)據(jù)量,多個(gè)站點(diǎn),并發(fā)爬取,數(shù)據(jù)沖突是不可避免地,在執(zhí)行插入之前,首先過(guò)濾掉殘缺不全的數(shù)據(jù),比如在插入 university 表時(shí)某條數(shù)據(jù)缺少 pc 字段,那么這條記錄就應(yīng)該被舍棄,最嚴(yán)重的是數(shù)據(jù)重復(fù),我采用的解決辦法是:先查詢待插入的數(shù)據(jù)是否已經(jīng)存在, university 表的主碼是(name,stu,stu_wl,pc,year),因?yàn)楝F(xiàn)實(shí)約束一個(gè)院校只能在一個(gè)年份在一個(gè)類別一個(gè)批次只能有一個(gè)錄取平均分,如果不存在,才執(zhí)行最后的插入,并 commit 提交事務(wù)。

?

后臺(tái)搭建

?

在 30w ?條數(shù)據(jù)拿到后,我打算后臺(tái)采用 Flask+PgSQL 的模式實(shí)現(xiàn),甚至在后臺(tái)在阿里云服務(wù)器部署好,小程序端在開(kāi)發(fā)者工具聯(lián)調(diào)通過(guò)之后,小程序上線遇到到一個(gè)大麻煩,因?yàn)樾〕绦蛞缶€上運(yùn)行不能通過(guò) ip 地址訪問(wèn)后臺(tái),必須通過(guò)備案的域名訪問(wèn),域名購(gòu)買一個(gè)倒不麻煩,只是域名備案比較耗時(shí)間,需要一周多時(shí)間,而當(dāng)時(shí)距離高考也就不到 5 天,在手足無(wú)措之時(shí),無(wú)意間看到小程序云開(kāi)發(fā),關(guān)于小程序云開(kāi)發(fā),官網(wǎng)的介紹是:

?

開(kāi)發(fā)者可以使用云開(kāi)發(fā)開(kāi)發(fā)微信小程序、小游戲,無(wú)需搭建服務(wù)器,即可使用云端能力。

云開(kāi)發(fā)為開(kāi)發(fā)者提供完整的原生云端支持和微信服務(wù)支持,弱化后端和運(yùn)維概念,無(wú)需搭建服務(wù)器,使用平臺(tái)提供的 API 進(jìn)行核心業(yè)務(wù)開(kāi)發(fā),即可實(shí)現(xiàn)快速上線和迭代,同時(shí)這一能力,同開(kāi)發(fā)者已經(jīng)使用的云服務(wù)相互兼容,并不互斥。

?

也就是說(shuō),只要把數(shù)據(jù)導(dǎo)入小程序自帶的后臺(tái),就能通過(guò)小程序平臺(tái)的 API 訪問(wèn)到這些數(shù)據(jù),以前了解過(guò)第三方的 LeanCloud 云 和 Bomb 云,沒(méi)想到小程序現(xiàn)在集成了這些功能,不得不佩服一下騰訊。

也就是,接下來(lái)的后臺(tái)的工作是主要是導(dǎo)入數(shù)據(jù),查詢小程序后臺(tái)可知,后臺(tái)支持導(dǎo)入 json 或者 csv 格式的數(shù)據(jù)。于是我就寫了個(gè)腳本,把數(shù)據(jù)從本地?cái)?shù)據(jù)庫(kù)導(dǎo)出到 json 文件中:

?

import?psycopg2
import?json

#?連接?pgsql?數(shù)據(jù)庫(kù),為保證隱私,密碼已隱藏
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?格式的縮進(jìn)
#?ensure_ascii?控制中文的正常顯示
with?open("province.json",?'w',?encoding="utf-8")?as?f:
????f.write(json.dumps(result,?indent=2,?ensure_ascii=False))

?

這里還有個(gè)坑需要說(shuō)明一下,小程序后臺(tái)要求的 json 格式和我們平常意義上的 json 格式還有點(diǎn)區(qū)別,首先,json 的所有內(nèi)容不能被 [ 和 ] 包括起來(lái),而且每個(gè)被 {} 所包括得數(shù)據(jù)項(xiàng)之間不能有逗號(hào)。

?

高考查分小程序開(kāi)發(fā)心得_學(xué)習(xí)_03

?

選用 notepad++ 打開(kāi)原來(lái)的 json 文件,使用替換功能就能解決,把 [ 和 ] 替換成空格,把 },替換成 } 即可。

修改之后,在小程序后臺(tái)通過(guò)導(dǎo)入該 json 文件,后臺(tái)搭建就基本完成了。

?

小程序端編寫

?

關(guān)于小程序端的編寫,我主要談?wù)剝牲c(diǎn)經(jīng)驗(yàn),第一是頁(yè)面的編寫,比如下面這個(gè)界面。

?

高考查分小程序開(kāi)發(fā)心得_學(xué)習(xí)_04

?

3

最開(kāi)始想實(shí)現(xiàn)這樣的效果,完全沒(méi)有思路,最后在從自定義模態(tài)彈窗那得到了思路,一開(kāi)始地區(qū)院校這個(gè)下拉框?qū)?yīng)的布局是隱藏的,在 wxml 文件中通過(guò) hidden=true 控制,一點(diǎn)擊 地區(qū)/院校 下拉框,就把 hidden 置為 false,如果開(kāi)始有其他下拉框?qū)?yīng)的布局的 hidden 屬性是 false 的話,同時(shí)要把這些布局的 hidden 屬性置為 true 來(lái)隱藏其他布局,當(dāng)然,這里的 true or false 需要在 js 文件里通過(guò) setData() 動(dòng)態(tài)修改,把修改后的數(shù)據(jù)從數(shù)據(jù)層渲染到視圖層。

?

第二是關(guān)于小程序云開(kāi)發(fā)的原生 Bug,查詢后臺(tái)時(shí)一次只能最多只能查詢到 20 條數(shù)據(jù),要實(shí)現(xiàn)一次得到所有匹配的結(jié)果,需要解決兩個(gè)問(wèn)題,第一個(gè)問(wèn)題很自然而然就能想到,第一次查到 20 條數(shù)據(jù)后,第二次跳過(guò)前 20 條再取 20 條,第三次跳過(guò)前 40 條再取 20 條,以此類推;還有一個(gè)更為致命的問(wèn)題,查詢后臺(tái)的 API 獲取結(jié)果的回調(diào)函數(shù)的 異步 的,也就是說(shuō),為了保證獲得完整數(shù)據(jù),第二次查詢需要寫在第一次查詢的回調(diào)里,第三次查詢需要寫在第二次查詢的回調(diào)里,而且你還不能顯式地知道要查詢多少次,需要寫多少層這樣的嵌套,以及煩人的同名變量覆蓋問(wèn)題,這就是所謂的 異步地獄。為了解決這個(gè)問(wèn)題,需要我們編寫代碼把這個(gè)異步方法轉(zhuǎn)成同步的,具體做法是:

?

先在所要添加功能的js頁(yè)面中導(dǎo)入 runtime.js 文件,同時(shí)把runtime.js文件放入相應(yīng)文件夾

?

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

?

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

?

同時(shí)模仿下例代碼完成業(yè)務(wù)邏輯:

?

//?查詢可能較慢,最好加入加載動(dòng)畫(huà)
wx.showLoading({
??????????title:?'加載中',
????????})
????????const?countResult?=?await?db.collection('province').where({
??????????stu_loc:?name,
??????????pc:?pici,

????????}).count()
????????const?total?=?countResult.total
????????//計(jì)算需分幾次取
????????const?batchTimes?=?Math.ceil(total?/?MAX_LIMIT)
????????//?承載所有讀操作的?promise?的數(shù)組
????????//初次循環(huán)獲取云端數(shù)據(jù)庫(kù)的分次數(shù)的promise數(shù)組
????????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()
??????????//二次循環(huán)根據(jù)獲取的promise數(shù)組的數(shù)據(jù)長(zhǎng)度獲取全部數(shù)據(jù)push到newResult數(shù)組中
??????????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
??????????})
????????}
????????//?隱藏加載動(dòng)畫(huà)
????????wx.hideLoading()

?

以上就是我本次開(kāi)發(fā)的一些心得體會(huì),歡迎批評(píng)指正。

?

點(diǎn)擊可快速查詢往年高考分?jǐn)?shù)線

?

?

?

本文摘自 :https://blog.51cto.com/u

開(kāi)通會(huì)員,享受整站包年服務(wù)立即開(kāi)通 >