弁財天

ゴフマン「専門家を信じるのではなく、自分自身で考えて判断せよ」

DataTables | Table plug-in for jQuery update5

「jQuery 1.9」がリリース、最後のIE 6~8対応バージョンに
また、jQuery 1.9ではInternet Explorer 6~8サポートが含まれているが、jQuery 2.0では廃止されている。

DWRのBrowser Support

Calling DWR library and JQuery library

jQuery Get Json
いちばん過激なのはXMLでもCSVでもなくJSONをブラウザに応答してjQueryで処理することだな。わっはっは。

HTML5 Local Storage
ローカルストレージのサンプル
巨大な検索結果をブラウザのJavascriptで処理するには限界があったけど、それをHTML5対応ブラウザのWebストレージに保存してしまう方法。

Web Storageの概要
FF34で5MバイトIE8で4.8MBでIE11ではエラーw IE11がWin2kR2環境だったから。「信頼済みのサイト」に登録しないとWebストレージは使えない。IE11でも4.8MBまで使用可能。

巨大な検索結果をWebストレージに保存することはできない。 しかし画面に表示中のデータを保存することができる。 でもこのサイズだと設定ファイルの類を保存する領域だな。

Datatables and Perl (and a little bit of jQuery)
DataTables | Table plug-in for jQuery
すげー。サーバはJSONをブラウザに出力するだけにするのか。 こんなになっちゃったのね。 HTML5 業務アプリケーションにおける Java の役割

開発要員構成

JavaScript での処理が多くなっているため必要とされる開発要員のスキルセットが変化しています。従来型ではそのほとんどが Java エンジニアで

Javaエンジニア:24名
デザイナー:1名
業務コンサルティング:3名

でしたが、現在では

Javaエンジニア:3名
JavaScriptエンジニア:21名
デザイナー:4名
業務コンサルティング:3

です。これはあるプロジェクトの要員バランスですが Java エンジニアが 1/8 に成ってしまったことはエンジニアにとっては考え深いものがあります。

ほんと、そう思う。

結局のところサーバはJSONをブラウザに出力すればいいのであって、Webストレージは5Mあるし、表示系はブラウザのJavascriptでやるということですな。なんとも簡単な世の中になって来ますたなー。

もはや時代遅れになってしまったWebシステムが無数にあって、それぞれの連携はftp(CSVファイル)で、カネがある部署はHULFT連携してて、強者はSOAPやWebサービス化(XML)してる。銀行とは全銀手順なのにオンラインではなくファイル転送してる。処理できない部分はエクセルやアクセスだ。

今ではサーバに表示系をやらせるのは完全にやめHTMLでもXMLでもCSVでもないJSONデータを出力するだけにして、それをブラウザのJavascriptだけで加工するようになった。まぁたしかにiPhoneとかAndroidのタブレットがでてきたのでそれが望ましいのだろうな。

Data Layer: Earthquake data
いちばん驚いたのはこのデモ。サーバにjsonフォーマットの約1000行の750KバイトのファイルをJavascriptでブラウザにダウンロードしてGoogle MapのAPIと連携して表示してる。

Server-side processing
データベースの検索結果が膨大になる場合、すべてをブラウザのWebストレージにダウンロードすることはできない。最大5Mだから。そこでページ単位に表形式で表示するDataTables登場。すげー。

//code.jquery.com/jquery-1.11.1.min.js
//cdn.datatables.net/1.10.2/js/jquery.dataTables.min.js
これだけでやるのかすっげー。うはは。

もう気付いた?地図表示ならGoogle MapのAPI V3、巨大なデータベースを表形式にしたいのならdatatables(.)netと連携させる。サーバ側はデータベースをJSON形式に出力するだけ、代わりに表示ロジックはJavascriptで開発というよりマッシュアップ。

昔アプリケーションサービスプロバイダーってのがあったけど、こっちのJavascript部品の商売のほうがすごいな。

Datatables and Perl (and a little bit of jQuery)

デモ
おー、超素朴なPerlのCGIでMySQLのWHERE条件のLIMITとOFFSETを使って3万8千行のデータをページ表示してる。やるなー。これで検索結果のスケーラビリティは大丈夫だな。

Oracleでlimit offsetもどき
つまりGoogle Map V3との連携とデータベースの大量の検索結果もMySQLのLIMITとOFFSETがOracleのROWNUMで似たようなことができるので、やればできるてこと。

いやー、価値観がガラッと変わっちゃったなー。サーバーサイドは別にJavaEEの巨大なF/Wは不要。PerlのCGIでも可www。開発リソースをブラウザのJavascriptに投入しろてこと。そうすることでのみWebkit対応のブラウザやアプリが動作するタブレットに対応できるのだ。

この辺の展開はさすがNSAてかんじだ。じぇんじぇん勝てる気しない。

jsPDFはPDF生成するHTML5クライアント側ソリューションなのだとか。すげー。帳票までJavascriptでやっちゃうのか。 jsPDF

7 Best jQuery & JavaScript PDF Viewer plugin with examples
ブラウザのJavascriptでPDF生成するのはjsPDFだけだ。

オレが探してるのはjQueryのpluginなる世界なんだそーで、サーバー側ベージングができる似たようなプラグインに jTableがある。

Datatables and Perl (and a little bit of jQuery) のデモをMySQLからOracle 11gR2用に改造して日本語がうまく通るかテストしてみた。

静的なhtmlファイルhoge.html

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
  <title>Datatablesデモ</title>

  <style type="text/css" title="currentStyle">
    @import "https://datatables.net/release-datatables/media/css/demo_page.css";
    @import "https://datatables.net/release-datatables/media/css/demo_table.css";
</style>
<script type="text/javascript" language="javascript" src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script type="text/javascript" language="javascript" src="https://datatables.net/release-datatables/media/js/jquery.dataTables.js"></script>
<script type="text/javascript" charset="utf-8">
    $(document).ready( function() {
        oTable = $('#ip_data').dataTable( {
            "bProcessing":     true,
            "bServerSide":     true,
            "bPaginate":       true,  
            "bScrollInfinite": true,
            "bScrollCollapse": true,
            "sScrollY":        "200px",
            "sAjaxSource":     "/cgi-bin/hoge.cgi",
            language: {
            "sProcessing":     "処理中…",
            "sLengthMenu":   "_MENU_ 件表示",
            "sZeroRecords":  "データはありません。",
            "sInfo":         " _TOTAL_ 件中 _START_ から _END_ まで表示",
            "sInfoEmpty":    " 0 件中 0 から 0 まで表示",
            "sInfoFiltered": "(全 _MAX_ 件より抽出)",
            "sInfoPostFix":  "",
            "sSearch":       "検索:",
            "sUrl":          "",
            "oPaginate": {
                "sFirst":    "先頭",
                "sPrevious": "前",
                "sNext":     "次",
                "sLast":     "最終"
                },
            },
        } );

        $('#ip_data').on("click", "td", function() {
            var sData = oTable.fnGetData( this );
            alert( 'The cell clicked on had the value of '+sData );
        });

    } );
</script>
<style>
#ip_data_wrapper {
    width: 800px;
    border: 1px solid #B8DCFE;
    -moz-border-radius: 15px;
    border-radius: 15px;
    padding: 7px;
}
#ip_data_info {
    float: none;
}
tr.odd {
    background-color: #FFE3B9; 
}
tr.odd td.sorting_1 { background-color: #FFC167; }
tr.odd td.sorting_2 { background-color: #FFC167; }
tr.odd td.sorting_3 { background-color: #FFC167; }
tr.even td.sorting_1 { background-color: #FF9700; }
tr.even td.sorting_2 { background-color: #FF9700; }
tr.even td.sorting_3 { background-color: #FF9700; }
</style>


</head>
<body style="font-family: Arial;border: 0 none;">
<h1>ワークシートのリストをDatatableプラグインで表示してみた。</h1>
<div id="visualization"></div>
<table cellpadding="0" cellspacing="0" border="0" class="display"
id="ip_data" width="500px">
    <thead>
        <tr>
            <th width="5%">#</th>
            <th width="5%">doc_id</th>
            <th width="55%">ワークブック名称</th>
            <th width="5%">作成者</th>
            <th width="5%">作成日</th>
            <th width="5%">devkey</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td colspan="5" class="dataTables_empty">Loading data from server</td>
        </tr>
    </tbody>
    <tfoot>
        <tr>
            <th>#</th>
            <th>doc_id</th>
            <th>ワークブック名称</th>
            <th>作成者</th>
            <th>作成日</th>
            <th>devkey</th>
        </tr>
    </tfoot>
</table>

</body>
</html>
環境変数をセットしてt.plを実行するhoge.cgi
#!/bin/sh

. /var/www/cgi-bin/11gR2.env
perl t.pl
HOGE.pmを使うt,pl
#!/usr/bin/perl

use HOGE;

binmode(STDOUT, ":utf8");

HOGE::connect("hoge", "hoge");
print "Content-type: application/json\n\n";
HOGE::workbook_list_json("HOGE");
HOGE::disconnect();
HOGE.pmの残骸。
package HOGE;
use strict;
use utf8;
use JSON;

use CGI;

my $dbh;

BEGIN {
    $ENV{NLS_LANG} = 'Japanese_Japan.UTF8';
	use DBD::Oracle;
    if ($^O eq 'cygwin') {
        DBD::Oracle::ora_cygwin_set_env( NLS_LANG => $ENV{NLS_LANG} );
    }
}

sub connect {
	my ($user, $pass) = @_;
	$dbh = DBI->connect("dbi:Oracle:host=hoge;sid=ORCL", $user, $pass);
}

sub disconnect {
	$dbh->disconnect;
}

sub workbook_list_json {
  my ($created) = @_;

  my $q = CGI->new;
  my $params = $q->Vars;
  my $rn_length = $params->{iDisplayLength} > 0 ? $params->{iDisplayLength} : 25;
  my $rn_from = $params->{iDisplayStart} // 0;
  my $rn_to = $rn_from + $rn_length;

  my $sql_count = "select count(doc_id) from hoge_documents hoge WHERE hoge.doc_content_type = 'application/hoge'";
  my $sql = "select rn,doc_id,workbook_name,created_by,creation_date,devkey from (SELECT 
  hoge.doc_name workbook_name,
  decode(hoge_get_isitapps_eul, 1, hoge_get_apps_userresp(hoge.doc_created_by), hoge.doc_created_by) created_by,
  hoge.doc_created_date creation_date,
  hoge.doc_developer_key devkey,
  hoge.doc_id,
  rownum rn
  FROM hoge_documents hoge
  WHERE hoge.doc_content_type = 'hoge'
  ) where rn between $rn_from and $rn_to";

  my $count = $dbh->selectrow_arrayref($sql_count)->[0];
  my @values;
  my $data = $dbh->selectall_arrayref($sql, { Slice => [] }, @values);

  my $params;

  my $json = JSON::PP->new->ascii(1)->allow_nonref(1)->encode({ aaData => $data, iTotalRecords => $count, iTotalDisplayRecords => $count, sEcho => int($params->{sEcho}) });
  print $json;

}

1;
サーバサイドで動いてるのはOracle11gR2の検索結果をJSONで吐き出す素朴なPerlスクリプトのCGIで、HTMLはjqueryをJavascriptで参照してるだーけ。おそるべしHTML5の世界。

11gR2にはPostgresqlのLIMIT OFFSETはないので、ページ表示するのにrownum between 11 and 20のサブクエリを使ってる。 Oracle12cがlimit offsetをサポートしてるので、コードはもっと簡単になるかも。

日本語での問題はブラウザのJavascriptにユニコードエスケープした文字列を返さないと文字化けする。

Content-type: application/json

 {"aaData":[["1","109132","12_\u501f\u53d7…",…]],"iTotalRecords":"741","iTotalDisplayRecords":"741"}

デモのソースに use utf8; を設定してJSON出力のコードを

my $json = encode_json({ aaData => $data, iTotalRecords => $count, iTotalDisplayRecords => $count, sEcho => int($params->{sEcho}) });
print $json;
から
my $json = JSON::PP->new->ascii(1)->allow_nonref(1)->encode({ aaData => $data, iTotalRecords => $count, iTotalDisplayRecords => $count, sEcho => int($params->{sEcho}) });
print $json;
に変更するくらいだな。


FFだと完璧に動作。
IE11でも動いたけど、ちょっとレイアウトが崩れるのは<td >タグの%がダサいからだなw

何でこれかというとだな、重いバッチが非同期で長時間裏で走っても問題ないところだな。Ajaxの非同期表示の仕掛けがどうしても必要なのだ。


国の財政はアベノミクスで破綻してしまったが、カネがなくなってもこの開発手法ならなんとか生き残っていけるだろう。無線LANだけが使える格安の高解像度タブレットでも動作するところがメリットw

既存のJavaフレームワークを全く無視。ブログツールのように画面にキオスク表示。既存のWebアプリの限界を非同期(Ajax)にして飛び越えて行くという方針ですな。ちょっとクズどもにはもったいない方針。

TableToolsがCSVファイル、PDFファイルと印刷表示をサポート。やることないじゃん。

ROW_NUMBER 分析ファンクションの使用例
12cより前の11gR2以前のOracleはROWIDを使うしかない。

SELECT
	 USER_ID
	,USER_NAME
	,CREATED_ON
	,ROW_NUMBER() OVER (ORDER BY CREATED_ON, USER_ID) LINE_NO
	                                          --  ↑ ここが違う
	FROM USER_MASTER
row_number()関数が使えるかも。
select rn,doc_id,workbook_name,created_by,creation_date,devkey from (SELECT 
  doc_name workbook_name,
  doc_created_date creation_date,
  doc_developer_key devkey,
  doc_id,row_number() over (order by doc_name asc,doc_id) rn FROM eul5_documents
  WHERE doc_content_type = 'hoge' order by doc_name asc,doc_id ) where rn between 1 and 10
みたいな。

Datatableにダミーの1行を戻すには。
ここで「検索キーワードを入力↑」をユニコードエスケープ文字列「\u691c\u7d22\u30ad\u30fc\u30ef\u30fc\u30c9\u3092\u5165\u529b\u2191」に変換w

  if ($search_word eq "" || $formula eq "") {
        print $q->header('application/json');
        print '{"sEcho":0,"iTotalRecords":"1","iTotalDisplayRecords":"1","aaData":[["datatable-on-click","\u691c\u7d22\u30ad\u30fc\u30ef\u30fc\u30c9\u3092\u5165\u529b\u2191"]]}';           
        return;
  }

投稿されたコメント:

コメント
コメントは無効になっています。