ushidayの日記

主に「IBMi」のメモに・・・

GData APIでGoogleスプレッドシートを使う

静岡Developers勉強会(SZD)で、Haskellの読書会をしている事は、何度かお伝えしているのですが、申し込みフォームに”Google Docsスプレッドシート”を使用しています。
このスプレッドシートは、何処でも使えて、運営委員との共有、フォーム作成、結果の集計と非常に便利なのですが、登録する側からすると、特に受付返信メールなどがあるわけではないので、(メールアドレスの2重登録はして頂いていますが、チェック機能もないので余計に)「ちゃんと申し込めているか?入力項目が間違っていないか?」などが、不安になります。特に勉強会は、会場の関係上20名という人数制限を設けているので、参加者からすると余計にそうだと思います。
とは言うものの、そのままのスプレッドシートを公開する訳にもいきません。そこで”GData API”(Googleサービス用に用意されたAPI)を使って、勉強会の登録状況と、定員の確認ができる照会を作成してみました。
公開するアプリケーションサーバーも持ってないので、GAE(ずーっと使ってなかった...)上にデプロイしました。”GData API”はJava版なので、久々にさわれて嬉しい:-)”Groovy”を使います。(あまりGroovyっぽさは無いですが...)そして軽量ツールキットの”Gaelyk”を使いました。(BigTable使ってないから勿体無いかも。)

GData API/Javaの入手

Downloads - gdata-java-client - Project Hosting on Google Codeから、GData APIを入手します。
スプレッドシートの操作に必要なライブラリーは、以下の通り。

    • gdata-core-1.0.jar
    • gdata-client-meta-1.0.jar
    • gdata-client-1.0.jar
    • gdata-spreadsheet-meta-3.0.jar
    • gdata-spreadsheet-3.0.jar
    • google-collect-1.0-rc1.jar
    • jsr305.jar
Gaelykの入手&主な使い方

Gaelykの入手と主な使い方については、id:kskyさんがこちらで非常に解りやすく日本語訳をされているので、そちらを参考にする事ができます。日本語が苦手な人はこっち

GData APIの使い方

Gaelykのテンプレートを入手したら、「パス/war/WEB-INF/lib」に前述の必要な、GData APIのjarをコピーします。
使い方は、参考サイトの@ITで、細かく解説してくれています。
今回作成したソースは以下の通りです。
■list.groovy

import com.google.gdata.client.spreadsheet.FeedURLFactory
import com.google.gdata.client.spreadsheet.ListQuery
import com.google.gdata.client.spreadsheet.SpreadsheetQuery
import com.google.gdata.client.spreadsheet.SpreadsheetService
import com.google.gdata.data.spreadsheet.CustomElementCollection
import com.google.gdata.data.spreadsheet.ListEntry
import com.google.gdata.data.spreadsheet.ListFeed
import com.google.gdata.data.spreadsheet.SpreadsheetEntry
import com.google.gdata.data.spreadsheet.SpreadsheetFeed
import com.google.gdata.data.spreadsheet.WorksheetEntry

// このアプリケーションの名称。任意の名前を設定
String applicationName = "shizu-dev.org-SpreadsheetSearch"

// Google AppsもしくはGoogleアカウントのメールアドレスとパスワードを設定
String username = "xxxxxxx@gmail.com"
String password = "*********"

// Spreadsheetsサービスへの認証を行う
SpreadsheetService service = new SpreadsheetService(applicationName)
service.setUserCredentials(username, password)

//スプレッドシート名
sheetName = "スプレッドシート名"

// 検索対象のスプレッドシートを取得
FeedURLFactory urlFactory = FeedURLFactory.getDefault()
SpreadsheetQuery spreadsheetQuery = new SpreadsheetQuery(urlFactory.getSpreadsheetsFeedUrl())
spreadsheetQuery.setTitleQuery(sheetName) // 検索対象のスプレッドシート名を指定している
SpreadsheetFeed spreadsheetFeed = service.query(spreadsheetQuery,SpreadsheetFeed.class)
SpreadsheetEntry spreadsheetEntry = spreadsheetFeed.getEntries().get(0) //sheet index

// 検索対象のワークシートを取得
WorksheetEntry worksheetEntry = spreadsheetEntry.getDefaultWorksheet()

// ワークシート内を検索
ListQuery listQuery = new ListQuery(worksheetEntry.getListFeedUrl())
//データ抽出やソートの場合
//listQuery.setSpreadsheetQuery("性別 = 男")
ListFeed listFeed = service.query(listQuery, ListFeed.class)


def listEntries = listFeed.getEntries()
int rowCount = listEntries.size()

def list = []
listEntries.eachWithIndex { listEntry,i->
	CustomElementCollection elements = listEntry.getCustomElements()
    def row = [:]
	row.no = i + 1
	row.name = elements.getValue("名前又はハンドル名")
	row.timestamp = elements.getValue("タイムスタンプ")
	row.banquet = elements.getValue("懇親会に参加されますか")
	row.student = elements.getValue("学生ですか")
	row.minor = elements.getValue("未成年ですか")
	row.cancel = elements.getValue("キャンセル待希望")?:"なし"
	list << row
}

def sheet = [:]

sheet.title = sheetName
sheet.list = list
sheet.maxCount = 20
sheet.currentCount= rowCount

request.setAttribute 'sheet', sheet
forward '/list.gtpl'

認証には、GmailGoogle Appsのアカウントを使います。スプレッドシートの名前を指定して、取得しますので、アカウント内でシート名がユニークである必要があります。
シートの抽出やソートは、ListQueryクラスの”setSpreadsheetQuery”メッソドを使用する事が出来ます。
あと未解決ですが、CustomElementCollectionクラスの”getValue”メソッドで、スプレッドシートの列名に”?”(自分の場合は最後に?、途中の?は未検証です。)が、使われていると、正しく結果を取る事が出来ませんでした。

ローカルで実行するには、「dev_appserver war」。GEAにデプロイするには「appcfg update war」。たったこれだけ。流石にローカルに比べると、GAE上のそれはレスポンスこそ悪いですが、それはGData APIを使っているから仕方がない事かと思います。
それにしても、GroovyとGaelykを使うと、あっという間に、GAE上にデプロイ出来てしまう。これスゴイとオモウ。
折角GAE使うなら、今度はBigTableを使った事がしたいです。

ちなみに出来たのは、こんな感じです。