2008/12/20

Groovyで、テーブル一覧、テーブル定義をHTML出力してみる2

前回作成したゲンゾウ用ポストイット: Groovyで、テーブル一覧、テーブル定義をHTML出力してみるの改良版。

もう少しテーブル定義を見やすくしてみました。

  • 左側にテーブル一覧が表示される
  • 右側にテーブル定義が表示される
  • テーブル一覧、テーブル定義それぞれ日本語名称を表示できる
  • 簡単なSelect SQLを作ってくれる

ソースは以下のとおり。

MarkupBuilder拡張クラス

#!/usr/bin/env groovy
import groovy.sql.*
import java.sql.ResultSet

/**
 * @author genzou
 */
class XhtmlBuilder extends groovy.xml.MarkupBuilder{
 
 def charset = "UTF8"
 def lang = "ja"
 def title = ""
 def cssList = ["style.css"]
 
 public XhtmlBuilder(map, writer){
  super(writer)
  map.keySet().each{
   this."$it" = map."$it"
  }
 }
 
 def body = { closure ->
  delegate.print("""\n""")
  delegate.print("""\n""")
  html(lang:"${this.lang}", "xml:lang":"${this.lang}"){
   head(){
    meta("http-equiv":"Content-Type", content:"text/html;charset=${this.charset}")
    meta("http-equiv":"Content-Style-Type", content:"text/css;charset=${this.charset}")
    title("${this.title}")
    cssList.each{
     link(rel:"stylesheet", href:it)
    }
   }
   body closure
  }
 }
}

日本語名称マッパー

#!/usr/bin/env groovy

/**
 * @author genzou
 */
public class Mapper{
 // テーブルID(大文字)と日本語名称の対応を記述(IDがキー)
 public static def tables = [:]
 
 // カラムID(大文字)と日本語名称の対応を記述(IDがキー)
 public static def columns = [:]
 
}

メイン処理

#!/usr/bin/env groovy
import groovy.sql.*
import java.sql.ResultSet

def props = [
    user:"ゆーざーめい!"
    ,password:"ぱすわーど!"
] as Properties
def url = "JDBCのURL!"
def driver = "てきとうなどらいば!"

def dir = new File("entities")
if( !dir.exists() || dir.file )
    dir.mkdirs()

def gsql
try{
    gsql = Sql.newInstance(
        url
        ,props
        ,driver)

    def rs = gsql.connection.metaData.getColumns(null, props.user, "%", "%")

    def rows = []
    while(rs.next()){
        rows << rs.toRowResult()
    }
    rs.close()
    def entities = rows.groupBy{ it.TABLE_NAME }.findAll{ !(it.key =~ /.*BIN\$.*/) }
    println entities
   
    // 出力処理
    new File("$dir/index.html").withWriter("UTF8"){
        new XhtmlBuilder(it, title:"テーブル定義").body(){
            div(class:"container"){
                div(class:"left"){
                    h2("テーブル一覧")

                    table(){
                        tr(){
                            th "ID"
                            th "名称"
                        }

                        def i = 0
                        entities.keySet().sort().each{ tableName ->
                            tr('class':(i++%2)?"odd":""){
                                td(){
                                   
                                    a(href:"${tableName}.html", tableName)
                                }
                                td Mapper.tables[tableName]
                            }
                        }
                    }
                }
                div(class:"right"){
                }
            }
        }
    }

    entities.each{ entity ->
        def columns = entity.value
        new File("$dir/${entity.key}.html").withWriter("UTF8"){
            new XhtmlBuilder(it, title:"テーブル定義 - ${entity.key}").body(){
                div(class:"container"){
                    div(class:"left"){
                        h2("テーブル一覧")

                        table(){
                            tr(){
                                th "ID"
                                th "名称"
                            }

                            def i = 0
                            entities.keySet().sort().each{ tableName ->
                                tr('class':(i++%2)?"odd":""){
                                    td(){
                                       
                                        a(href:"${tableName}.html", tableName)
                                    }
                                    td Mapper.tables[tableName]
                                }
                            }
                        }
                    }
                    div(class:"right"){
                        h1 "テーブル定義"
                       
                        h2 "ID"
                        p "${entity.key}"
                       
                        h2 "名称"
                        p "${Mapper.tables[entity.key]}"
                       
                        h2 "カラム情報"
                        table(){
                            tr(){
                                th "ID"
                                th "名称"
                                th "型"
                                th "サイズ"
                                th "NOT NULL"
                            }

                            def i = 0
                            columns.each{ column ->
                                tr('class':(i++%2)?"odd":""){
                                    td column.COLUMN_NAME
                                    td (Mapper.columns[column.COLUMN_NAME])
                                    td column.TYPE_NAME
                                    td (class:"num", column.COLUMN_SIZE)
                                    td (column.IS_NULLABLE?.toString())
                                }
                            }
                        }
                       
                        h2 "sql"
def sql = """\
    SELECT
        *
    FROM
        ${entity.key}
--    WHERE""" + columns.collect{ "\n--        " + it.COLUMN_NAME + " = '' " }.join("AND")
                        textarea(sql)
                    }
                }
            }
        }
    }
} finally {
    gsql?.close()
} 


new File("$dir/style.css").write("""\
div.container
{
    width:99%;
}

h2
{
    border:2px solid gray;
    border-left:10px solid gray;
    padding-left:20px;
}

body
{
    background-color:#fbfbfb;
}

div.left
{
    float:left;
    width:30%;
    border-right:2px double gray;
    padding-right:0;
    margin-right:5px;
    height:800px;
    overflow:scroll;
}

div.left table
{
    font-size:75%;
}

div.right
{
    width: 65%;
    float:left;
}

div.right p
{
    padding-left:40px;
}

div.left td
{
    word-break:break-all;
    word-wrap:break-word;
}

div.right th,div.right td
{
    white-space:nowrap;
}

table
{
    width:90%;
    border:2px solid gray;
    border-collapse:collapse;
    margin:1px auto;
}

tr th
{
    background:#d7dbff;
}

th,td
{
    border-bottom:1px solid #c5cfc8;
    border-left:1px solid #e5eff8;
    padding:1px;
}

tr.odd td
{
    background:#f7fbe0;
}
textarea{
    width: 450px;
    height:200px;
} """, "UTF8")

結構長くなってしまった。

わからなかったこと1

MarkupBuilderの拡張クラスとしてXhtmlBuilderというクラスを作成したけれども、bodyというクロージャを作成しそいつを呼び出したときにbuilder処理が行われる作りにしたけれども、bodyではなく任意のメソッド名でも実行されるようにしたかった。

わからなかったこと2

index.htmlとエンティティ名.htmlの両方で、左側のテーブル一覧出力処理は同じにも関わらず、同一の処理を記述している。

ここをうまいこと共通化できないものかなぁ。

作ってみてよかったこと

すごくビルダーの勉強になった。

ちなみにアンカー出力の処理は以下のような記述方法があるみたい。

  • a(href:"url"){ yield "テキスト" }
  • a(href:"url", "テキスト")

いずれも<a href="url">テキスト</a>になるぽい。

0 件のコメント:

コメントを投稿