本來要趕在跨年前發布這篇文章,當作是2015年的Ending之作
結果因為關帳一忙,就delay到今天
就當作開年的第一篇文章吧
緣起於年前有網友來信詢問,如果要將學生成績輸入在 Google Spreadsheet 讓學生可以透過網頁查詢成績,當下覺得這是個很有趣的Topic也應該是很好的應用
於是一開始先建立了一個
成績試算表,想說撰寫一個查詢函數,將資料轉成JSON格式回傳即可,但是將試算表部署成網路應用程式之後,一直告訴我找不到 doGet 函數,後來參考
這一篇講解,發現是搞錯方向了
應該是要新增一個Apps Script專案,再從專案中去開啟Spreadsheet
首先,先新增一個Google Apps Script專案
將無標題專案及 myFunction 修改為 學生成績查詢 以及 doGet
同時新增兩個 html,Index & qryResult (檔案 | 新增 | HTML檔) 當作前端介面的 Template
doGet指的就是前端查詢時會觸發的 event (即 http 的 Get)
在這裡我們透過內建的 HtmlService 將設計好的 HTML 範本丟回給查詢的前端
在這裡的設計,是當前端觸發 Apps Script 時,我們會回應一個輸入學號與驗證碼的頁面
在 Index.html 中 (檔案 | 新增 | HTML 檔案),我們設計輸入學號與驗證碼的欄位,供前端輸入
在 Form Action 的地方,可以看到有一個類似ASP輸出變數值的寫法
< form action="< ?= serviceUrl ? >" class="login-form" method="post" role="qryForm" >
< div class="form-group">
< label class="sr-only" for="id" >學號< /label >
< input class="form-username form-control" id="form-username" name="id" placeholder="學號..." type="text" / >
< /div>
< div class="form-group">
< label class="sr-only" for="authCode">驗證碼
< input class="form-password form-control" id="form-password" name="authCode" placeholder="驗證碼..." type="password" / >
< /div>
< button class="btn" type="submit" >查詢< /button >
< /form>
對應到 doGet 函數中,就可以明瞭這中間的運作方式,我們在Template中指定的變數,可以在doGet中透過 evaluate()的方式將變數值輸出到前端頁面
function doGet(e){
var tmpl = HtmlService.createTemplateFromFile('Index');
tmpl.serviceUrl = ScriptApp.getService().getUrl();
return tmpl.evaluate();
}
同時,在 Index.html中,我們採用了Form submit的方式將資料回傳到後端,所以相對應的也必須要有 doPost 來承接前端的POST
function doPost(e){
var id=e.parameter.id;
var authCode=e.parameter.authCode;
return qryScores(id,authCode);
}
前端傳進來的Form data可以透過 e.parameter.xx 的方式來擷取,這樣我們就可以得到前端的輸入值,並交給 qryScores 來處理我們要得到的結果(可以把 qryScores 當作是 Model)
這邊要特別注意的是,Spreadsheet是被拿來當作資料儲存的地方,Apps Script只是一連串的指令碼,我們仍然需要 create 一個 Spreadsheet 的 Instance 來對檔案進行操作,而我們的Spreadsheet 與 Apps Script 都是在雲端,所以必須要以 openByUrl 的方式來開啟 Spreadsheet 檔
設定方式,在 Google Drive 找到該檔案,按右鍵取得連結,同時須做共用的設定 (進入共用設定後選進階),如果是要公開給別人使用,權限要注意一下,不然會一直被要求取得開啟檔案權限的
function qryScores(id,authCode) {
var iRow=3;
var isAuthenticated=false;
var sheetApp = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/1lIUUdZximIlLNM6UXjCAeKeqYJTHtIXBFq9iLEuap1c/edit#gid=0');
var sheetScore = sheetApp.getSheetByName('學期成績');
var sheetStudent=sheetApp.getSheetByName('學生帳號');
// check id & authCode
Logger.log('Verify id & authCode...');
while (sheetStudent.getRange(iRow-1, 1).getValue()!=''){
Logger.log(sheetStudent.getRange(iRow-1, 1).getValue());
if (sheetStudent.getRange(iRow-1, 1).getValue()==id && sheetStudent.getRange(iRow-1, 2).getValue()==authCode){
isAuthenticated=true;
break;
}
iRow++;
}
if (!isAuthenticated){
return HtmlService.createHtmlOutput('認證錯誤!');
}else{
var tmpl = HtmlService.createTemplateFromFile('qryResult');
tmpl.Student_ID = sheetScore.getRange(iRow, 1).getValue();
tmpl.Student_Name = sheetScore.getRange(iRow, 2).getValue();
tmpl.Chn_1st = sheetScore.getRange(iRow, 3).getValue();
tmpl.Eng_1st = sheetScore.getRange(iRow, 4).getValue();
tmpl.Math_1st = sheetScore.getRange(iRow, 5).getValue();
tmpl.Chn_2nd = sheetScore.getRange(iRow, 6).getValue();
tmpl.Eng_2nd = sheetScore.getRange(iRow, 7).getValue();
tmpl.Math_2nd = sheetScore.getRange(iRow, 8).getValue();
tmpl.Chn_3rd = sheetScore.getRange(iRow, 9).getValue();
tmpl.Eng_3rd = sheetScore.getRange(iRow, 10).getValue();
tmpl.Math_3rd = sheetScore.getRange(iRow, 11).getValue();
tmpl.Chn_quiz = sheetScore.getRange(iRow, 12).getValue();
tmpl.Eng_quiz = sheetScore.getRange(iRow, 13).getValue();
tmpl.Math_quiz = sheetScore.getRange(iRow, 14).getValue();
tmpl.Chn_sum = sheetScore.getRange(iRow, 15).getValue();
tmpl.Eng_sum = sheetScore.getRange(iRow, 16).getValue();
tmpl.Math_sum = sheetScore.getRange(iRow, 17).getValue();
tmpl.Chn_avg = sheetScore.getRange(iRow, 18).getValue();
tmpl.Eng_avg = sheetScore.getRange(iRow, 19).getValue();
tmpl.Math_avg = sheetScore.getRange(iRow, 20).getValue();
tmpl.total_sum = sheetScore.getRange(iRow, 21).getValue();
tmpl.total_avg = sheetScore.getRange(iRow, 22).getValue();
tmpl.rank = sheetScore.getRange(iRow, 23).getValue();
return tmpl.evaluate();
}
}
回到程式,在
成績試算表 中,有兩個 Sheet,一個用來登錄成績,一個用來驗證學號的驗證碼,這邊用比較陽春的方式來設計,主要是做一個示範,並不鼓勵採用這種做法
當驗證通過時,將頁面導向 qryResult.html 這個 Template,一樣透過 evaluate() 將對應的變數值輸出到前端,結果如下:
順帶一提,當欄位很多時,如果要從 Spreadsheet 快速產生 html 格式,可以先將 Spreadsheet 用網頁的方式下載下來 (檔案 | 下載格式 | 網頁(.zip) ),將內容整理一下貼到 template 中
最後,也是最重要的部分,就是要將 Google Apps Script 這個專案發佈到網路上成為應用程式
將應用程式執行為的方式,如果設定為 "我" ,網路上的使用者打開連結時,會被要求取得執行權限的(會發送 email 通知你自己)
因為趕時間,所以就沒有往當初設想的方向去測試,除了用繞檔案的方式來做查詢,網路上也有實作用下 SQL來查詢的方式(就像是透過 ODBC 來查詢 Excel 檔)
這一次的實作,倒也讓自己收穫不少,像學到了可以把 Apps Script 當作是 MVC 的平台,.gs 當作是 Controller/Model,doGet/doPost 可以當作 Routing Rule,搭配 View Template 來與前端互動,倒是還蠻方便的 :)
測試網址:
https://script.google.com/macros/s/AKfycbwj3VxM_jpQ2514VYk0B47Wkes9hMq_am96LPZik9TK/dev
帳號:10105
密碼:MoGu7b