今回は、App Engine側で読み取ったスプレッドデータのDatastore書き込み、およびそれぞれのデータ読み取り表示をスプレッドシート風のUI表示で行う処理内容について見ていきます。前回からJavaのプログラミングに入っていますが、今回もJavaによるスプレッドデータの処理が中心となります。
図1:Spread Sheet 年月別店舗売上(グリッド表示)(クリックで拡大)
図1のように、スプレッドデータをApp Engineから読み込んで、また簡易形式で画面表示する部分は前回の連載で見てきましたが、今回は読み取ったスプレッドデータをDatastoreに書き込んでみます。またDrive上およびDatastoreに書き込まれたスプレッドデータをグリッド表示するサンプルを紹介します。
スプレッドデータの表示形式では前回は簡易表示でしたが、今回はスプレッドシートの表示を、ActiveWidgetsを使用したサンプルとParamQuery gridを使用したサンプルの2種類紹介します。
1. Drive上のスプレッドデータをApp Engineから読み込みDatastoreに書き込む
最初はスプレッドデータのDatastore書き込みです。前回はスプレッドデータをApp Engineから読み込む処理について解説しましたが、今回は更にそのデータをDatastoreに書き込む処理について見ていきます。
ここで、スプレッドデータのDatastore書き込みでは、App EngineのLow-Level APIを使用しますが、Low-Level APIについてはThinkITにも下記の連載で解説していますので参考にしてください。
Think IT連載『Google App EngineのLow-Level APIを極める』
1.1 サーブレットのコード記述
リスト1 サーブレット(SpreadServlet.java)
01 | package com.google.gdata; |
02 | import java.io.IOException; |
03 | import java.io.PrintWriter; |
04 | import javax.servlet.http.*; |
05 | @SuppressWarnings("serial") |
06 | public class SpreadServlet extends HttpServlet { |
07 | public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { |
08 | resp.setContentType("text/plain"); |
09 | resp.setContentType("text/html; charset=utf-8"); |
10 | PrintWriter out = resp.getWriter(); |
11 | String mode = req.getParameter("mode"); |
12 | String sheet = req.getParameter("sheet"); |
13 | SpreadBean ss = new SpreadBean(); |
14 | //////////////////////////////////////////////////////////////////// |
16 | if (mode.equals("getdsallshopym")) { |
17 | String rv = ss.getDsAllShopYm(sheet); //(1) |
24 | public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { |
25 | resp.setContentType("text/plain"); |
26 | resp.setContentType("text/html; charset=utf-8"); |
27 | PrintWriter out = resp.getWriter(); |
28 | String mode = req.getParameter("mode"); |
29 | String sheet = req.getParameter("sheet"); |
30 | SpreadBean ss = new SpreadBean(); |
31 | //////////////////////////////////////////////////////////////////// |
33 | if (mode.equals("addspreadallshoptodsym")) { |
34 | String rv = ss.addSpreadAllShopToDsYm(sheet); //(2) |
サーブレットの処理は連載前回のリスト2への追加で行われており、(1)のgetDsAllShopYmメソッドではDatastoreに書き込まれたスプレッドデータの読み取り、(2)のaddSpreadAllShopToDsYmメソッドではDriveから読み込んだスプレッドデータのDatastore書き込み処理を行っています。
1.2 ビーンズコード記述
リスト2 addSpreadAllShopToDsYmメソッド(SpreadBean.java)
01 | public String addSpreadAllShopToDsYm(String sheet) { |
02 | // このアプリケーションの名称。任意の名前を設定 |
03 | String appliName = "cyberspace-SpreadsheetSearch-1"; |
04 | String username = "xxxxxxxxxxxxxxxxxxxxxxxxx"; |
05 | String password = "xxxxxxxxxxxxxxx"; |
07 | ///////////////////////////////////////////////////////// |
08 | // [I] Driveにあるスプレッドデータを読み取る |
10 | SpreadsheetService spreadsheetservice = new SpreadsheetService(appliName); |
11 | spreadsheetservice.setUserCredentials(username, password); |
13 | FeedURLFactory feedurlfactory = FeedURLFactory.getDefault(); |
14 | SpreadsheetQuery spreadsheetquery = |
15 | new SpreadsheetQuery(feedurlfactory.getSpreadsheetsFeedUrl()); |
16 | spreadsheetquery.setTitleQuery(sheet); // 検索対象のスプレッドシート名を指定している |
17 | SpreadsheetFeed spreadFeed = |
18 | spreadsheetservice.query(spreadsheetquery, SpreadsheetFeed.class); |
19 | SpreadsheetEntry spreadsheetentry = spreadFeed.getEntries().get(0); |
21 | WorksheetEntry worksheetentry = spreadsheetentry.getDefaultWorksheet(); |
23 | ListQuery listquery = new ListQuery(worksheetentry.getListFeedUrl()); |
24 | ListFeed listfeed = spreadsheetservice.query(listquery, ListFeed.class); |
25 | ///////////////////////////////////////////////////////// |
26 | // [II] 読み取ったスプレッドデータをDatastoreに書き込む |
27 | DatastoreService ds = DatastoreServiceFactory.getDatastoreService(); //(1) |
29 | for (ListEntry listentry : listfeed.getEntries()) { |
30 | CustomElementCollection customelementcollection = listentry.getCustomElements(); |
32 | DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); |
33 | String moddate = df.format(new Date()); |
35 | if (!customelementcollection.getValue("店舗名").equals("売上合計")) { //(3) |
36 | Key saleskey = KeyFactory.createKey //(4) |
37 | ("salesym", sheet + customelementcollection.getValue("店舗名")); |
38 | sales = new Entity(saleskey); //(5) |
39 | sales.setProperty("seq", i++); |
41 | Key saleskey = KeyFactory.createKey |
42 | ("salesymtotal", sheet + customelementcollection.getValue("店舗名")); //(6) |
43 | sales = new Entity(saleskey); //(7) |
45 | sales.setProperty("shop", customelementcollection.getValue("店舗名")); //(8) |
46 | sales.setProperty("yyyymm", sheet); |
47 | sales.setProperty("food", customelementcollection.getValue("食品")); |
48 | sales.setProperty("electric", customelementcollection.getValue("家電")); |
49 | sales.setProperty("bedding", customelementcollection.getValue("寝具")); |
50 | sales.setProperty("other", customelementcollection.getValue("その他")); |
51 | sales.setProperty("moddate", moddate); |
54 | return "スプレッドデータのDatastore登録成功"; |
55 | } catch (AuthenticationException e) { |
57 | return "スプレッドデータのDatastore登録不成功 :" + e; |
58 | } catch (IOException e) { |
60 | return "スプレッドデータのDatastore登録不成功 :" + e; |
61 | } catch (ServiceException e) { |
63 | return "スプレッドデータのDatastore登録不成功 :" + e; |
[I] Driveにあるスプレッドデータを読み取る
Drive上のスプレッドデータ読み取りは、前回記事のリスト3と同じですので省略します。
[II] 読み取ったスプレッドデータをDatastoreに書き込む
(1)DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
App EngineのDatastoreにアクセスする場合は、最初にDatastoreServiceのインスタンス(ここではds)を生成します。
(2)次に、読み込んだスプレッドデータを1行ずつ読み取っての繰り返し処理に入ります。
(3)if~else文
・読み取ったデータが売上合計でない場合はif文内の(4)でキーを作成した後、kind名が「salesym」のエンティティをDatastore書き込み用に生成します(5)。
・読み取ったデータが売上合計の場合はelse以下で処理しており、(6)でキーを作成した後、(7)で「salesymtotal」のエンティティを生成しています。
その後は(8)以下で書き込むエンティティ(sales)にプロパティ項目をセットし、(9)のputメソッドで書き込み処理を行います。
2.Datastoreに書き込まれたスプレッドデータをApp Engineから読み取る
リスト3 getDsAllShopYmメソッド (SpreadBean.java)
01 | public String getDsAllShopYm(String yyyymm) throws IOException, ServiceException { |
03 | DatastoreService ds = DatastoreServiceFactory.getDatastoreService(); //(1) |
04 | Filter ymFilter = new FilterPredicate("yyyymm", FilterOperator.EQUAL, yyyymm); //(2) |
05 | Query q = new Query("salesym").setFilter(ymFilter).addSort("seq", SortDirection.ASCENDING); |
07 | PreparedQuery pq = ds.prepare(q); //(4) |
08 | String rv = "["; //(7) |
09 | for (Entity res : pq.asIterable()) { //(5) |
10 | String shop = (String) res.getProperty("shop"); //(6) |
11 | String food = (String) res.getProperty("food"); |
12 | String electric = (String) res.getProperty("electric"); |
13 | String bedding = (String) res.getProperty("bedding"); |
14 | String other = (String) res.getProperty("other"); |
15 | rv += "[\"" + shop + "\"," |
17 | + "\"" + electric + "\"," |
18 | + "\"" + bedding + "\"," |
19 | + "\"" + other + "\"],"; //(7) |
21 | rv = rv.substring(0, rv.length() - 1) + "]"; //(7) |
23 | } catch (Exception e) { |
25 | return "参照不成功 Exception:" + e; |
Datastoreに書き込まれたスプレッドデータを読み取る処理は、よりシンプルなコード記述になります。
(1)で前と同様にDatastoreServiceのインスタンス(ds)を生成し、(3)でDatastore検索用のQueryを生成しています。Queryはフィルタやソート条件を追加して検索データの絞り込みや、並べ替えを指定することができますが、ここでは(2)のフィルタ指定で年月指定を行い、ソート条件でseq(シークエンス)プロパティを昇順で並べ替える指定を行っています。
次に、(4)prepareで実行するクエリを作成し、(5)ではasIterableで(4)で作成したクエリを実行し、 Entity項目を Iterable(反復可能)として取得します。その後(6)以下のgetPropertyでプロパティ名に対応した値を取得し、(7)でWebクライアントでの処理に対応したJSONの配列形式にフォーマット後(8)でクライアントへ送ります。
3.DriveおよびDatastoreのスプレッドデータをUI表示する
3.1 ブラウザ上の操作と表示
次に、ここまで見てきたスプレッドデータのサーバ側処理結果を、ブラウザでUI表示する処理について見ていきますが、最初に画面操作と表示内容を見てみます。
>
画面操作の参照用サイト
図2:Spreadsheetデータの登録・参照画面(
リンク)(クリックで拡大)
図2は、Spreadsheetデータ登録・参照の初期表示画面です。この画面から、ここまで見てきた
- スレッド登録のaddSpreadAllShopToDsYmメソッド
- Datastoreに書き込まれたスプレッドデータ読み取りのgetDsAllShopYmメソッド
- 前回紹介したDrive上のスプレッドデータ読み取りのgetSpreadAllShopYmメソッド
をサーブレット経由で呼び出して表示処理を行います。
3.2 Drive上スプレッドデータのDatastore登録
図3:スプレッドデータのDatastore登録(クリックで拡大)
図3はスプレッドデータのDatastore登録処理表示で、年月指定によってSpreadsheetデータを(前回の連載で見てきた)addSpreadAllShopToDsYmメソッドによって読み取り、次にDatastoreへの登録処理を行っています。
3.3 Drive上のスプレッドデータ参照
図4:Spreadsheetデータの登録・参照およびDatastore書き込みデータの参照画面(クリックで拡大)
図2の画面で年月指定後、「スプレッド参照」ボタンをクリックするとDrive上のスプレッドデータが図4の画面のようにグリッド形式で表示されます。Drive上スプレッドデータを簡易形式で表示するサンプルは前回の記事で紹介しており、サーバ側ビーンズの処理コードは前回のものと全く同じです。
また図4のようなスプレッド風画面表示では、ここで使用しているActicewidgetsのgridコントロールの他にも幾つかあってjQueryの追加プラグインなどもあり、その内のParamQuery gridについて最後に紹介します。
3.4 Datastoreスプレッドデータの参照
図5:Datastoreスプレッドデータの参照(クリックで拡大)
次に図5は、図3の処理でDatastoreに書き込まれたスプレッドデータを参照しています。書き込みは5月度のデータですので図3の参照データとは値が異なっているのが確認できます。
3.5 ActiveWidgetsが提供するWebコンポーネント
ActiveWidgets社(http://www.activewidgets.com/)は図4~図5のようなグリッドコンポーネントの他にも、図6のようなさまざまなWebコンポーネントを提供しており、これ等を使用することによってWebUIのリッチ化を行うことができます。
図6:ActiveWidgetsが提供するGrid以外のWebコンポーネント(クリックで拡大)
ところでActivewidgetsについては、筆者は以前にもThink ITに下記のような連載記事を書いています。この連載では、サーバ側で DWR(Direct Web Remoting)を使用した場合のActivewidgetsクライアントとの連携や表計算機能の追加、グラフ表示などについても解説していますので、興味のある方は是非参照してみてください。
Think IT連載『読んで試して!ActiveWidgets!』
3.6 Spreadsheetデータの登録・参照スクリプト
リスト3はSpreadsheetデータ登録・参照のHTMLおよびJavaScript記述でこの記述で図3~図5の表示処理すべてを行っています。
リスト4 Spreadsheetデータの登録・参照スクリプト(modDsSpreadAllShopYm.htm)
004 | <meta charset="utf-8"/> |
005 | <title> modDsSpreadAllShopYm </title> |
006 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> |
007 | <link rel="stylesheet" href="../css/aw.css"/> |
008 | <style type="text/css"/> |
009 | #sgrid .aw-grid-row {height: 20px; border-bottom: 1px solid #ccc} |
010 | #sgrid .aw-alternate-even {background: #fff;} |
011 | #sgrid .aw-alternate-odd {background: #ddf;} |
012 | #sgrid .aw-alternate-even .aw-column-0 {background: #ddf;} |
013 | #sgrid .aw-alternate-odd .aw-column-0 {background: #ccf;} |
014 | #sgrid .aw-rows-selected {background: #316ac5;} |
015 | #sgrid .aw-rows-selected .aw-column-1 {background: #316ac5;} |
016 | #sgrid .aw-column-0 {width: 75px; text-align: center; border-right: 1px dotted #ccc;} |
017 | #sgrid .aw-column-1 {width: 65px; text-align: center; border-right: 1px dotted #ccc;} |
018 | #sgrid .aw-column-2 {text-align: right} |
019 | #sgrid .aw-column-3 {text-align: right} |
020 | #sgrid .aw-column-4 {text-align: right} |
021 | #sgrid .aw-column-5 {text-align: right} |
022 | #sgrid .aw-column-6 {text-align: right} |
023 | #sgrid .aw-mouseover-cell {color: red;} |
024 | #sgrid .aw-grid-row .aw-cells-selected {background: #316ac5;} |
025 | #sgrid .aw-grid-headers {color: blue} |
026 | #sgrid .aw-grid-headers .aw-column-1 {font-weight: bold} |
027 | #sgrid .aw-mouseover-header {color: red;} |
028 | #sgrid .aw-mousedown-header {color: yellow;} |
029 | #sgrid .aw-header-1 {background: #def} |
030 | #sgrid .aw-row-selector {width: 20px; text-align: center} |
031 | #sgrid .aw-row-2 .aw-row-selector {font-weight: bold} |
032 | #sgrid .aw-mouseover-row .aw-row-selector {color: red;} |
033 | #sgrid .aw-mouseover-selector {background: green;} |
034 | #sgrid .aw-mousedown-selector {background: yellow;} |
035 | #sgrid {font-size: 10pt} |
037 | <script type="text/javascript" src="../js/jquery-2.0.3.min.js"></script> |
038 | <script type="text/javascript" src="../js/aw.js"></script> |
039 | <script type="text/javascript"> |
041 | $("#addDs").click(function() { //(1)スプレッド登録 |
042 | $("#dsp").html("<div id='stat'></div>") |
044 | query["mode"] = "addspreadallshoptodsym"; |
045 | query["sheet"] = $("#year").val() + $("#month").val(); |
046 | $.post("/spread", query, function(res) { |
047 | $("#stat").text(res); |
050 | $("#revSp").click(function() { //(2)ドライブのスプレッドデータ参照 |
051 | getdata("getspreadallshopym"); |
053 | $("#revDs").click(function() { //(3)Datastoreのスプレッドデータ参照 |
054 | getdata("getdsallshopym"); |
056 | function getdata(mode) { //(4) 参照処理関数 |
057 | $("#dsp").html("<div id='sgrid'></div>") |
059 | query["mode"] = mode; |
060 | query["sheet"] = $("#year").val() + $("#month").val(); |
061 | $.get("/spread", query, function(resp) { |
062 | var r = $.parseJSON(resp); //(5)受信したJSONデータをjavaScriptオブジェクトに変換 var rows = 16; |
064 | var cdat = new Array(rows); |
065 | for (j = 0; j < rows; j++) { |
066 | cdat[j] = new Array(cols); //(6)表示データ格納用に2次元配列生成 |
070 | cdat[10][0] = "中国地区"; |
071 | if (mode == "getspreadallshopym") { //(7)Driveスプレッドデータの配列セット |
072 | for (var i = 0; i < r.wsdat.length ; i++) { |
073 | var idat = r.wsdat[i].data.split(","); //(8) |
074 | for (var j = 0; j < idat.length; j++) { |
075 | var vdat = idat[j].split(":")[1]; //(9) |
076 | cdat[i][j+1] = vdat; //(10) |
079 | } else if (mode == "getdsallshopym") { //(11)Datastore格納スプレッドの配列セット |
080 | for (var i = 0; i < r.length; i++) { |
082 | for (var j = 0; j < r[i].length; j++) { |
084 | rtotal += parseInt(r[i][j]); //(11) 行合計の加算 |
086 | cdat[i][j+1] = r[i][j]; //(12)セル値の配列セット |
088 | cdat[i][j+1] = rtotal; //(13)行合計の集計値セット |
090 | cdat[15][1] = "売上合計"; |
091 | for (var i = 2; i < cols; i++) { //(14)列合計値の計算 |
093 | for (var j = 0; j < rows - 1 ;j++) { |
094 | ctotal += parseInt(cdat[j][i]); |
096 | cdat[rows -1][i] = ctotal; //(15)列合計の集計値セット |
099 | var headers = ["地域名", "店舗名", "食品", "家電", "寝具", "その他", "合計"]; |
101 | var grid = new AW.Grid.Extended; |
103 | var gridw = 28 + 93 * cols; |
104 | var gridh = 28 + 26 * rows; |
105 | grid.setControlSize(gridw, gridh); // グリッド幅と高さ指定 |
106 | grid.setCellText(cdat); //表示データの配列を指定 |
107 | grid.setCellEditable(true); //グリッドのセルを編集可能に指定 |
108 | grid.setHeaderText(headers); //ヘッダ表示の配列を指定 |
109 | grid.setRowCount(rows); // 行数指定 |
110 | grid.setColumnCount(cols); // 列数指定 |
111 | grid.setSelectorText(function(i){return this.getRowPosition(i);}); // 行ヘッダ表示 |
112 | grid.setSelectorVisible(true); //行ヘッダの表示指定 |
113 | document.getElementById("sgrid").innerHTML = grid; //(17) |
120 | <h3>Spreadsheet データ登録・参照</h3> |
122 | <option value="">=年選択=</option> |
123 | <option value="2013">2013年</option> |
124 | <option value="2012">2012年</option> |
125 | <option value="2011">2011年</option> |
128 | <option value="">=月選択=</option> |
129 | <option value="01">1月</option> |
130 | <option value="02">2月</option> |
131 | <option value="03">3月</option> |
132 | <option value="04">4月</option> |
133 | <option value="05">5月</option> |
134 | <option value="06">6月</option> |
135 | <option value="07">7月</option> |
136 | <option value="08">8月</option> |
137 | <option value="09">9月</option> |
138 | <option value="10">10月</option> |
139 | <option value="11">11月</option> |
140 | <option value="12">12月</option> |
142 | <input type="button" id="addDs" value=" スプレッド登録 " /> |
143 | <input type="button" id="revSp" value=" スプレッド参照 " /> |
144 | <input type="button" id="revDs" value="データストア参照 " /> |
リスト4で、(1)のスプレッド登録は一般的なjQueryの$.post通信なので問題ないでしょう。(2)と(3)はドライブとDatastoreのスプレッドデータの参照処理で、(4)のgetdataメソッドを、処理モード(”mode”)を引数に指定して呼び出しています。
処理内容はどちらも同様で、受信したスプレッドデータをセル項目毎に分割し、2次元配列にセットした後に表示処理(レンダリング)を行います。ただし、受信するデータフォーマットがDriveからとDatastoreからでは異なるため、配列へデータをセットする部分のコード記述が異なっています。
[Driveからのスプレッドデータを配列にセット]
Driveからのスプレッドデータの場合は、各セル項目がカンマ区切り(CSV)形式でセットされているため、(8)においてカンマ区切りでsplit処理したデータを配列idatにセットし、更に”セル名:セル値”になっている配列idatの各項目から(9)でセル値を取り出して、(10)で配列にセットしています。
[Datastoreからのスプレッドデータを配列にセット]
Datastoreからのスプレッドデータの場合は、リスト2の(7)でクライアントに送信されるJSONデータが2次元配列形式にフォーマットされているので、(5)でJavaScriptオブジェクトに変換された配列値を(11)で行合計値を加算した後、個別のセル値を(12)で配列にセットし、集計の終わった行合計値を(13)でセットしています。
その後、列合計の集計を(14)の繰り返し処理で行い、(15)で集計値をセットしています。ここで行合計の欄も列合計の計算で集計されるので、総合計値が行合計欄の最後の項目として配列にセットされます。
[グリッド表示の編集]
(16)のヘッダ項目指定以下は、グリッドの表示形式を設定するメソッドが並んでおり、最後に(17)のinnerHTMLでグリッドのWeb画面への表示(レンダリング)が行われます。
[ParamQuery gridでSpreadsheetデータを表示]
ここではActivewidgetsを使用したグリッド表示について紹介しましたが、もちろんグリッド表示をサポートしているJavaScriptライブラリは他に幾つもあります。例えばjQueryの追加プラグインとして公開されているものもありますが、ここではその中からParamQuery gridを紹介します。
図7:ParamQuery公式サイト(
リンク)(クリックで拡大)
ParamQuery gridはオープンソースのjQuery グリッドプラグインで、Ajaxアプリケーションで表データの表示や更新処理などで使用することができます。メモリの効率的使用と仮想表示のアーキテクチャを使用して百万のレコードでも10レコードの場合と同様のパフォーマンスを得ることができ、大量データの高速表示で威力を発揮します。
図8:ParamQuery gridを使用したスプレッドデータ表示(
リンク)(クリックで拡大)
図8はParamQuery gridを使用したスプレッドデータの登録・表示画面で、画面操作等は3の「DriveおよびDatastoreのスプレッドデータをUI表示する」で見てきたActiveWidgetsを使用したケースと全く同じです。
リスト5 ParamQuery gridを使用したSpreadsheetデータの登録・参照(modDsSpreadAllShopYmPq.htm)
004 | <meta charset="utf-8"/> |
005 | <title> modDsSpreadAllShopYmPq </title> |
006 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> |
010 | <link rel="stylesheet" href="../css/pqgrid.min.css" /> |
011 | <script type="text/javascript" src="../js/pqgrid.min.js"></script> |
012 | <script type="text/javascript"> |
014 | $("#addDs").click(function() { //(1)スプレッド登録 |
015 | $("#dsp").html("<div id='stat'></div>") |
017 | query["mode"] = "addspreadallshoptodsym"; |
018 | query["sheet"] = $("#year").val() + $("#month").val(); |
019 | $.post("/spread", query, function(res) { |
020 | $("#stat").text(res); |
023 | $("#revSp").click(function() { //(2)ドライブのスプレッドデータ参照 |
024 | getdata("getspreadallshopym"); |
026 | $("#revDs").click(function() { //(3)Datastoreのスプレッドデータ参照 |
027 | getdata("getdsallshopym"); |
029 | function getdata(mode) { //(4)参照処理関数 |
030 | $("#dsp").html("<div id='sgrid'></div>") |
032 | query["mode"] = mode; |
033 | query["sheet"] = $("#year").val() + $("#month").val(); |
034 | $.get("/spread", query, function(resp) { //(5) |
035 | var r = $.parseJSON(resp); |
038 | var data = new Array(rows); |
039 | for (j = 0; j < rows; j++) { |
040 | data[j] = new Array(cols); //(6)表示データ格納用に2次元配列生成 |
044 | data[10][0] = "中国地区"; |
045 | if (mode == "getspreadallshopym") { //(7)Driveスプレッドデータの配列セット |
046 | for (var i = 0; i < r.wsdat.length ; i++) { |
047 | var idat = r.wsdat[i].cdat.split(","); //(8) |
048 | for (var j = 0; j < idat.length; j++) { |
049 | var vdat = idat[j].split(":")[1]; //(9) |
050 | data[i][j+1] = vdat; //(10) |
053 | } else if (mode == "getdsallshopym") { //(11)Datastore格納スプレッドの配列セット |
054 | data[15][1] = "売上合計"; |
055 | for (var i = 0; i < r.length; i++) { |
057 | for (var j = 0; j < r[i].length; j++) { |
059 | rtotal += parseInt(r[i][j]); //(11) 行合計の加算 |
061 | data[i][j+1] = r[i][j]; //(12)セル値の配列セット |
063 | data[i][j+1] = rtotal; //(13)行合計の集計値セット |
065 | for (var i = 2; i < cols; i++) { //(14)列合計値の計算 |
067 | for (var j = 0; j < rows - 1 ;j++) { |
068 | ctotal += parseInt(data[j][i]); |
070 | data[rows - 1][i] = ctotal; //(15)列合計の集計値セット |
074 | obj.width = 635; //(16) |
076 | obj.colModel = [{title:"地域名", width:80, dataType:"string"}, //(17) |
077 | {title:"店舗名", width:80, dataType:"string"}, |
078 | {title:"食品 ", width:80, dataType:"integer", align:"right"}, |
079 | {title:"家電 ", width:80, dataType:"integer", align:"right"}, |
080 | {title:"寝具 ", width:80, dataType:"integer", align:"right"}, |
081 | {title:"その他 ", width:80, dataType:"integer", align:"right"}, |
082 | {title:"合計", width:80, dataType:"integer", align:"right"}]; |
083 | obj.dataModel = {data:data}; |
084 | $("#sgrid").pqGrid(obj); //(18)レンダリング |
091 | <h3>Spreadsheet データ登録・参照</h3> |
093 | <option value="">=年選択=</option> |
094 | <option value="2013">2013年</option> |
095 | <option value="2012">2012年</option> |
096 | <option value="2011">2011年</option> |
099 | <option value="">=月選択=</option> |
100 | <option value="01">1月</option> |
101 | <option value="02">2月</option> |
102 | <option value="03">3月</option> |
103 | <option value="04">4月</option> |
104 | <option value="05">5月</option> |
105 | <option value="06">6月</option> |
106 | <option value="07">7月</option> |
107 | <option value="08">8月</option> |
108 | <option value="09">9月</option> |
109 | <option value="10">10月</option> |
110 | <option value="11">11月</option> |
111 | <option value="12">12月</option> |
113 | <input type="button" id="addDs" value=" スプレッド登録 " /> |
114 | <input type="button" id="revSp" value=" スプレッド参照 " /> |
115 | <input type="button" id="revDs" value="データストア参照 " /> |
リスト5は、図8の画面表示と操作を行うParamQuery gridを使用した場合のWebクライアントコードです。リスト5での処理の流れは、(1)から(15)までActiveWidgetsを使用したリスト4の場合と同じで(16)から後の部分だけが異なっています。
(16)ではスプレッドの表示サイズ、(17)以下では各列のタイトルと表示書式を指定し、(18)の.pqGrid関数でレンダリングを行っています。
今回紹介したActiveWidgetとParamQueryの両方ともパラメータ指定で、グリッドのセルを表示オンリーから編集可能に設定することができ、Excelと同様にグリッドのセル単位で表示データの編集を行うこともできるようになっています。もちろん編集済みのデータをDatastoreに再登録する形でスプレッドデータの更新処理を行うことも可能です。
今回はDrive上スプレッドデータのDatastore書き込みと、スプレッドシート風の画面表示について見てきました。次回は連載最終回となりますが、これまでとは逆の流れで、Datastoreに書き込まれたスプレッドデータを読み取ってDrive上のSpreadsheet上に再現する処理、およびこれまで見てみたDrive上のスプレッドデータのDatastore書き込みを自動化する処理について見ていきます。
※サンプルサイトでの操作では、特に最初の参照などで時間がかかる場合がありますが、これはApp Engineインスタンス初期起動等での時間消費と考えられます。