自己動手實現(xiàn)自動打包缴挖,上傳下載服務(wù)袋狞,前端展示

前段時間,獨自接手公司另一個項目組的App(該產(chǎn)品僅存的唯一的一個小伙伴離職了)映屋,本來心里很不情愿苟鸯。因為代碼實在是太古老了,而且經(jīng)過了n手的像我這樣的斷代接收棚点,長期處于半維護狀態(tài)早处,所以我都是一邊看代碼一邊吐槽。并不是說前面的小伙伴的技術(shù)不好瘫析,而是經(jīng)過多年多次流轉(zhuǎn)砌梆,每一代都風(fēng)格迥異就形成了現(xiàn)在這副冗余不堪的樣子默责。

我們自己的App是用當(dāng)前最流行的Jenkins+Git+Gradle持續(xù)集成,但這個App就慘了咸包,你不得不自己打包發(fā)到群里桃序,可想而知多少麻煩,就想著接入接入我們的Jenkins服務(wù)器烂瘫,自動打包媒熊。但是被權(quán)限問題折騰過后,而且這段時間大家都忙著一個超高優(yōu)先級的項目忱反,就先擱置了泛释。

前天就想著為什么不自己寫一套呢。反正有免費的服務(wù)器用温算,那就物盡其用怜校。

首先要實現(xiàn)的功能:
1,自動打包-Python實現(xiàn)
2注竿,文件上傳下載服務(wù)器-Python實現(xiàn)
3茄茁,包列表前端展示-HTML
4,包列表展示和下載移動端實現(xiàn)

經(jīng)過兩天的加班加點巩割,終于實現(xiàn)啦裙顽,先看效果:
移動端apk列表:


移動端

前端apk列表:


前端

后端文件服務(wù)核心代碼:

import os

from flask import request, jsonify
from flask import send_from_directory, abort
from flask_restful import Resource, reqparse
from werkzeug.utils import secure_filename

from modules.APKRecord import APKRecordModel
from support.CHelper import get_millisecond, get_file_name

basedir = os.path.abspath(os.path.dirname(__file__))
# set(['jpeg', 'apk'])
ALLOWED_EXTENSIONS = {'apk'}


# 用于判斷文件后綴
def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS


class APKRecord(Resource):
    @staticmethod
    def get():
        return {"You should have a file_name": 404}, 403

    # @staticmethod
    # def get(file_name):
    #     if os.path.isfile(os.path.join('uploadApk', file_name)):
    #         return send_from_directory('uploadApk', file_name, as_attachment=True)
    #     abort(404)

    @staticmethod
    def get(file_name):
        if os.path.isfile(os.path.join(r'D:\_pythonProj\CFlaskProj\resources\uploadApk', file_name)):
            return send_from_directory(r'D:\_pythonProj\CFlaskProj\resources\uploadApk', file_name, as_attachment=True)
        else:
            abort(404)


class APKRecordList(Resource):
    parser = reqparse.RequestParser()

    @staticmethod
    def get():
        file_dir = os.path.join(basedir, "uploadApk")
        if not os.path.exists(file_dir):
            os.makedirs(file_dir)

        apkList = []
        if os.path.exists(file_dir):
            for root, dirs, files in os.walk(file_dir):
                for file in files:
                    item = APKRecordModel(file)
                    apkList.append(item.json())

        return jsonify(result='success', data=apkList)

    def post(self):
        file_dir = os.path.join(basedir, "uploadApk")
        if not os.path.exists(file_dir):
            os.makedirs(file_dir)
        f = request.files['apk_name']  # 從表單的file字段獲取文件,apk_name為該表單的name值
        if f and allowed_file(f.filename):  # 判斷是否是允許上傳的文件類型
            fname = secure_filename(f.filename)
            ext = fname.rsplit('.', 1)[1]  # 獲取文件后綴
            name = get_file_name(fname)
            timestamp = get_millisecond()
            new_filename = name + '_' + str(timestamp) + '.' + ext  # 修改了上傳的文件名加上了 _時間戳
            f.save(os.path.join(file_dir, new_filename))  # 保存文件到uploadApk目錄
            return {"code": 0, "msg": "upload success", "fileName": new_filename, "fileTime": timestamp}, 201
        else:
            return {"code": 1001, "msg": "file not allowed"}

這里要注意的一點的是:不同的環(huán)境(比如Mac環(huán)境和Windows環(huán)境)宣谈,這個地址也要改變:
Mac環(huán)境下:

    @staticmethod
    def get(file_name):
        if os.path.isfile(os.path.join('uploadApk', file_name)):
            return send_from_directory('uploadApk', file_name, as_attachment=True)
        abort(404)

Windows環(huán)境下:

    @staticmethod
    def get(file_name):
        if os.path.isfile(os.path.join(r'D:\_pythonProj\CFlaskProj\resources\uploadApk', file_name)):
            return send_from_directory(r'D:\_pythonProj\CFlaskProj\resources\uploadApk', file_name, as_attachment=True)
        else:
            abort(404)

前端展示:還是用的最簡單jquery

<script>
  $.ajax({
    url: "/apk/records",
    dataType: 'json',
    success: function (res) {
      res.data.map(item => {
        let liNode = document.createElement("li");
        liNode.className = "my_record_list_li"

        let labelNode = document.createElement("label")
        labelNode.className = "my_record_list_label"
        let spanNode = document.createElement("span")
        spanNode.innerHTML = item.fileTime
        labelNode.append(spanNode)
        let delNode = document.createElement("a");
        delNode.className = "delete_record"
        delNode.href = item.downloadUrl
        delNode.innerHTML = "下載"
        labelNode.append(delNode)

        let aNode = document.createElement("a");
        aNode.className = "my_record_list_a"
        aNode.href = item.downloadUrl
        aNode.innerHTML = item.fileName

        liNode.append(aNode)
        liNode.append(labelNode)

        $("#record_list_container").append(liNode)
      })
      document.getElementById('record_num_value').innerHTML = "共" + res.data.length + "個包"
    }
  })

</script>

同樣實現(xiàn)了愈犹,通過網(wǎng)頁上傳代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>文件上傳</title>

</head>
<body>
<form id="form1" method="post" action="http://xx.xxxx.xxxx.xxxx:5000/apk/records" enctype="multipart/form-data">
    <div>
        <input id="file1" type="file" name="apk_name"/>
        <input type="submit">提交</input>
    </div>
</form>
</body>
</html>

當(dāng)然打包,上傳腳本核心代碼:


# 請求服務(wù)器
def request_url(url, params):
    cookies = cookielib.CookieJar()
    opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookies), MultipartPostHandler.MultipartPostHandler)
    try:
        print('request url:' + url)
        print('request params:' + str(params))
        response = opener.open(url, params)
        return response.read()
    except Exception as e:
        print(str(e))


# 上傳文件到服務(wù)器
def upload_file(url, apkpath):
    params = {'username': reinforce_username, 'password': reinforce_password, 'apk': open(apkpath, 'rb'),
              'tactics_id': reinforce_tactics_id}
    response = request_url(url, params)
    data = json.loads(response)
    return data

搞定這些東西還是有點成就感的漩怎,感覺應(yīng)該可以寫成gradle腳本嗦嗡,甚至生成gradle插件,這樣服務(wù)器就沒必要配置Python環(huán)境侥祭,稍后有時間寫成插件。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末宰睡,一起剝皮案震驚了整個濱河市舆吮,隨后出現(xiàn)的幾起案子锅论,更是在濱河造成了極大的恐慌访惜,老刑警劉巖椿疗,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異障陶,居然都是意外死亡,警方通過查閱死者的電腦和手機抱究,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鼓寺,“玉大人,你說我怎么就攤上這事妈候「颐遥” “怎么了啸胧?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長纺念。 經(jīng)常有香客問我,道長陷谱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任烟逊,我火速辦了婚禮踪栋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘夷都。我一直安慰自己,他們只是感情好囤官,可當(dāng)我...
    茶點故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著党饮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪刑顺。 梳的紋絲不亂的頭發(fā)上饲常,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天贝淤,我揣著相機與錄音,去河邊找鬼政供。 笑死,一個胖子當(dāng)著我的面吹牛布隔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播衅檀,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼计济!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起排苍,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎传藏,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體彤守,經(jīng)...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年具垫,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片筝蚕。...
    茶點故事閱讀 40,444評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖洲胖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情绿映,我是刑警寧澤,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布腐晾,位于F島的核電站丐一,受9級特大地震影響卸奉,放射性物質(zhì)發(fā)生泄漏钝诚。R本人自食惡果不足惜榄棵,卻給世界環(huán)境...
    茶點故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一疹鳄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瘪弓,春花似錦、人聲如沸腺怯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至晾虑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間帜篇,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工笙隙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人坎缭。 一個月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像凯亮,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子哄尔,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,455評論 2 359