AppsスプレッドシートとApp Engineのデータ交換を完成させる
[3] タスク実行サーブレット
キューに追加された実行サーブレットはデフォルトではPOSTメソッドで呼び出され、スプレッドデータのDatastore書き込を行います・サーブレットの指定はリスト4 web.xmlの(2)で行っています。
リスト8 sptodsServlet.java
package com.google.gdata; import javax.servlet.http.*; import java.io.IOException; import java.sql.Connection; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.logging.Logger; 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.Key; import com.google.appengine.api.datastore.KeyFactory; 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.util.AuthenticationException; import java.util.Properties; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; import javax.mail.Message; import javax.mail.Session; import javax.mail.Transport; @SuppressWarnings("serial") public class sptodsServlet extends HttpServlet { private static final Logger log = Logger.getLogger(sptodsServlet.class.getName()); //(1) Connection con = null; @Override public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { req.setCharacterEncoding("utf-8"); resp.setContentType("text/plain"); resp.setCharacterEncoding("utf-8"); String sheet = req.getParameter("sheet"); String applicationName = "cyberspace-SpreadsheetSearch-1"; String username = "xxxxxxxxxxxxxxxxxxxxxx"; String password = "xxxxxxxxxxxxxx"; try { SpreadsheetService spreadsheetservice = new SpreadsheetService(applicationName); spreadsheetservice.setUserCredentials(username, password); // 検索対象のスプレッドシートを取得 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); // 検索対象のワークシートを取得 WorksheetEntry worksheetentry = spreadsheetentry.getDefaultWorksheet(); // ワークシート内を検索 ListQuery listQuery = new ListQuery(worksheetentry.getListFeedUrl()); ListFeed listFeed = spreadsheetservice.query(listQuery, ListFeed.class); DatastoreService ds = DatastoreServiceFactory.getDatastoreService(); int i = 0; for (ListEntry listentry : listFeed.getEntries()) { CustomElementCollection customelementcollection = listentry.getCustomElements(); DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); String moddate = df.format(new Date()); Entity sales = null; if (!customelementcollection.getValue("店舗名").equals("売上合計")) { Key saleskey = KeyFactory.createKey ("salesym", sheet + customelementcollection.getValue("店舗名")); sales = new Entity(saleskey); sales.setProperty("seq", i++); } else { Key saleskey = KeyFactory.createKey ("salesymtotal", sheet + customelementcollection.getValue("店舗名")); sales = new Entity(saleskey); } sales.setProperty("shop", customelementcollection.getValue("店舗名")); sales.setProperty("yyyymm", sheet); sales.setProperty("food", customelementcollection.getValue("食品")); sales.setProperty("electric", customelementcollection.getValue("家電")); sales.setProperty("bedding", customelementcollection.getValue("寝具")); sales.setProperty("other", customelementcollection.getValue("その他")); sales.setProperty("moddate", moddate); ds.put(sales); log.severe("{\"flag\": \"" + "Success " + "\"}"); } } catch (AuthenticationException e) { log.severe("{\"flag\": \"" + "認証エラー : " + e + "\"}"); } catch (IOException e) { log.severe("{\"flag\": \"" + "IOエラー : " + e + "\"}"); } catch (Exception e) { log.severe("{\"flag\": \"" + "エラー : " + e + "\"}"); } ////////////////////////////////////////////////////////// // メール送信処理l Properties props = new Properties(); Session session = Session.getDefaultInstance(props, null); String msgBody = "Drive上スプレッドシートの" + sheet.substring(0, 4) + "年" + sheet.substring(4, 6) +"月度データの、Datastore書き込みが完了しました。\n"; try { Message msg = new MimeMessage(session); msg.setFrom(new InternetAddress("sws3gaej4pgm3@gmail.com", "Spread Admin")); msg.addRecipient(Message.RecipientType.TO, new InternetAddress("superelmer21@gmail.com", "Spread user")); msg.addRecipient(Message.RecipientType.CC, new InternetAddress("sws3gaej4pgm3@gmail.com", "Admin user")); msg.setSubject("Spread to Datastore"); msg.setText(msgBody); Transport.send(msg); log.severe("{\"flag\": \"" + "Success " + "\"}"); } catch (AddressException e) { log.severe("{\"flag\": \"" + "アドレスエラー : " + e + "\"}"); } catch (MessagingException e) { log.severe("{\"flag\": \"" + "メッセージングエラー :" + e + "\"}"); } } }
リスト8はDriveのスプレッドデータを読み取ってDatastoreに書き込むサーブレットです。サーブレットで行われている処理内容は、連載第4回のリスト2にあるビーンズメソッド(addSpreadAllShopToDsYm)と殆ど同じですが、最後にメール送信の処理が追加されています。
[メール送信処理]
Datastoreへの書き込み完了後、メールでの通知を行っています。App Engineのメール送信ではMimeMessageオブジェクトを使用します。リスト8ではインスタンスmsgのメソッドを使用してFROM、TO、CCのアドレスおよび送信メッセージ情報を組み立て、Transportクラスのsend()メソッドでメール送信します。送信されたメールは、メールクライアントがGmailの場合下記のように受信表示されます。
[ログへの出力]
リスト8のサーブレットはユーザーインタラクションがないため、出力はログ・ファイルに行います。ログ出力ではLog4jを使用していますが、(1)でクラスの名称を Logger インスタンスに設定してLoggerインスタンス(log)を生成、そのあと下記メソッドを使用してログ出力を行っています。
log.info("メッセージ1"); //ログメッセージ1の出力
log.warning("メッセージ2"); //警告(warning)ログメッセージ2の出力
log.severe("メッセージ3"); //エラーログメッセージ3の出力
2. 3 Pull Taskの実行
[1] デフォルトアプリケーションに設定
タスクはデフォルトアプリケーションでなければ実行されません。タスク実行にはプロジェクトをApp EngineのApplicationとしてアップロード後、アップロードしたApplicationのバージョンを、App Engine管理者画面のVersionsから「Make Default」ボタンクリックでデフォルトバージョンに設定します。
[2] 実行確認用HTML
リスト9 pulltask.htm
<!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title>タスクジョブ</title> </head> <body><h3>タスクジョブテスト</h3> <a href="/cron/taskcontrol">pullタスクを実行</a> </body> </html>
また、タスクをデフォルトアプリケーションにしても、スケジュールされた時間が来るまで実行されません。しかし、これは開発時にタスク処理の動作確認を行う場合は不便です。リスト9のような簡単なプログラムを作れば、リスト6のtask制御サーブレットをWebクライアントから直接実行することができ、このプログラムを使用してプログラムの動作確認とデバッグを行います。ただしこのプログラムはweb.xmlの
スプレッドシートを使用したGoogle DriveとApp Engineのデータ交換を中心とした本連載も今回で終了です。ここまで見てきた内容は数あるGoogleのクラウドを連携する内容でしたが、連載第2回の図18にあるように、App Engineを中心としたクラウド連携は他にもあり、その中でも有力な機能としてApp EngineのDatastoreにあるデータをCloud Storageを介してBigQueryでのビッグデータ解析を行えるようにする連携があります。そしてこの連携を連載で見てきたDriveスプレッドデータとApp Engineの連携と組み合わせれば、大量のスプレッド(およびExcel)データをビッグデータソースとして使用するシステムを構築することもできるようになります。
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- AppsのスプレッドシートデータをApp Engineから読み取る
- App Engineから読み取ったデータの書き込みと、スプレッドシートのUIで表示する処理
- Google AppとApp Engineの準備・設定を完了する
- JDO APIとLow-Level APIの違いと基本CRUD処理
- クラウドをより身近に!Google Driveを使った業務データ移行入門
- 同一テーブルでプロパティ項目を変更して永続化
- FirebaseプログラムをApp Engineにディプロイする
- エンティティ所有/被所有関係とトランザクション処理
- リスト・プロパティを含むエンティティの永続化
- Google Driveと Cloud DatastoreのデータをBigQueryで使用する