1. 程式人生 > >flask + sqlite3 + android 構建RESTful API實現個人資訊查詢系統 (上(伺服器端))

flask + sqlite3 + android 構建RESTful API實現個人資訊查詢系統 (上(伺服器端))


手裡有一些資料,原來是xls格式的,需要查詢一些資訊的時候用ecxel很不方便,所以便想做一套查詢系統,最好是Andriod的,隨時隨地就可以查詢,說幹就幹。

一、伺服器端

1.1

以前沒有接觸過後端,只做過安卓和前端,在問了其他人和上網搜尋比較之後,有以下幾種方案:

1.webservice

2.Java

3.Python的flask

考慮到伺服器的配置比較低(1核、1G、Ubuntu 14.04)以及需求很簡單(移動端請求查詢,伺服器端處理並向資料庫查詢後,通過JSON返回到移動端),遂決定採用flask

至於資料庫,由於資料比較少,只有幾千條,所以採用了sqlite3。

最終服務端要求實現的效果是:提供一套API,移動端訪問提供的API地址,伺服器將資料通過JSON返回。

1.2 設計一個簡單的API

一般情況,一個編號唯一對應一個人,所以只需要請求編號就可以。但有些時候僅知道姓名,這時候需要提供通過姓名查詢的方法。 API如下:
HTTP方法 URI 動作
GET http://[hostname]/[id] 返回資訊
GET http://[hostname]/[name] 返回資訊

1.3 初步瞭解flask

flask是一個知名的Python框架,可以快速的開發web應用,他的安裝和部署也十分快捷。 先安裝virtualenv虛擬環境,virtualenv是開發Python必備的,提供Python虛擬環境,可以理解為一個沙箱,防止不同專案之間互相沖突。 使用xshell連線到伺服器
,執行以下程式碼:
$ sudo apt-get install python-virtualenv
安裝成功之後,建立一個相關環境
$ virtualenv flaskapp
這裡virtualenv建立了一個資料夾,flaskapp/,並且設定了一個純淨的python拷貝,同時安裝了包管理器pip。 進入新建立的開發環境並激活:(注意第二行period與bin之間有一個空格)
$ cd flaskapp
$ . bin/activate
接下來就可以安全地安裝Flask了:
$ pip install Flask
接下來,建立我們的第一個flask應用,看一下flask是否安裝成功
$ vi hello.py
在hello.py中寫下如下程式碼:
from flask import Flask, jsonify

app = Flask(__name__)

@app.route('/', methods=['GET'])    # '/' 這一部分表示訪問的URL
def home():   <span style="white-space:pre">			</span>    # def xxx() 表示對應響應的操作
  return "Hello,World"

if __name__ == '__main__':
  app.run(debug=True)
儲存後,執行
$ python hello.py
訪問本地IP,埠5000. 看到如下頁面: [這裡應該有張圖] 這樣,我們的flask就架設成功了。 在這裡可能會有一個小問題,在伺服器上架設flask,可能有的朋友會在本地機器上直接訪問伺服器IP,結果卻發現無法開啟。此時,只需要將最後一句程式碼改為
app.run(host='0.0.0.0') 
這樣,就可以被任意IP訪問了。

1.4 安裝Sqlite3資料庫

依然連線伺服器,執行  $ sudo apt-get install sqlite sqlite3 接下來建立資料庫  $ sqlite3 test.db 對於sqlite3的操作,為了方便起見,我們使用WinSCP將其下載到本地,在本地對其進行操作 在這裡推薦一個Win下操作sqlite3資料庫的小工具 sqlitestudio 在使用過程中可能會報錯,不過不用理會就好。 在本地建表,匯入資料。

1.4.2 將EXCEL表格轉入到資料庫中

上千條資料,雖然不多,但是將其手動輸入到資料庫中似乎是一個不可能完成的任務。幸好sqlitestudio提供了轉換功能。
但是需要將xls檔案轉換成csv之後才可匯入,這裡又有一個問題: xls檔案轉換成csv檔案之後,對於長資料項,比如身份證號一類,會造成精度損失。即使將所有單元格設定成“文字”也無濟於事。 解決辦法:先建立一個空白的csv檔案,將所有單元格設定為“文字”格式,然後將原xls檔案資料貼上到新建的csv檔案中。 這樣就可以保留資料。 建表過程不再贅述。

1.5 編寫服務端程式碼

在flask中使用sqlite3,需要新增如下程式碼:
def connect_db():
    return sqlite3.connect('test.db')

@app.before_request
def before_request():
    g.db = connect_db()

@app.teardown_request
def teardown_request(exception):
    if hasattr(g, 'db'):
        g.db.close()
之後利用遊標來查詢資料 程式碼如下:
cursor = sqlite3.connect('test.db').cursor()

cursor.execute(這裡嵌入sql語句)

result = cursor.fetchall()
cursor.close()
sqlite3.connect('test.db').close()
這樣,資料庫查詢的資料就儲存到了result中 result[0]代表查詢到的第一條記錄 result[0][0]代表查詢到的第一條記錄的第一個值 前面我們提到,在flask中  @app.route('/xxx', methods=['GET']) def xxx() :     # 執行程式碼 表示對http://[hostname]/xxx 進行響應,並執行xxx()函式。為了實現我們設計的API,所以我們為其新增響應編號的程式碼,並和之前的查詢程式碼綜合起來,程式碼如下:
@app.route('/<int:user_id>', methods=['GET'])
def query(user_id):
	cursor = sqlite3.connect('test.db').cursor()

	# #query
	sql = "select name,stu_id,sex,mz,cla_id,place,ro_id,do_id,date,school,address from myer where stu_id = "+ str(user_id)  <span style="white-space:pre">				</span>#這裡通過字串的方式達到在sql語句中插入變數的目的。
	cursor.execute(sql)
	result = cursor.fetchall()
	print "query has been ok"
	print sql
	cursor.close()
	sqlite3.connect('test.db').close()
	return jsonify(
		{
			'user_id': user_id,
			'name': result[0][0],
			'stu_id': result[0][1],
			'sex': result[0][2],
			'mz': result[0][3],
			'cla_id': result[0][4],
			'place': result[0][5],
			'ro_id': result[0][6],
			'do_id': result[0][7],
			'date': result[0][8],
			'address': result[0][9]
		})
(通過flask的jsonify實現對資料的JSON化) 接下來實現用名字來查詢,方法大同小異,就不再贅述了。 值得注意的是,為了防止查詢中文引起的編碼錯誤,需要在hello.py的開頭加入如下程式碼:
import sys
reload(sys)
sys.setdefaultencoding( "utf-8" )
同時,在查詢的sql語句中,中文的兩端需要加上雙引號 sql = "select name,stu_id,sex,mz,cla_id,place,ro_id,do_id,date,school,address from myer where name = "+"\""+user_name+"\""
注意引號個數。

1.6 完整程式碼

到這裡,伺服器端就算是開發完成了。完整程式碼如下:
import sys
reload(sys)
sys.setdefaultencoding( "utf-8" )
import sqlite3
from flask import g
from flask import Flask, jsonify

app = Flask(__name__)

def connect_db():
    return sqlite3.connect('test.db')

@app.before_request
def before_request():
    g.db = connect_db()

@app.teardown_request
def teardown_request(exception):
    if hasattr(g, 'db'):
        g.db.close()

@app.route('/<int:user_id>', methods=['GET'])
def query(user_id):
	cursor = sqlite3.connect('test.db').cursor()

	# #query
	sql = "select name,stu_id,sex,mz,cla_id,place,ro_id,do_id,date,school,address from myer where stu_id = "+ str(user_id) 
	cursor.execute(sql)
	result = cursor.fetchall()
	print "query has been ok"
	print sql
	cursor.close()
	sqlite3.connect('test.db').close()
	return jsonify(
		{
			'user_id': user_id,
			'name': result[0][0],
			'stu_id': result[0][1],
			'sex': result[0][2],
			'mz': result[0][3],
			'cla_id': result[0][4],
			'place': result[0][5],
			'ro_id': result[0][6],
			'do_id': result[0][7],
			'date': result[0][8],
			'address': result[0][9]
		})

@app.route('/<user_name>', methods=['GET'])
def query_a(user_name):
	cursor = sqlite3.connect('test.db').cursor()

	# #query
	sql = "select name,stu_id,sex,mz,cla_id,place,ro_id,do_id,date,school,address from myer where name = "+ "\""+user_name+"\"" 
	cursor.execute(sql)
	result = cursor.fetchall()
	print "query has been ok"
	print sql
	cursor.close()
	sqlite3.connect('test.db').close()
	return jsonify(
		{
			'name': result[0][0],
			'stu_id': result[0][1],
			'sex': result[0][2],
			'mz': result[0][3],
			'cla_id': result[0][4],
			'place': result[0][5],
			'ro_id': result[0][6],
			'do_id': result[0][7],
			'date': result[0][8],
			'address': result[0][9]
		})

@app.route('/', methods=['GET'])
def home():
  return "11"

@app.route('/ok', methods=['GET'])
def ok():
  return "Hello,World"

@app.errorhandler(404)
def page_not_found(e):
    res = jsonify({'error': 'not found'})
    res.status_code = 404
    return res

if __name__ == '__main__':  
    app.run(host='0.0.0.0')