liftでmysql

最近おうちではscala+liftにお熱あげてます。もともとjava畑だったので入り易かったってのもあるかもしれない。でliftなんですけどderbyっていう要は懐かしのHSQLっぽいDBがデフォルトらしい。
なので最近仲良しなMySQLで動かす方法をせっかくなのでメモっておく。
http://wiki.liftweb.net/index.php/HowTo_configure_lift_with_MySQL
といってもこのページに書いてある通りなんですが。スーパーpre記法がscalaに対応したらしい記念に。。。

LIFTROOT/src/main/scala/bootstrap/liftweb/Boot.scala

object DBVendor extends ConnectionManager {
 def newConnection(name: ConnectionIdentifier): Box[Connection] = {
   try {
     Class.forName("com.mysql.jdbc.Driver")
     val dm = DriverManager.getConnection("jdbc:mysql://localhost/name-of-your-database?user=#user#&password=#password#")
     Full(dm)
   } catch {
     case e : Exception => e.printStackTrace; Empty
   }
 }
 def releaseConnection(conn: Connection) {conn.close}
}

Boot.scalaをこんな感じにすればいいらしい。
なんてことはない。普通にjdbcドライバでconnection作ってるのかと懐かしくなった。
てことはmaven2でドライバひっぱってくるのかなと思ったら案の定。
というかさっきのリンクの上部に書いてあるね。

pom.xmlに依存するアイテムとして追加してあげる

<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>5.0.8</version>
</dependency>

NOTE: The version namespace: 5.0.8 is for the myql-connector-java NOT your MySQL version number.

と書いてある通り慣れてる人ならなんてことないんだろうけどMySQLのバージョンじゃなくてドライバのバージョンですよ。とのこと。
どうでもいいけどmyqlになってるね。引用元。
http://dev.mysql.com/downloads/connector/j/5.0.html
一応調べてみたら5.0系は書いてある通り5.0.8が最新みたい。

http://blog.takeda-soft.jp/blog/show/355
あと、Boot.scalaの記述がベタでよろしくないのでxmlとかの外部ファイル化できないかなと思って調べてたらlift1.1系からは.propsファイルで指定するようになるみたい。この拡張子も懐かしい。ありがとう武田ソフトさん。そして後発で同じ事書いてるなわたくし。
と、こんなこと書いてるけどまだまともにCRUD書いてないんだな。
今週中の宿題にしよう。

group_concat 問い合わせ結果を配列化

厳密には配列では全然ない。
久々にお仕事でプログラマぶるなお仕事を。
MySQLで他システム連携用にviewを定義していたんだけど
あるテーブルのカラムをグルーピングしてカンマ区切りの文字列としてviewに収めたい。
楽にできないかなぁと思って少し調べたらgroup_concatに遭遇。

http://dev.mysql.com/doc/refman/4.1/ja/group-by-functions.html

GROUP_CONCAT([DISTINCT] expr [,expr ...]
[ORDER BY {unsigned_integer | col_name | formula} [ASC | DESC] [,col ...]]
[SEPARATOR str_val])

要するにこんなテーブルがあった場合

table drinking
name  order
山田   ビール
岡田   ビール
佐藤   カシスウーロン
鈴木   梅酒
山田   ビール
鈴木   黒糖梅酒
岡田   ライムサワー
佐藤   ウーロン茶
山田   ビール
岡田   日本酒

以下のSQL文を投げると

select name ,group_concat(order SEPARATOR '>') from drinking group by name;

こんな結果に。

山田  ビール>ビール>ビール
岡田  ビール>ライムサワー>日本酒
佐藤  カシスウーロン>ウーロン茶
鈴木  梅酒>黒糖梅酒

これだと山田はビールばっかだなとか一瞥して分かる感じです。
もっとも有用な使い方かどうかは別ですが。
複雑なクエリーを投げる回避策としてview作成時に利用したり
セパレータをカンマにすることでクエリーを受け取る言語側での配列作成等が楽になったりとか
結構重宝しますね。

MAC vmwareFusionにubuntu8.10

8.10だとapt-getでRUBY1.8.7が入るってことなので
ロングサポートじゃないけど今のお仕事で1.8.7を使う事になったので
併せて環境を作っておこうかなと。
8.04だとubunutuの日本語ページにvmware用の仮想イメージが
あるんだけどそっちから入れて、8.10にアップグレードしたら
なんだかよくわからないけどネットワークをうまく認識しなくなった。。。
頑張ったけど駄目だったので、
8.10のisoファイルから構築する事にした。

fusionのセットアップとOSの入れ方はこっちから
http://d.hatena.ne.jp/wadap/20080706/1215323979
http://d.hatena.ne.jp/wadap/20080720/1216541500

手抜きですんません。

namespaceありのXMLをDataGridで表示する

ちょいとamazonのecsを使って軽くDataGridで表示しようと思ったのだが、e4xで受けた結果をキチンとXMLList形式でdataProviderに渡しても表示できない。つーか2段階でつまづいた。


まずはe4xでのnamespaceの扱い。HTTPServiceでe4xで受けたresultからxmlを正常に取得できない。名前空間はその中で使われる変数へのアクセスを制限するためparseする?オブジェクト側でしっかりnamespaceを関連付けてあげないといけない・・・らしい。


Amazon Web ServiceをActionScript3.0から利用する方法


次、DataGridのdataFieldプロパティは、名前空間付きのXMLオブジェクトは、そのままではうまく扱えない・・・らしい。labelFunctionを使用して一度、グリッドに関連づけたデータを取り出し名前解決して要素を取り出して値をセットしてあげるとできた。


Flex User Group-XMLの参照


後はamazonが返すXMLがかなり動的(例えばAuthorノードは著者の数だけあるとか)でノードも深いので色々面倒・・・。

今日の成果。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:net="flash.net.*" layout="vertical">

	<mx:Script>
		<![CDATA[
			import mx.controls.Image;
			import mx.controls.Alert;
			import mx.managers.CursorManager;
			import mx.rpc.events.FaultEvent;
			import mx.rpc.events.ResultEvent;
			var itempage:int = 1;
			default xml namespace = new Namespace("http://webservices.amazon.com/AWSECommerceService/2007-10-29");
 
			private function search():void{
				var param:Object = new Object();
				param.Service = "AWSECommerceService";
				param.AWSAccessKeyId = "取得したID";
				param.Operation = "ItemSearch";
				param.SearchIndex = "Books";
				param.ItemPage = itempage;
				param.ResponseGroup = "Medium";
				param.Version  = "2007-10-29";


				param.Keywords = searchText.text;
				
				amazonWebService.send(param);
				
				CursorManager.setBusyCursor();
				enabled = false;
				
			}
			
			private function searchResult(event:ResultEvent):void{
				CursorManager.removeBusyCursor();
				enabled = true;
			    
                var xml:XML = event.target.lastResult as XML;
                var list:XMLList = xml..Item;
                resultDataGrid.dataProvider = list;
//				resultDataGrid.dataProvider = event.result.Items;
				trace(list.toString());
			}
			
			private function searchFault(event:FaultEvent):void{
				CursorManager.removeBusyCursor();
				enabled = true;

				Alert.show(event.message.toString());
			}
              private function genericLabelFunction(dgcXML:Object,dcg:DataGridColumn):String {
                    var currentItem:XML = XML(dgcXML);
                    var ns:Namespace = currentItem.namespace();
                    trace("test "+ dcg.dataField);
                    var displayValue:String = currentItem.ns::[dcg.dataField];
                    return displayValue;
                } 
              private function attLabelFunction(dgcXML:Object,dcg:DataGridColumn):String {
                    var currentItem:XML = XML(dgcXML);
                    var ns:Namespace = currentItem.namespace();
                    trace("test "+ dcg.dataField);
                    
                    var displayValue:String = ""
                    for each(var node:XML in currentItem.ns::ItemAttributes.ns::[dcg.dataField]){
                    	if(displayValue.length != 0){
                    		displayValue +=",";
                    	}
                    	displayValue = displayValue +  node.toString();
                    }
                    return displayValue;
                } 
              private function imageLabelFunction(dgcXML:Object,dcg:DataGridColumn):String {
                    var currentItem:XML = XML(dgcXML);
                    var ns:Namespace = currentItem.namespace();
                    trace("test "+ dcg.dataField);
                    var displayValue:String = currentItem.ns::MediumImage.ns::[dcg.dataField];
                    return displayValue;
              }
		]]>
	</mx:Script>
	
	<mx:HTTPService id="amazonWebService" 
		url="http://webservices.amazon.co.jp/onca/xml" 
		result="searchResult(event)" 
		fault="searchFault(event)"
		resultFormat="e4x" />

	<mx:Panel width="800" height="100%" layout="vertical" >
		<mx:HBox>
			<mx:TextInput id="searchText"/>
			<mx:Button label="アマゾる" id="searchButton" click="search()"/>
		</mx:HBox>

		<mx:DataGrid  width="100%" height="100%" rowHeight="160" id="resultDataGrid" enabled="true">
			<mx:columns>
				<mx:DataGridColumn width="120"  dataField="URL" labelFunction="imageLabelFunction" headerText="image" itemRenderer="{new ClassFactory(Image)}" />
				<mx:DataGridColumn dataField="Title" labelFunction="attLabelFunction" headerText="タイトル"/>
				<mx:DataGridColumn dataField="Author" labelFunction="attLabelFunction" headerText="著者"/>
				<mx:DataGridColumn dataField="Label" labelFunction="attLabelFunction" headerText="出版社"/>
			</mx:columns>
		</mx:DataGrid>
	</mx:Panel>
</mx:Application>

ちなみにmxmlってスーパーpre記法に何を指定すれば一番見やすいんだろう??

PHPでproxy経由でHTTPコンテンツを取得する

pear HTTP_CLIENTのインストールが必要

<?php
require_once("HTTP/Client.php");
$client =& new HTTP_Client(array(
    'proxy_host' => "192.168.1.12", // proxy ホスト
    'proxy_port' => "8080", // proxy ポート(省略時 8080)
//    'proxy_user' => $user, // proxy の認証ユーザ名(省略時認証なし)
//    'proxy_pass' => $pass // proxy の認証パスワード(省略可)
));
$contents = $client->get($_POST["uri"]);
$response = $client->currentResponse();

echo $response["body"];
?>

ポストのuriというパラメータで取得したいアドレスを渡す。
これを使えばcrossdomain.xmlの問題とか回避できたりする。