Google Spreadsheets Data APIを使う 参照編
**Google Spreadsheet Data APIとは
GoogleのサービスをプログラムからアクセスできるGoogle Data APIのGoogle SpreadsheetsにアクセスするためのAPI
Google Data API - Google Code http://code.google.com/intl/ja/apis/gdata/
Google スプレッドシートの API とツール - Google Code http://code.google.com/intl/ja/apis/spreadsheets/
Google Data APIサイトには各言語から簡単にアクセスするためのライブラリが公開されています。
Java JavaScript Python .NETなど
ライブラリのダウンロード
Google Data APIサイトからライブラリをダウンロードします。
Java用ライブラリはここからダウンロード
Downloads - gdata-java-client - Google Data Java Client Library - Google Project Hosting http://code.google.com/p/gdata-java-client/downloads/list
サンプル付きとソースコード付きの2つがあります。
ソースコード付きの gdata-src.java-1.45.0.zip をダウンロードします。
ライブラリのインポート
ダウンロードしたzipファイルを解凍し、jarファイルをビルドパスに追加します。
Google Spreadsheets Data APIにアクセスするためには以下のライブラリが必要です。
- /gdata/java/lib/
gdata-core-1.0.jar
gdata-client-meta-1.0.jar
gdata-client-1.0.jar
gdata-media-1.0.jar
gdata-spreadsheet-meta-3.0.jar
gdata-spreadsheet-3.0.jar
gdata-docs-meta-3.0.jar
gdata-docs-3.0.jar
- /gdata/java/deps/
google-collect-1.0-rc1.jar
認証
非公開のspreadsheetsにアクセスするためには認証をする必要があります。
認証方式にはOAuthとAuthStubとClientLoginがあります。
今回はデスクトップアプリケーション向けにClientLoginを使用します。
WebアプリケーションならばOAuthかAuthStubを使うべきです。
OAuthはここが参考になるかもしれません。*1
Google Data APIのOAUTHに挑戦 - 気楽なC#工房 http://csfun.blog49.fc2.com/blog-entry-46.html
ClientLogin
import com.google.gdata.client.spreadsheet.SpreadsheetService; import com.google.gdata.util.AuthenticationException; public class ClientLogin { private static final String APPLICATION_NAME = "tomorrowkey-" + ClientLogin.class.getSimpleName() + "-v1"; public static void main(String[] args) { SpreadsheetService client = new SpreadsheetService(APPLICATION_NAME); String username = ArgumentUtil.getUsernameFromArgument(args); String password = ArgumentUtil.getPasswordFromArgument(args); try { client.setUserCredentials(username, password); } catch (AuthenticationException e) { e.printStackTrace(); } } }
アプリケーション名(APPLICATION_NAME)は
[会社名]-[アプリケーション名]-[バージョン]
という命名規則に従って設定します。
この規則に従っていなくても動作はしますが…。
Google Spreadsheetにアクセスする場合は常にSpreadsheetServiceを使用します。
スプレッドシート一覧を取得する
自分のDocsに保存されているSpreadsheetsの名前を表示します。
ソースコード
import java.io.IOException; import java.net.URL; import java.util.List; import com.google.gdata.client.spreadsheet.FeedURLFactory; import com.google.gdata.client.spreadsheet.SpreadsheetService; import com.google.gdata.data.spreadsheet.SpreadsheetEntry; import com.google.gdata.data.spreadsheet.SpreadsheetFeed; import com.google.gdata.util.AuthenticationException; import com.google.gdata.util.ServiceException; public class PrintAllSpreadsheet { private static final String APPLICATION_NAME = "tomorrowkey-" + PrintAllSpreadsheet.class.getSimpleName() + "-v1"; public static final void main(String[] args) { String username = ArgumentUtil.getUsernameFromArgument(args); String password = ArgumentUtil.getPasswordFromArgument(args); PrintAllSpreadsheet printAllSpreadsheet = new PrintAllSpreadsheet(); printAllSpreadsheet.start(username, password); } private SpreadsheetService client; private void start(String username, String password) { try { client = new SpreadsheetService(APPLICATION_NAME); client.setUserCredentials(username, password); URL url = FeedURLFactory.getDefault().getSpreadsheetsFeedUrl(); SpreadsheetFeed feed = client.getFeed(url, SpreadsheetFeed.class); List<SpreadsheetEntry> spreadsheetEntryList = feed.getEntries(); for (SpreadsheetEntry spreadsheetEntry : spreadsheetEntryList) { System.out.println(spreadsheetEntry.getTitle().getPlainText()); } } catch (AuthenticationException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ServiceException e) { e.printStackTrace(); } } }
実行結果
TEST 投票シート CharSettings作成シート 第2回Android温泉 会計 第2回Android温泉企画 第2回Android温泉参加者一覧 第2回Android温泉アンケート 集まれGDDのdeb仲間 デコ美統計 やることリスト 都道府県別DL数 デ部T申し込みフォーム 検索データ ガソリン 北海道日程 北海道日程
スプレッドシート名で検索して取得する
ソースコード
import java.io.IOException; import java.net.URL; import java.util.List; import com.google.gdata.client.spreadsheet.FeedURLFactory; import com.google.gdata.client.spreadsheet.SpreadsheetQuery; import com.google.gdata.client.spreadsheet.SpreadsheetService; import com.google.gdata.data.spreadsheet.SpreadsheetEntry; import com.google.gdata.data.spreadsheet.SpreadsheetFeed; import com.google.gdata.util.AuthenticationException; import com.google.gdata.util.ServiceException; public class PrintSearhedSpreadsheet { private static final String APPLICATION_NAME = "tomorrowkey-" + PrintSearhedSpreadsheet.class.getSimpleName() + "-v1"; public static final void main(String[] args) { String username = ArgumentUtil.getUsernameFromArgument(args); String password = ArgumentUtil.getPasswordFromArgument(args); PrintSearhedSpreadsheet printSearhedSpreadsheet = new PrintSearhedSpreadsheet(); printSearhedSpreadsheet.start(username, password); } private SpreadsheetService client; private void start(String username, String password) { try { client = new SpreadsheetService(APPLICATION_NAME); client.setUserCredentials(username, password); URL url = FeedURLFactory.getDefault().getSpreadsheetsFeedUrl(); SpreadsheetQuery query = new SpreadsheetQuery(url); query.setTitleQuery("android"); SpreadsheetFeed feed = client.query(query, SpreadsheetFeed.class); List<SpreadsheetEntry> spreadsheetEntryList = feed.getEntries(); for (SpreadsheetEntry spreadsheetEntry : spreadsheetEntryList) { System.out.println(spreadsheetEntry.getTitle().getPlainText()); } } catch (AuthenticationException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ServiceException e) { e.printStackTrace(); } } }
実行結果
第2回Android温泉 会計 第2回Android温泉企画 第2回Android温泉参加者一覧 第2回Android温泉アンケート
大文字/小文字は識別されないようですね。
ソースコード
import java.io.IOException; import java.net.URL; import java.util.List; import com.google.gdata.client.spreadsheet.FeedURLFactory; import com.google.gdata.client.spreadsheet.SpreadsheetQuery; import com.google.gdata.client.spreadsheet.SpreadsheetService; 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; public class PrintAllWorksheet { private static final String APPLICATION_NAME = "tomorrowkey-" + PrintAllWorksheet.class.getSimpleName() + "-v1"; public static final void main(String[] args) { String username = ArgumentUtil.getUsernameFromArgument(args); String password = ArgumentUtil.getPasswordFromArgument(args); PrintAllWorksheet printAllWorksheet = new PrintAllWorksheet(); printAllWorksheet.start(username, password); } private SpreadsheetService client; private void start(String username, String password) { try { client = new SpreadsheetService(APPLICATION_NAME); client.setUserCredentials(username, password); SpreadsheetEntry spreadsheet = getSpreadsheet("TEST"); URL url = spreadsheet.getWorksheetFeedUrl(); WorksheetFeed feed = client.getFeed(url, WorksheetFeed.class); List<WorksheetEntry> worksheetEntryList = feed.getEntries(); for (WorksheetEntry worksheetEntry : worksheetEntryList) { System.out.println(worksheetEntry.getTitle().getPlainText()); } } catch (AuthenticationException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ServiceException e) { e.printStackTrace(); } } private SpreadsheetEntry getSpreadsheet(String spreadsheetName) throws IOException, ServiceException { URL url = FeedURLFactory.getDefault().getSpreadsheetsFeedUrl(); SpreadsheetQuery query = new SpreadsheetQuery(url); query.setTitleQuery(spreadsheetName); SpreadsheetFeed feed = client.query(query, SpreadsheetFeed.class); List<SpreadsheetEntry> spreadsheetEntryList = feed.getEntries(); if (spreadsheetEntryList.isEmpty()) { throw new RuntimeException("not found spreadsheet '" + spreadsheetName + "'"); } return spreadsheetEntryList.get(0); } }
実行結果
東京 品川 新宿
ワークシート名で検索して取得する
ソースコード
import java.io.IOException; import java.net.URL; import java.util.List; import com.google.gdata.client.spreadsheet.FeedURLFactory; import com.google.gdata.client.spreadsheet.SpreadsheetQuery; import com.google.gdata.client.spreadsheet.SpreadsheetService; import com.google.gdata.client.spreadsheet.WorksheetQuery; 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; public class PrintSearchedWorksheet { private static final String APPLICATION_NAME = "tomorrowkey-" + PrintSearchedWorksheet.class.getSimpleName() + "-v1"; public static final void main(String[] args) { String username = ArgumentUtil.getUsernameFromArgument(args); String password = ArgumentUtil.getPasswordFromArgument(args); PrintSearchedWorksheet printAllWorksheet = new PrintSearchedWorksheet(); printAllWorksheet.start(username, password); } private SpreadsheetService client; private void start(String username, String password) { try { client = new SpreadsheetService(APPLICATION_NAME); client.setUserCredentials(username, password); SpreadsheetEntry spreadsheet = getSpreadsheet("TEST"); URL url = spreadsheet.getWorksheetFeedUrl(); WorksheetQuery query = new WorksheetQuery(url); query.setTitleQuery("品川"); WorksheetFeed feed = client.query(query, WorksheetFeed.class); List<WorksheetEntry> worksheetEntryList = feed.getEntries(); for (WorksheetEntry worksheetEntry : worksheetEntryList) { System.out.println(worksheetEntry.getTitle().getPlainText()); } } catch (AuthenticationException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ServiceException e) { e.printStackTrace(); } } private SpreadsheetEntry getSpreadsheet(String spreadsheetName) throws IOException, ServiceException { URL url = FeedURLFactory.getDefault().getSpreadsheetsFeedUrl(); SpreadsheetQuery query = new SpreadsheetQuery(url); query.setTitleQuery(spreadsheetName); SpreadsheetFeed feed = client.query(query, SpreadsheetFeed.class); List<SpreadsheetEntry> spreadsheetEntryList = feed.getEntries(); if (spreadsheetEntryList.isEmpty()) { throw new RuntimeException("not found spreadsheet '" + spreadsheetName + "'"); } return spreadsheetEntryList.get(0); } }
実行結果
品川
ワークシートからリスト一覧を取得する
リストとは行のことであり、spreadsheetをデータベースのように扱う場合、レコードのようなイメージになります。
import java.io.IOException; import java.net.URL; import java.util.List; import com.google.gdata.client.spreadsheet.FeedURLFactory; import com.google.gdata.client.spreadsheet.SpreadsheetQuery; import com.google.gdata.client.spreadsheet.SpreadsheetService; import com.google.gdata.client.spreadsheet.WorksheetQuery; 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; public class PrintAllList { private static final String APPLICATION_NAME = "tomorrowkey-" + PrintAllList.class.getSimpleName() + "-v1"; public static final void main(String[] args) { String username = ArgumentUtil.getUsernameFromArgument(args); String password = ArgumentUtil.getPasswordFromArgument(args); PrintAllList printAllWorksheet = new PrintAllList(); printAllWorksheet.start(username, password); } private SpreadsheetService client; private void start(String username, String password) { try { client = new SpreadsheetService(APPLICATION_NAME); client.setUserCredentials(username, password); WorksheetEntry worksheet = getWorksheet("TEST", "東京"); URL url = worksheet.getListFeedUrl(); ListFeed feed = client.getFeed(url, ListFeed.class); List<ListEntry> listEntryList = feed.getEntries(); for (ListEntry listEntry : listEntryList) { CustomElementCollection customElements = listEntry.getCustomElements(); StringBuilder sb = new StringBuilder(); sb.append("品目:").append(customElements.getValue("品目")).append(","); sb.append("価格:").append(customElements.getValue("価格")).append(","); sb.append("在庫:").append(customElements.getValue("在庫")); System.out.println(sb.toString()); } } catch (AuthenticationException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ServiceException e) { e.printStackTrace(); } } private WorksheetEntry getWorksheet(String spreadsheetName, String worksheetName) throws IOException, ServiceException { SpreadsheetEntry spreadsheet = getSpreadsheet(spreadsheetName); URL url = spreadsheet.getWorksheetFeedUrl(); WorksheetQuery query = new WorksheetQuery(url); WorksheetFeed feed = client.query(query, WorksheetFeed.class); List<WorksheetEntry> worksheetEntryList = feed.getEntries(); if (worksheetEntryList.isEmpty()) { throw new RuntimeException("not found worksheet '" + worksheetName + "' in '" + spreadsheetName + "'"); } return worksheetEntryList.get(0); } private SpreadsheetEntry getSpreadsheet(String spreadsheetName) throws IOException, ServiceException { URL url = FeedURLFactory.getDefault().getSpreadsheetsFeedUrl(); SpreadsheetQuery query = new SpreadsheetQuery(url); query.setTitleQuery(spreadsheetName); SpreadsheetFeed feed = client.query(query, SpreadsheetFeed.class); List<SpreadsheetEntry> spreadsheetEntryList = feed.getEntries(); if (spreadsheetEntryList.isEmpty()) { throw new RuntimeException("not found spreadsheet '" + spreadsheetName + "'"); } return spreadsheetEntryList.get(0); } }
実行結果
品目:りんご,価格:100,在庫:10 品目:みかん,価格:80,在庫:20 品目:もも,価格:160,在庫:3
ワークシートを検索してリストを取得する
ソースコード
import java.io.IOException; import java.net.URL; import java.util.List; 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.client.spreadsheet.WorksheetQuery; 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; public class PrintSearchedList { private static final String APPLICATION_NAME = "tomorrowkey-" + PrintSearchedList.class.getSimpleName() + "-v1"; public static final void main(String[] args) { String username = ArgumentUtil.getUsernameFromArgument(args); String password = ArgumentUtil.getPasswordFromArgument(args); PrintSearchedList printAllWorksheet = new PrintSearchedList(); printAllWorksheet.start(username, password); } private SpreadsheetService client; private void start(String username, String password) { try { client = new SpreadsheetService(APPLICATION_NAME); client.setUserCredentials(username, password); WorksheetEntry worksheet = getWorksheet("TEST", "東京"); URL url = worksheet.getListFeedUrl(); ListQuery query = new ListQuery(url); query.setFullTextQuery("*ん"); ListFeed feed = client.getFeed(query, ListFeed.class); List<ListEntry> listEntryList = feed.getEntries(); for (ListEntry listEntry : listEntryList) { CustomElementCollection customElements = listEntry.getCustomElements(); StringBuilder sb = new StringBuilder(); sb.append("品目:").append(customElements.getValue("品目")).append(","); sb.append("価格:").append(customElements.getValue("価格")).append(","); sb.append("在庫:").append(customElements.getValue("在庫")); System.out.println(sb.toString()); } } catch (AuthenticationException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ServiceException e) { e.printStackTrace(); } } private WorksheetEntry getWorksheet(String spreadsheetName, String worksheetName) throws IOException, ServiceException { SpreadsheetEntry spreadsheet = getSpreadsheet(spreadsheetName); URL url = spreadsheet.getWorksheetFeedUrl(); WorksheetQuery query = new WorksheetQuery(url); WorksheetFeed feed = client.query(query, WorksheetFeed.class); List<WorksheetEntry> worksheetEntryList = feed.getEntries(); if (worksheetEntryList.isEmpty()) { throw new RuntimeException("not found worksheet '" + worksheetName + "' in '" + spreadsheetName + "'"); } return worksheetEntryList.get(0); } private SpreadsheetEntry getSpreadsheet(String spreadsheetName) throws IOException, ServiceException { URL url = FeedURLFactory.getDefault().getSpreadsheetsFeedUrl(); SpreadsheetQuery query = new SpreadsheetQuery(url); query.setTitleQuery(spreadsheetName); SpreadsheetFeed feed = client.query(query, SpreadsheetFeed.class); List<SpreadsheetEntry> spreadsheetEntryList = feed.getEntries(); if (spreadsheetEntryList.isEmpty()) { throw new RuntimeException("not found spreadsheet '" + spreadsheetName + "'"); } return spreadsheetEntryList.get(0); } }
実行結果
品目:みかん,価格:80,在庫:20
検索条件には完全一致はもちろん、"*"を使って簡単なあいまい検索もできるみたいです。
ワークシートからすべてのセルを取得する
ソースコード
import java.io.IOException; import java.net.URL; import java.util.List; import com.google.gdata.client.spreadsheet.FeedURLFactory; import com.google.gdata.client.spreadsheet.SpreadsheetQuery; import com.google.gdata.client.spreadsheet.SpreadsheetService; import com.google.gdata.client.spreadsheet.WorksheetQuery; import com.google.gdata.data.spreadsheet.CellEntry; import com.google.gdata.data.spreadsheet.CellFeed; 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; public class PrintAllCell { private static final String APPLICATION_NAME = "tomorrowkey-" + PrintAllCell.class.getSimpleName() + "-v1"; public static final void main(String[] args) { String username = ArgumentUtil.getUsernameFromArgument(args); String password = ArgumentUtil.getPasswordFromArgument(args); PrintAllCell printAllWorksheet = new PrintAllCell(); printAllWorksheet.start(username, password); } private SpreadsheetService client; private void start(String username, String password) { try { client = new SpreadsheetService(APPLICATION_NAME); client.setUserCredentials(username, password); WorksheetEntry worksheet = getWorksheet("TEST", "東京"); URL url = worksheet.getCellFeedUrl(); CellFeed feed = client.getFeed(url, CellFeed.class); List<CellEntry> cellEntryList = feed.getEntries(); for (CellEntry cellEntry : cellEntryList) { System.out.println(cellEntry.getCell().getValue()); } } catch (AuthenticationException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ServiceException e) { e.printStackTrace(); } } private WorksheetEntry getWorksheet(String spreadsheetName, String worksheetName) throws IOException, ServiceException { SpreadsheetEntry spreadsheet = getSpreadsheet(spreadsheetName); URL url = spreadsheet.getWorksheetFeedUrl(); WorksheetQuery query = new WorksheetQuery(url); WorksheetFeed feed = client.query(query, WorksheetFeed.class); List<WorksheetEntry> worksheetEntryList = feed.getEntries(); if (worksheetEntryList.isEmpty()) { throw new RuntimeException("not found worksheet '" + worksheetName + "' in '" + spreadsheetName + "'"); } return worksheetEntryList.get(0); } private SpreadsheetEntry getSpreadsheet(String spreadsheetName) throws IOException, ServiceException { URL url = FeedURLFactory.getDefault().getSpreadsheetsFeedUrl(); SpreadsheetQuery query = new SpreadsheetQuery(url); query.setTitleQuery("TEST"); SpreadsheetFeed feed = client.query(query, SpreadsheetFeed.class); List<SpreadsheetEntry> spreadsheetEntryList = feed.getEntries(); if (spreadsheetEntryList.isEmpty()) { throw new RuntimeException("not found spreadsheet '" + spreadsheetName + "'"); } return spreadsheetEntryList.get(0); } }
実行結果
品目 価格 在庫 りんご 100 10 みかん 80 20 もも 160 3
ワークシートを検索してセルを取得する
ソースコード
import java.io.IOException; import java.net.URL; import java.util.List; import com.google.gdata.client.spreadsheet.CellQuery; import com.google.gdata.client.spreadsheet.FeedURLFactory; import com.google.gdata.client.spreadsheet.SpreadsheetQuery; import com.google.gdata.client.spreadsheet.SpreadsheetService; import com.google.gdata.client.spreadsheet.WorksheetQuery; import com.google.gdata.data.spreadsheet.CellEntry; import com.google.gdata.data.spreadsheet.CellFeed; 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; public class PrintSearchedCell { private static final String APPLICATION_NAME = "tomorrowkey-" + PrintSearchedCell.class.getSimpleName() + "-v1"; public static final void main(String[] args) { String username = ArgumentUtil.getUsernameFromArgument(args); String password = ArgumentUtil.getPasswordFromArgument(args); PrintSearchedCell printAllWorksheet = new PrintSearchedCell(); printAllWorksheet.start(username, password); } private SpreadsheetService client; private void start(String username, String password) { try { client = new SpreadsheetService(APPLICATION_NAME); client.setUserCredentials(username, password); WorksheetEntry worksheet = getWorksheet("TEST", "東京"); URL url = worksheet.getCellFeedUrl(); CellQuery query = new CellQuery(url); query.setFullTextQuery("*0"); CellFeed feed = client.getFeed(query, CellFeed.class); List<CellEntry> cellEntryList = feed.getEntries(); for (CellEntry cellEntry : cellEntryList) { System.out.println(cellEntry.getCell().getValue()); } } catch (AuthenticationException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ServiceException e) { e.printStackTrace(); } } private WorksheetEntry getWorksheet(String spreadsheetName, String worksheetName) throws IOException, ServiceException { SpreadsheetEntry spreadsheet = getSpreadsheet(spreadsheetName); URL url = spreadsheet.getWorksheetFeedUrl(); WorksheetQuery query = new WorksheetQuery(url); WorksheetFeed feed = client.query(query, WorksheetFeed.class); List<WorksheetEntry> worksheetEntryList = feed.getEntries(); if (worksheetEntryList.isEmpty()) { throw new RuntimeException("not found worksheet '" + worksheetName + "' in '" + spreadsheetName + "'"); } return worksheetEntryList.get(0); } private SpreadsheetEntry getSpreadsheet(String spreadsheetName) throws IOException, ServiceException { URL url = FeedURLFactory.getDefault().getSpreadsheetsFeedUrl(); SpreadsheetQuery query = new SpreadsheetQuery(url); query.setTitleQuery("TEST"); SpreadsheetFeed feed = client.query(query, SpreadsheetFeed.class); List<SpreadsheetEntry> spreadsheetEntryList = feed.getEntries(); if (spreadsheetEntryList.isEmpty()) { throw new RuntimeException("not found spreadsheet '" + spreadsheetName + "'"); } return spreadsheetEntryList.get(0); } }
実行結果
100 10 80 20 160
まとめ
1. FeedのURLを取得する
・Spreadsheet
→FeedURLFactory.getDefault().getSpreadsheetsFeedUrl();
・Worksheet
→SpreadsheetEntry#getWorksheetFeedUrl();
・List
→WorksheetEntry#getListFeedUrl();
・Cell
→WorksheetEntry#getCellFeedUrl();
2. 検索する場合はQueryを作成する
・Spreadsheet
→SpreadsheetQuery
・Worksheet
→WorksheetQuery
・List
→ListQuery
・Cell
→CellQuery
3. URL/Queryを使い、Feedを作成する
・Spreadsheet
→SpreadsheetService#getFeed(#URL, SpreadsheetFeed.class);
→SpreadsheetService#getFeed(#SpreadsheetQuery, SpreadsheetFeed.class);
・Worksheet
→SpreadsheetService#getFeed(#URL, WorksheetFeed.class);
→SpreadsheetService#getFeed(#WorksheetQuery, WorksheetFeed.class);
・List
→SpreadsheetService#getFeed(#URL, ListFeed.class);
→SpreadsheetService#getFeed(#ListQuery, ListFeed.class);
・Cell
→SpreadsheetService#getFeed(#URL, CellFeed.class);
→SpreadsheetService#getFeed(#CellQuery, CellFeed.class);
4. List
Feed#getEntries();
所感
同じようなコードをたくさん書いて疲れた、、。
とりあえず参照はこれだけあればできるはず。
他にRecordとTableってクラスがあるけど使ったことないなあ。
*1:試していません。いつかやりたいな
ブラウザからlogcatを見る
こちらが最新です ブラウザからlogcatを見る(アップデートしました) - 明日の鍵 http://d.hatena.ne.jp/tomorrowkey/20111001/1317451235
充電していない状態でlogcatを確認したくて、どうすればいいか悩んでました。
思いついたのが、表示するアプリを作ればいいんじゃね!って事。
しかし、端末に表示するのでは画面が小さすぎる、読みづらいので
Socketでパソコンとつないで表示することに
ついでに気になってたWebSocketを使うようにすれば、新しい事もできて一石二鳥!わーい!
構成
通常のSocketについて調べる
Socketはさんざん触ったことあるので、大丈夫。
勉強したい人はTECHSCOREがオススメ
ソケットネットワークプログラミング-TECHSCORE- http://legacy.techscore.com/tech/J2SE/Network/2.html
そういや本も一冊買ってた
Socketの他にStreamについても勉強になった
- 作者: Kenneth L. Calvert,Michael J. Donahoo,小高知宏
- 出版社/メーカー: オーム社
- 発売日: 2003/05/01
- メディア: 単行本
- 購入: 2人 クリック: 36回
- この商品を含むブログ (10件) を見る
WebSocketを調べる
The WebSocket API http://www.w3.org/TR/2011/WD-websockets-20110419/
WebSocketの一次情報
draftと書かれているので、仕様が変わるかもしれないってヤツですね。
英語分からん。
W3C - 『The WebSocket API』日本語訳 - HTML5.JP http://www.html5.jp/trans/w3c_websockets.html
日本語訳バージョン
日本語分からん。
WebSocket - Wikipedia http://ja.wikipedia.org/wiki/WebSocket
Wikipedia
通常のSocketみたく、繋げたら何してもおっけーってわけではなく
ハンドシェイクというやりとりが必要という情報が
WebSocketのプロトコル ― ありえるえりあ http://dev.ariel-networks.com/Members/inoue/websocket/
1年くらい前の記事だけど
WebSocketについてまとまってる
ハンドシェイクのやり方も丁寧に解説してある
意味あんのかって突っ込んでるけどw
http://www.google.co.jp/codesearch/p?hl=ja#CwgqP48SYDw/trunk/shared/J2SE/jWebSocketServer/org/jwebsocket/netty/engines/NettyEngineHandler.java
google code searchでjavaでのサーバ側の実装を見つけた
constructHandShakeResponseというメソッドでごにょごにょしてる
一番参考になった。コードが一番分かりやすい。
jWebSocket - The Open Source Java WebSocket Server http://jwebsocket.org/
どうやらこれのソースみたいだ
HTML5 WebSockets Tutorial http://www.tutorialspoint.com/html5/html5_websocket.htm
クライアントサイドはここを参照
簡単すなぁ…
作った
適当な実装だけど動くものはできた
試すには
http://tomorrowkey.googlecode.com/svn/tags/LogcatSocketServer/1.0.0/bin/LogcatSocketServer.apk
このアプリをAndroid端末にインストール(※クリックするとapkファイルがダウンロードされます)
アプリ起動するとIPアドレスとポート番号が表示されます。*1
http://tomorrowkey.googlecode.com/svn/trunk/LogcatOnBrowser/Client/logcat.html
同じLAN内につながってるパソコンにこのHTMLを保存する
ブラウザから保存したhtmlファイルにアクセスする*2
IPアドレスとポート番号を入れるテキストがあるので、アプリに表示されているものを入力
connectボタンを押せばlogcatが読み込まれます
動くようには作りましたが、けっこう適当実装です。
自己責任で実行してください。責任は一切負いません。
やってみて
javascriptとかhtmlとか普段ぜんぜんやらないから楽しかった!
今は情報がたくさんあって、知識がなくてもなんとなくで作れてしまうね
なんか実装の悪いところあったら指摘ください。
WebSocketはすごく楽しい。
可能性を感じる。
9patchを覚えよう!
9patchを使おう!
そこで9patchの出番です。
9patchは、画像よりモノが大きかった場合(今回は画像よりボタンが大きかった)
引き伸ばす部分を指定することで、画像の崩れを無くす事ができるのです!
Fireworksでいう所の9スライスという機能に似ています。
先ほどのボタン画像に9patchの処理を施してみます。
できました!
上側と左側に黒い1ピクセルが見えますでしょうか?
ちょっと拡大します。
拡大したのでボケてますが、これなら分かりますね。
9patchは上下左右に、アルファ無しの黒(#000000)の印を付けることで伸ばす部分を指定します。
上下左右それぞれ意味があります。
上と左の印は必須です。
下と右の印は省略することができます。
下と右の印の説明は後でやります。
図解9patch
さきほどの画像を解説すると
上に指定したピクセルの列(赤)が
横に伸びる時にコピーされます。
左に指定したピクセルの行(青)が
縦に伸びる時にコピーされます。
こうやって角丸部分が拡大されないようにします。
端末に設定してみましょう。
綺麗に角丸が表示されました。
さらに、どの部分にコピーされているのか確認したいため、こんな画像も用意してみました。
端末で表示してみましょう。
なるほどー、さっきのサンプルみたいにコピーされました。
さらに挙動を調べる
通常9patchの上と左の指定は1ピクセルだけで済みますが、実際には複数ピクセル指定することができます。
端末で表示させて挙動をたしかめてみましょう。
たとえば2ピクセル指定した場合はどうなるんでしょう。
端末で表示して見てみます。
半分ずつコピーされました。
おもしろいですね。
次はこんな画像はどうでしょう。
各々近いところを補うんですかね。
さらに活用する
挙動が分かれば、それを利用します。
この画像を使って
こんな風に表示したり*1
この画像を使って
こんな風に表示したり*2
グラデーションなら左側をほとんど塗っちゃってもいいんじゃないでしょうか
段差が見えちゃってますが、多少の拡大ならごまかせます。
ベタ塗りなのにこういう9patchの指定の仕方をしている人がいて、本当に理解しているのかなーって心配になります…。
ちゃんと表示はされるんだけどね…。
文字が変な位置に表示される
ボタンにはラベルが必要です。
ボタンを押した時にどんな機能が働くのかを、ラベルの文字によって表現しましょう。
今回は"こんにちは!"というラベルにします。
きっと押したら"ぽぽぽぽーん!"と音が鳴るに違いありません。
さっき作ったボタンにラベルを表示するよう変更してみます。
こんにちは!って表示されたけど、位置がおかしいです。
下に表示しているデフォルトのボタンではセンタリングされているのに、今回作ったボタンは変な位置に表示されています。
さらに9patch
これも9patchの機能を使って解決します。
上と左の印を使う事によって伸ばす部分を指定しましたが、
下と右の印を使う事によってコンテンツの位置を指定することができます。
ボタンの画像に対してコンテンツの位置を指定してみます。
できました!
例によって拡大します。
下と右に黒いピクセルがたくさんあるかと思います。
解説すると
下の黒いピクセルの列(赤)と
右の黒いピクセルの行(青)の
交わった場所(紫)がコンテンツの入る場所になります。
今回だと文字列の入る場所です。
端末で表示してみましょう。
ちゃんとセンタリングされました。
さっきの赤/青の画像でも表示してみましょう。
ちゃんと紫のところにラベルが表示されています。
さらに挙動をしらべる
調べようかと思ったのですが
何もできません。
下と右はこれですべてみたいです。
例えばこんな画像を用意して端末で表示してみようかと思ったのですが
eclipseさんに怒られてしまい、コンパイルが通りません。
9patchが苦手な画像
9patchには苦手な画像があります。
たとえば
ストライプ*3
グラデーション
例に出しましたが、段差が見えてしまうのでオススメできません。
その他連続した柄*4
他にもいろいろパターンはあると思うので、想像しながら作りましょう。
AndroidSDKの中に入ってるdraw9patchというツールを使うと、どういう風に表示されるか見ながら9patchのマークを付ける事ができます。
慣れないうちはそれを使うのも手でしょう。*5
さらに9patchを理解する
読むだけだと完全に理解はできません。
これ以上は実際に作って、端末に表示させてみて、挙動を自分で確かめてみるといいと思います。
その他9patch記事
Draw 9-patch | Android Developers http://developer.android.com/guide/developing/tools/draw9patch.html 公式の9patch解説
Draw 9-patch - ソフトウェア技術ドキュメントを勝手に翻訳 https://sites.google.com/a/techdoctranslator.com/jp/android/developing/tools/draw9patch 公式の9patch解説の日本語翻訳
9-patch - 3156note https://sites.google.com/site/3156note/home/android/9-patch draw9patchの使い方を詳しく解説
チュートリアル:9patchで画像を作る « Tech Booster http://techbooster.jpn.org/andriod/environment/3996/ draw9patchの使い方を詳しく解説
draw9patch で NinePatch をつくる方法 - Hacking My Way 〜 itogのhack日記 http://d.hatena.ne.jp/itog/20100209/1265684439 draw9patchの使い方を詳しく解説
まとめ
- 単純に拡大されたくない時は9patchを使う。
- コピーされる場所を指定するには上と左に9patchのマークをつける。
- 中に何かコンテンツを入れる時は下と右に9patchのマークをつける。
- どんな画像になるか想像しながら作る。
*1:xmlで指定することにより、ボタンとアイコン(ハート、星)を分離することができます。分離できた方がデザイナさんもプログラマーさんも幸せなので、そちらを使った方がいいです。
*2:xmlで指定することにより、ボタンとアイコン(ハート、星)を分離することができます。分離できた方がデザイナさんもプログラマーさんも幸せなので、そちらを使った方がいいです。
*3:9patchではなく、これを使うと解決できるかもしれません http://developer.android.com/guide/topics/resources/drawable-resource.html#Bitmap
*4:9patchではなく、これを使うと解決できるかもしれません http://developer.android.com/guide/topics/resources/drawable-resource.html#Bitmap
Protocol Buffersを使う
ProtocolBuffers
protobuf - Project Hosting on Google Code
http://code.google.com/p/protobuf/
ProtocolBuffersはシリアライズライブラリです。
バージョン2.4.0aを使ってみます。
ダウンロード
ビルド
C++のところをビルド
$ ./configure $ make $ make check $ sudo make install
jarつくる
cd java mvn package
targetフォルダ内にprotobuf-java-2.4.0a.jarというファイルができていると思います
シリアライズ化するクラスの作成
ProtocolBuffersはシリアル化するクラスのprotoファイルを書く必要があります
Language Guide - Protocol Buffers - Google Code http://code.google.com/intl/ja/apis/protocolbuffers/docs/proto.html
このprotoファイルはIDLって言語で書くみたいです。
androidでserviceとの通信インターフェイスを定義するaidlファイルもIDLですね
インタフェース記述言語 - Wikipedia http://ja.wikipedia.org/wiki/%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%95%E3%82%A7%E3%83%BC%E3%82%B9%E8%A8%98%E8%BF%B0%E8%A8%80%E8%AA%9E
EmployeeTranslater.proto
package jp.tomorrowkey; message Employee { required string name; required int32 age; }
ファイル名とメッセージ名は違うやつにしないと怒られます
クラスに変換
プロジェクトルートで以下をコマンドする
protoc --java_out=src src/jp/tomorrowkey/EmployeeTranslater.proto
するとsrc/jp/tomorrowkeyにEmployeeTranslater.javaができあがります。
クラス変換を楽にするために
protoclipseというeclipse pluginがあります
これを使うとproto→javaの変換をjavaのビルドのタイミングで自動でやってくれます。
protoclipse - Project Hosting on Google Code http://code.google.com/p/protoclipse/
インストールが終わったらprotocの場所を設定したあとProtocolBuffersを使いたいプロジェクトで
右クリックして[Add Google ProtoBuf Compiler Nature]を選べば完了です。
Buildersの中にProtocolBuffersの変換する処理が追加されてると思います。
コードを書く
import com.google.protobuf.InvalidProtocolBufferException; public class Main { public static void main(String[] args) { EmployeeTranslater.Employee.Builder builder = EmployeeTranslater.Employee.newBuilder(); builder.setName("taro"); builder.setAge(25); EmployeeTranslater.Employee src = builder.build(); // シリアライズ byte[] buffer = src.toByteArray(); // 表示してみる for (byte b : buffer) { System.out.print(Integer.toHexString(b & 0xFF) + " "); } System.out.println(); // デシリアライズ EmployeeTranslater.Employee dst = null; try { dst = EmployeeTranslater.Employee.parseFrom(buffer); } catch (InvalidProtocolBufferException e) { dst = null; } // ちゃんと復元されたかな? if (dst != null) { System.out.println("name:" + dst.getName()); System.out.println("age:" + dst.getAge()); } else { System.out.println("dst is null"); } } }
MessagePack for Javaを使う
ビルド
ビルドにはMavenが必要です。
ダウンロードしてパス通せば使えます。
Maven - Welcome to Apache Maven http://maven.apache.org/
あとはこれを打てばおっけー
$ git clone https://github.com/msgpack/msgpack.git $ cd msgpack/java/ $ mvn package $ mvn install
targetフォルダの中にmsgpack-0.5.1-devel.jarができてると思います
eclipseでプロジェクト作成
普通にjavaプロジェクトを作成
libsフォルダを作成し、中にmsgpack-0.5.1-devel.jarを入れてビルドパスに追加する
.classpathを開き以下を追加する
コードを書く
import org.msgpack.MessagePack; import org.msgpack.annotation.MessagePackMessage; public class Main { /** * シリアライズするクラス * MessagePackMessageアノテーションをつけるだけでおっけー */ @MessagePackMessage public static class Employee { // publicなフィールドでないとシリアライズされない public String name; // publicなフィ(ry public int age; public Employee() { // デフォルトコンストラクタないと怒られます } public Employee(String name, int age) { this.name = name; this.age = age; } } public static void main(String[] args) { Employee src = new Employee("taro", 25); // シリアライズ byte[] buffer = MessagePack.pack(src); // 表示してみる for (byte b : buffer) { System.out.print(Integer.toHexString(b & 0xFF) + " "); } System.out.println(); // デシリアライズ Employee dst = MessagePack.unpack(buffer, Employee.class); // ちゃんと復元されたかな? System.out.println("name:" + dst.name); System.out.println("age:" + dst.age); } }
キーリピートを実装する
Buttonクラスを拡張して、長押しされている場合クリック動作を呼び出すようにします。
RepeatButton.java
import android.content.Context; import android.os.Handler; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.View.OnLongClickListener; import android.widget.Button; public class RepeatButton extends Button implements OnLongClickListener { /** * 連続してボタンを押す間隔(ms) */ private static final int REPEAT_INTERVAL = 100; /** * 連打フラグ */ private boolean isContinue = true; /** * ハンドラ */ private Handler handler; public RepeatButton(Context context, AttributeSet attrs) { super(context, attrs); setOnLongClickListener(this); handler = new Handler(); } @Override public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event); // キーから指が離されたら連打をオフにする if (event.getAction() == MotionEvent.ACTION_UP) { isContinue = false; } return true; } @Override public boolean onLongClick(View v) { isContinue = true; // 長押しをきっかけに連打を開始する handler.post(repeatRunnable); return true; } Runnable repeatRunnable = new Runnable() { @Override public void run() { // 連打フラグをみて処理を続けるか判断する if (!isContinue) { return; } // クリック処理を実行する performClick(); // 連打間隔を過ぎた後に、再び自分を呼び出す handler.postDelayed(this, REPEAT_INTERVAL); } }; }
使用例
こんな感じで使えばNumberPicker的に使えます
MainActivity.java
import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.TextView; public class MainActivity extends Activity implements OnClickListener { private TextView txtNumber; private RepeatButton btnIncrement; private RepeatButton btnDecrement; private int number = 0; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); txtNumber = (TextView)findViewById(R.id.txtNumber); txtNumber.setText(String.valueOf(number)); btnIncrement = (RepeatButton)findViewById(R.id.btnIncrement); btnIncrement.setOnClickListener(this); btnDecrement = (RepeatButton)findViewById(R.id.btnDecrement); btnDecrement.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btnIncrement: { increment(); break; } case R.id.btnDecrement: { decrement(); break; } } } private void increment() { number++; txtNumber.setText(String.valueOf(number)); } private void decrement() { number--; txtNumber.setText(String.valueOf(number)); } }
main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:gravity="center_vertical|center_horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent"> <view class="jp.tomorrowkey.android.repeatpushbutton.RepeatButton" android:id="@+id/btnIncrement" android:text="Increment" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/txtNumber" android:text="0" android:textSize="32sp" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <view class="jp.tomorrowkey.android.repeatpushbutton.RepeatButton" android:id="@+id/btnDecrement" android:text="Decrement" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
独自Viewの定義の仕方
独自ViewのXMLの定義の仕方は2つあります
viewタグを使う場合
<view class="jp.tomorrowkey.android.repeatpushbutton.RepeatButton" android:layout_width="wrap_content" android:layout_height="wrap_content" />
暗号本メモ
[twitter:@inuchin] さんオススメ
図解入門よくわかる最新暗号技術の基本と仕組み (How‐nual Visual Guide Book)
- 作者: 若林宏
- 出版社/メーカー: 秀和システム
- 発売日: 2005/04/11
- メディア: 単行本
- 購入: 1人 クリック: 19回
- この商品を含むブログ (6件) を見る
- 古いけど入門書にいいらしい
- 作者: 結城浩
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2008/11/22
- メディア: 単行本
- 購入: 46人 クリック: 720回
- この商品を含むブログ (82件) を見る
- レビューもいい感じだし、ポチッた
[twitter:@hamatz] さんオススメ
- 作者: ブルース・シュナイアー,山形浩生,Bruce Schneier
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2003/05/31
- メディア: 単行本
- クリック: 66回
- この商品を含むブログ (33件) を見る
- 辞書的に使える
- かなりオススメらしい
- 詳しくなったらほしいな
- 欠点:重い
最新 暗号技術 (NTT R&D 情報セキュリティシリーズ)
- 作者: NTT情報流通プラットフォーム研究所
- 出版社/メーカー: アスキー
- 発売日: 2006/05/17
- メディア: 大型本
- クリック: 5回
- この商品を含むブログ (4件) を見る
- 入門に良さそう?
- レビューがなくて判断しづらい
- 作者: サイモンシン,Simon Singh,青木薫
- 出版社/メーカー: 新潮社
- 発売日: 2001/07/31
- メディア: 単行本
- 購入: 9人 クリック: 230回
- この商品を含むブログ (241件) を見る
- 暗号の勉強というより暗号の歴史を読む
- モチベーションあげるための本
[twitter:@keiji_ariyama] さんオススメ
Javaで作って学ぶ暗号技術 - RSA,AES,SHAの基礎からSSLまで
- 作者: 神永正博,山田聖,渡邊高志
- 出版社/メーカー: 森北出版
- 発売日: 2008/05/13
- メディア: 単行本(ソフトカバー)
- 購入: 2人 クリック: 87回
- この商品を含むブログ (6件) を見る
- javaで実装されてるならコード読めるし、分かりやすいかも
改訂新版 暗号の数理―作り方と解読の原理 (ブルーバックス)
- 作者: 一松信
- 出版社/メーカー: 講談社
- 発売日: 2005/09/10
- メディア: 新書
- 購入: 3人 クリック: 11回
- この商品を含むブログ (20件) を見る
- 内容がきになる。
- 暗号解読と同じく歴史が読めるかも?