AppsのスプレッドシートデータをApp Engineから読み取る
前回の第2回までで、Google AppsとApp Engine双方のセットアップが完了したので、今回はいよいよSpreadsheetのデータをApp Engineから読み取るプログラムサンプルを見ていきます。また読み取ったSpreadデータは画面上に表示して内容を確認してみます。
1. MS ExcelをGoogle Driveにアップロードする
1.1 ExcelシートをDriveにアップロードする
最初のステップとして、Excelに書き込まれた受注データをDrive上にアップロードします(図1)。アップロードされたExcelは自動的にSpread sheetに変換されます。またDrive上のSpreadsheetをExcelに自動変換してダウンロードすることもできます。
ExcelシートをGoogle Driveにアップロードするのは簡単です。図2の「↑」のマークをクリックしてFilesを選択するとファイル選択のダイアログが表示されるので、ファイル選択後「開く」をクリックすればアップロードされます。また、Folderを選択すればフォルダ内のファイルをまとめてアップロードすることもできます。
アップロードされたExcelシートはDrive上のフォルダで図4のようにxlsxサフィックスのまま表示されますが、これをSpreadsheetに変換します。
1.2 アップロードされたExcelをSpreadsheetに変換する
Spreadsheetに変換するには、アップロードされたファイルを右クリックして表示されるサブメニューから
Open with -> Google sheet を選択します(図5)。
選択によって、図6のように連載で使用するスプレッドシートが表示され、フォルダでの表示も図7のようになります。TITLEでマークが付いているサフィックスのないファイルがSpreadsheetです。
ここで、Excelシートで定義されたマクロ(VBA)は、Spreadsheetでは無効になりますが、関数定義は有効です。
例えば図8のExcelでは1行目の合計欄に「=sum(C2:F2)」が定義されていますが、この関数定義はアップロード後のSpreadsheetでも有効です。
2.Drive上のSpreadSheetをApp Engineから読み取り画面表示する
ここまでで、ExcelシートとSpreadsheetのアップロードおよびファイル変換についての説明は終わり、次に本連載メインテーマのApp EngineからのSpreadsheet読み取りについて入っていきます。
ただし、ここからはJavaやJavascriptを使用したプログラミングの内容になっていきますので、ある程度プログラミング経験があることを前提とした内容になっていきます。
ここで紹介するApp EngineからのSpreadsheet読み取りでは、参照画面のボタンクリックから起動されるサーブレットによってビーンズをインスタンス化し、その中のメソッドによって実行されます(図9)。読み取られたSpreadデータはブラウザに画面表示されますが、今回は簡易形式での画面表示を紹介し、次回の連載でスプレッドシート風のグリッド表示について紹介します。
2.1 デプロイメントディスクリプタ(web.xml)を記述する
リスト1 デプロイメントディスクリプタ(web.xml)
<?xml version="1.0" encoding="utf-8" standalone="no"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.5" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <servlet-name>spread</servlet-name> <servlet-class>com.google.gdata.SpreadServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>spread</servlet-name> <url-pattern>/spread</url-pattern> </servlet-mapping> : <welcome-file-list> <welcome-file>index.htm</welcome-file> </welcome-file-list> </web-app>
ブラウザからの表示リクエストはデプロイメントディスクリプタ(web.xml)の記述にしたがってサーブレットを呼び出します。この辺りは問題ないでしょう。
2.2 サーブレットを記述する
リスト2 サーブレット(SpreadServlet.java)
package com.google.gdata; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.http.*; import com.google.gdata.util.ServiceException; @SuppressWarnings("serial") public class SpreadServlet extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { resp.setContentType("text/plain"); resp.setContentType("text/html; charset=utf-8"); PrintWriter out = resp.getWriter(); String mode = req.getParameter("mode"); //呼び出すビーンズメソッドを指定 String sheet = req.getParameter("sheet"); //読み取るシート名を指定 SpreadBean ss = new SpreadBean(); //スプレッドシート処理のビーンズをインスタンス化 if (mode.equals("getspreadallshopym")) { //modeパラメータでビーンズメソッド指定 String rv = ss.getSpreadAllShopYm(sheet); //ワークシート一覧表示のビーンズメソッド呼び出し out.println(rv); } else if (mode.equals("getspreadshopym")) { String shop = req.getParameter("shop"); String rv = ss.getSpreadShopYm(sheet, shop); //ワークシート店舗別表示のビーンズメソッド呼び出し out.println(rv); } } }
呼び出されたサーブレットはmodeパラメータで指定された値によってビーンズメソッドを呼び出します。
2.3 ワークシート一覧表示のビーンズメソッドを記述する
ここで見ていくビーンズメソッドでは、ワークシートに書き込まれたデータを一覧表示するもので、Spreadsheetの検索表示では一般的なものです。
リスト3 ビーンズ(SpreadBean.java)
package com.google.gdata; import java.io.IOException; import java.net.URL; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.List; import com.google.appengine.api.datastore.DatastoreService; import com.google.appengine.api.datastore.DatastoreServiceFactory; import com.google.appengine.api.datastore.Entity; import com.google.appengine.api.datastore.EntityNotFoundException; import com.google.appengine.api.datastore.Key; import com.google.appengine.api.datastore.KeyFactory; import com.google.appengine.api.datastore.Query; import com.google.appengine.api.datastore.Query.Filter; import com.google.appengine.api.datastore.Query.FilterOperator; 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; import com.google.gdata.data.spreadsheet.WorksheetFeed; import com.google.gdata.util.AuthenticationException; import com.google.gdata.util.ServiceException; import com.google.appengine.api.datastore.Query.FilterPredicate; import com.google.appengine.api.datastore.PreparedQuery; public class SpreadBean { public String getSpreadAllShopYm(String sheet) { String appliName = "cyberspace-SpreadsheetSearch-1"; String user = "xxxxxxxxxxxxxxxxxxx"; String pass = "xxxxxxxxxxxxxxxxx"; try { /////////////////////////////////////////////////////// // [I] 認証処理 SpreadsheetService spreadsheetservice = new SpreadsheetService(appliName); spreadsheetservice.setUserCredentials(user, pass); /////////////////////////////////////////////////////// // [II] 検索対象のスプレッドシートを特定 FeedURLFactory feedurlfactory = FeedURLFactory.getDefault(); SpreadsheetQuery spreadsheetquery = new SpreadsheetQuery(feedurlfactory.getSpreadsheetsFeedUrl()); spreadsheetquery.setTitleQuery(sheet); SpreadsheetFeed spreadsheetfeed = spreadsheetservice.query(spreadsheetquery, SpreadsheetFeed.class); SpreadsheetEntry spreadsheetentry = spreadsheetfeed.getEntries().get(0); /////////////////////////////////////////////////////// // [III] 検索対象のワークシートを特定 WorksheetEntry worksheetentry = spreadsheetentry.getDefaultWorksheet(); /////////////////////////////////////////////////////// // [IV] クエリでワークシート内の検索 ListQuery listquery = new ListQuery(worksheetentry.getListFeedUrl()); ListFeed listfeed = spreadsheetservice.query(listquery, ListFeed.class); List<ListEntry> datalist = lisfFeed.getEntries(); /////////////////////////////////////////////////////// // [V] ワークシートデータをJSONフォーマットにする String rv = "{ \"wsdat\":["; for (Iterator<ListEntry> it = datalist.iterator(); it.hasNext();) { ListEntry listentry = (ListEntry) it.next(); rv += "{\"cdat\": \"" + listentry.getPlainTextContent() + "\"},"; } rv = rv.substring(0, rv.length() - 1) + "]}"; return rv; } catch (AuthenticationException e) { e.printStackTrace(); return "参照不成功 :" + e; } catch (IOException e) { e.printStackTrace(); return "参照不成功 :" + e; } catch (ServiceException e) { e.printStackTrace(); return "参照不成功 :" + e; } } : }
[I] 認証処理
String appliName = "cyberspace-SpreadsheetSearch-1"; String user = "xxxxxxxxxxxxxxxxxxx"; String pass = "xxxxxxxxxxxxxxxxx"; SpreadsheetService spreadsheetservice = new SpreadsheetService(appliName); //(1) spreadsheetservice.setUserCredentials(user, pass); //(2)
処理の最初はアプリケーション名の指定と、ユーザ名とパスワードによる認証処理です。
(1)アプリケーション名はSpreadsheetと接続する場合の識別用に使用されます。
(2)ユーザ名とパスワードによる認証はsetUserCredentialsメソッドで行いますが、Googleアカウントのメールアドレスとパスワードを使用します。 実システムでは画面からGoogleアカウントとパスワードを入力して、ユーザの認証を行うようにするのが良いでしょう。
[II] 検索対象のスプレッドシートを特定する
FeedURLFactory feedurlfactory = FeedURLFactory.getDefault(); (1) SpreadsheetQuery spreadsheetquery = new SpreadsheetQuery(feedurlfactory.getSpreadsheetsFeedUrl()); (2) spreadsheetquery.setTitleQuery(sheet); (3) SpreadsheetFeed spreadsheetfeed = spreadsheetservice.query(spreadsheetquery, SpreadsheetFeed.class); (4) SpreadsheetEntry spreadsheetentry = spreadsheetfeed.getEntries().get(0); (5)
(1)では、Spreadsheetsサーバで使用される フィードURLのデフォルトインスタンスを生成します。
フィード(Feed)には幾つかの意味がありますが、ここでは、Webサイトから受信可能なデータと考えれば良いでしょう。
(2)feedurlfactory.getSpreadsheetsFeedUrl() では認証によってアクセス可能なすべてのSpreadsheetに対するフィードを受け取ることができるURLを取得し、SpreadsheetQueryでは取得したフィードURLを引数にして、Spreadsheetを検索するためのqueryを生成します。
(3)生成されたqueryにスプレッドシート名(sheet)を引数にしたフルテキスト検索を構成します。
ここで注意が必要なのは、Drive上には同じ名前のSpreadsheetファイルを複数配置することができるということです。また、同じ名前のspreadsheetはDrive上のフォルダが同じでも違っていても、すべて(3)のフル検索の対象になります。
例えば、図10にはSalesフォルダ内にファイル名201304のシートが1つあり、図11にはtestフォルダ内に同じ201304のシートが2つありますが、これらはすべて検索の対象になります。
(4)では(3)で生成したspreadsheetqueryを引数にクエリを実行し、クエリ内容に一致するエントリを含んだフィードを取得します。
(5)spreadsheetfeed.getEntries() でフィード内のスプレッドシートエントリのリストを返しますが、上で見たように同じ名前のスプレッドシートを複数作成することもできるので、get(0) で1つのスプレッドシートを特定します。ただここで、複数の同じ名前のシートの内、どのシートがget(0)で選択されるのかが問題ですが、図10、図11の右端に表示されているLAST MODIFIED(最終更新日)が最も新しいシートが選択されます。つまりgetメソッドの引数は更新日の新しい方から、0,1,2…となっている訳です。
ただし、更新の度に選択されるシートが変わってしまうのでは正確な処理を行うことはできません。したがって、Drive上でのスプレッドシート名はすべて一意(unique)にしておくべきです。
[III] 検索対象のワークシートを特定する
WorksheetEntry worksheetentry = spreadsheetentry.getDefaultWorksheet(); (1)
ここまでの処理で、検索対象は1枚のスプレッドシートに特定されましたが、最後にワークシートの特定を行います。
Excelでは1つのシートファイルに、タブ設定によって複数の入力シートを保持できますが、Drive上のSpreadsheet でも同様に複数のワークシートを保持することができます。したがって、複数ワークシートから1つを特定することが必要になってきますが、これを行っているのが(1)です。getDefaultWorksheet() は複数のワークシートから一番上に表示されているシート(図12のSheet1)を選択して返します。
[IV] クエリでワークシートデータの検索
ここまでで、複数のSpreadsheetから、幾つかの処理を経て検索対象のワークシートを特定する処理を見てきましたが、これでようやくワークシートデータの検索ができるようになります。
ListQuery listQuery = new ListQuery(worksheetentry.getListFeedUrl()); (1) ListFeed listFeed = spreadsheetservice.query(listQuery, ListFeed.class); (2) List<ListEntry> dataList = listFeed.getEntries(); (3)
(1)worksheetentry.getListFeedUrl() でワークシートのリストフィードのURLを取得し、それを引数にした ListQuery の生成でワークシートに対する行ベースのクエリを構成します。
(2)ターゲットサービスへのクエリを実行し、クエリ結果に一致するリストフィード(listFeed)を返します。
(3)リストフィード内のエントリを行単位のリストで返します。
[V] ワークシートデータをJSONフォーマットで返す
String rv = "{ \"wsdat\":["; for (Iterator<ListEntry> it = dataList.iterator(); it.hasNext();) { ListEntry listEntry = (ListEntry) it.next(); rv += "{\"cdat\": \"" + listEntry.getPlainTextContent() + "\"},"; } rv = rv.substring(0, rv.length() - 1) + "]}"; return rv;
最後に、行単位のワークシートデータをJSONフォーマットに組み立てでクライアントに送りますが、この部分は一般的な繰り返し(iterate)処理ですので、問題ないでしょう。
2.4 ワークシートのデータを簡易形式で一覧表示する
Web画面での簡易形式表示は、JavaScriptの記述が容易で、Spreadsheet検索データをWeb画面から確認する場合に便利です。スプレッドシート風の画面表示もありますが、これについては次回の連載で紹介します。
リスト4 全店舗一覧表示(getSpreadAllShopYm.htm)
<!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title> getSpreadAllShopYm </title> <script type="text/javascript" src="../js/jquery-2.0.3.min.js"></script> <script type="text/javascript"> $(function() { $("#rev").click(function(e) { var query = {}; query["mode"] = "getspreadallshopym"; // 実行するビーンズメソッドを指定して連想配列(query)にセット query["sheet"] = $("#year").val() + $("#month").val(); //セレクトメニューで指定された年月からシート名を組み立ててqueryにセット $.get("/spread", query, function(res) { // jQueryの$.getでサーブレットにリクエストを送信 var r = $.parseJSON(res); //サーブレットからレスポンス受信したJSON形式の文字列をJavaScript オブジェクトに変換 for (var i = 0; i < r.sheet.length -1; i++) { items.options[items.options.length] = new Option(r.sheet[i].data); //受信したワークシートのデータを、セレクトメニューのオプション項目として表示 } }); }); }); </script> </head> <body> <h3>Spread Sheet 店舗個別読取</h3> 年:<select id="year"> <option value="">=年選択=</option> <option value="2013">2013年</option> <option value="2012">2012年</option> <option value="2011">2011年</option> </select> 月:<select id="month"> <option value="">=月選択=</option> <option value="01">1月</option> <option value="02">2月</option> <option value="03">3月</option> <option value="04">4月</option> <option value="05">5月</option> <option value="06">6月</option> <option value="07">7月</option> <option value="08">8月</option> <option value="09">9月</option> <option value="10">10月</option> <option value="11">11月</option> <option value="12">12月</option> </select> <input type="button" id="rev" value=" 参照 "/><hr/> <select id="items" size="15" style="width: 490px"></select><br/> </body> </html>
リスト4は、ワークシート1枚のデータすべてを一覧で表示しますが、サーブレットからの受信データをセレクトメニューのオプション項目として行単位で追加表示しています。この表示方式は簡単で、スプレッドデータの検索確認結果用としては便利ですが、表示内容が見やすいとは言えません。
→ Spread Sheet 年月別店舗売上
次に、画面から店舗名を指定して店舗単位のスプレッドデータを表示するサンプルを紹介します。またこのサンプルではスプレッドのデータを取得する方法として、スプレッドシートのKey値を使用しています。
2.5 ワークシート店舗別表示のビーンズメソッドを記述する
リスト5 店舗別表示(getSpreadShopYmメソッド)
public String getSpreadShopYm(String sheet, String shop) { String appliName = "cyberspace-SpreadsheetSearch-1"; String user = "xxxxxxxxxxxxxxxxxxx"; String pass = "yyyyyyyyyyy"; try { /////////////////////////////////////////////////////// // [I] 認証処理 SpreadsheetService spreadsheetservice = new SpreadsheetService(appliName); spreadsheetservice.setUserCredentials(user, pass); /////////////////////////////////////////////////////// // [II] 検索対象のスプレッドシートを特定 String key = "0Al8sybupdpoxxxxxxxxxxxxxxxxxzcUFmRnc"; URL spurl = new URL("http://spreadsheets.google.com/feeds/spreadsheets/" + key); SpreadsheetEntry spreadsheetentry = spreadsheetservice.getEntry(spurl, SpreadsheetEntry.class); /////////////////////////////////////////////////////// // [III] 検索対象のワークシートを特定 WorksheetEntry worksheetentry = spreadsheetentry.getDefaultWorksheet(); /////////////////////////////////////////////////////// // [IV] クエリでワークシートデータの検索 ListQuery listquery = new ListQuery(worksheetentry.getListFeedUrl()); ListFeed listfeed = spreadsheetservice.query(listquery, ListFeed.class); ListEntry listentry = listfeed.getEntries().get(Integer.parseInt(shop)); CustomElementCollection elements = listEntry.getCustomElements(); /////////////////////////////////////////////////////// // [V] ワークシートデータをJSONフォーマットで返す String rv = "{\"stat\": \"" + "参照成功" + "\", \"food\": \"" + elements.getValue("食品") + "\", \"electric\": \"" + elements.getValue("家電") + "\", \"bedding\": \"" + elements.getValue("寝具") + "\", \"other\": \"" + elements.getValue("その他") + "\", \"total\": \"" + elements.getValue("合計") + "\"}"; return rv; } catch (AuthenticationException e) { e.printStackTrace(); return "参照不成功 :" + e; } catch (IOException e) { e.printStackTrace(); return "参照不成功 :" + e; } catch (ServiceException e) { e.printStackTrace(); return "参照不成功 :" + e; } }
リスト5のビーンズメソッドは、リスト3と、[I]の認証処理と[III]の検索対象のワークシート特定は同じです。
[II] 検索対象のスプレッドシートを特定する
String key = "0Al8sybupdpoFdEdOTUtPLWxjOGRGckVvaklzcUFmRnc"; (1) URL spurl = new URL("http://spreadsheets.google.com/feeds/spreadsheets/" + key); (2) SpreadsheetEntry spreadsheetentry = spreadsheetservice.getEntry(spurl, SpreadsheetEntry.class); (3)
[II] の検索対象のスプレッドシート特定 ではキーを使用しています。このキー値はシート画面を開いた時のアドレスバーに表示されます。
(1)では図15の、URLキー key=0Al8sybupdpoFdEdOTUtPLWxjOGRGckVvaklzcUFmRnc を文字列にセットし、(2)でこのキー値を使用してURLオブジェクトを生成しています。
(3)次に getEntry メソッドの第一引数に(2)で生成したURLオブジェクトして実行することにより、アクセス可能なスプレッドシートの中から1つのスプレッドシートを選択してspreadsheetentryに返します。
[IV] クエリでワークシートデータの検索
ListQuery listquery = new ListQuery(worksheetentry.getListFeedUrl()); (1) ListFeed listfeed = spreadsheetservice.query(listquery, ListFeed.class); (2) ListEntry listentry = listfeed.getEntries().get(Integer.parseInt(shop)); (3) CustomElementCollection elements = listEntry.getCustomElements(); (4)
(1)と(2)はリスト3の処理と同様です。
(3)ではListFeedのgetEntries()メソッドでワークシートのデータエントリをアクセス可能な形式で取得し、getメソッドで店舗名に対応するインデックス値を指定することによって、店舗名に対応するデータエントリを取得します。
(4)ワークシート行に含まれるデータ項目をコレクション形式で取得します。
[V] ワークシートデータをJSONフォーマットで返す
String rv = "{\"stat\": \"" + "参照成功" + "\", \"food\": \"" + elements.getValue("食品") (1) + "\", \"electric\": \"" + elements.getValue("家電") (2) + "\", \"bedding\": \"" + elements.getValue("寝具") (3) + "\", \"other\": \"" + elements.getValue("その他") (4) + "\", \"total\": \"" + elements.getValue("合計") (5) + "\"}"; return rv;
クライアントに返すJSONデータを作っていますが、(1)~(5)では[IV]で生成したelementsのgetValueメソッドでスプレッドシートのカラム名に対応するテキストデータが返されます。
2.6 ワークシートの店舗別データを簡易形式で表示する
リスト6 店舗別表示(getSpreadShopYm.htm)
<!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title> getSpreadShopYm </title> <style> .num {text-align: right; } </style> <script type="text/javascript" src="../js/jquery-2.0.3.min.js"></script> <script type="text/javascript"> $(function() { $("#rev").click(function(e) { var query = {}; query["mode"] = "getspreadshopym"; query["shop"] = $("#shop").val(); query["sheet"] = $("#year").val() + $("#month").val(); $.get("/spread", query, function(res) { var r = $.parseJSON(res); $("#food").val(r.food); $("#electric").val(r.electric); $("#bedding").val(r.bedding); $("#other").val(r.other); $("#total").val(r.total); }); }); }); </script> </head> <body> <h3>Spread Sheet 店舗別読取</h3> 店舗名<select id="shop"> <option value="">=選択=</option> <option value="0">水戸</option> <option value="1">浦和</option> <option value="2">千葉</option> <option value="3">川崎</option> <option value="4">小田原</option> <option value="5">大阪</option> <option value="6">神戸</option> <option value="7">京都</option> <option value="8">滋賀</option> <option value="9">和歌山</option> <option value="10">鳥取</option> <option value="11">岡山</option> <option value="12">島根</option> <option value="13">広島</option> <option value="14">山口</option> </select> <input type="button" id="rev" value=" 参照 "/> <br /><br /> 年:<select id="year"> <option value="">=年選択=</option> <option value="2013">2013年</option> <option value="2012">2012年</option> <option value="2011">2011年</option> </select> 月:<select id="month"> <option value="">=月選択=</option> <option value="01">1月</option> <option value="02">2月</option> <option value="03">3月</option> <option value="04">4月</option> <option value="05">5月</option> <option value="06">6月</option> <option value="07">7月</option> <option value="08">8月</option> <option value="09">9月</option> <option value="10">10月</option> <option value="11">11月</option> <option value="12">12月</option> </select> <hr /> 食品 :<input type="text" size="12" class="num" id="food" /><br/> 家電 :<input type="text" size="12" class="num" id="electric" /><br/> 寝具 :<input type="text" size="12" class="num" id="bedding" /><br/> その他 :<input type="text" size="12" class="num" id="other" /><br/> 合計 :<input type="text" size="12" class="num" id="total" /><br/> </body> </html>
リスト6の店舗別表示では店舗選択用のセレクトメニューが追加され、ビーンズメソッドでの検索方式に合わせて([IV]の(3))value値を整数にしています。
図15はSpreadsheet店舗別読み取り表示画面で、店舗名、売上の年月を入力後「参照」ボタンのクリックで表示されます。
今回は、Google Drive上のspreadsheetをApp Engineから読み取って画面表示するサンプルを紹介しました。ここで画面は簡易形式で表示していましたが、次回は画面表示をスプレッド形式で行うサンプルと、読み取ったスプレッドデータをDatastoreに書き込むサンプルを紹介する予定です。
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- AppsスプレッドシートとApp Engineのデータ交換を完成させる
- App Engineから読み取ったデータの書き込みと、スプレッドシートのUIで表示する処理
- Google AppとApp Engineの準備・設定を完了する
- エンティティ所有/被所有関係とトランザクション処理
- 「TAURI」でExcelのデータを読み書きしてWebページに表示してみよう
- リスト・プロパティを含むエンティティの永続化
- JDO APIとLow-Level APIの違いと基本CRUD処理
- 同一テーブルでプロパティ項目を変更して永続化
- Office 2010とSilverlight 4の連携
- ドメインを考慮した柔軟なPodの配置を実現する「Balancer」