tag:blogger.com,1999:blog-54290982462629623402024-03-13T12:34:10.113+09:00nabedge blogNEW BLOG IS HERE ! http://nabedge.mixer2.orgnabedgehttp://www.blogger.com/profile/15249139606699432144noreply@blogger.comBlogger73125tag:blogger.com,1999:blog-5429098246262962340.post-33753489805577881192016-02-13T17:37:00.001+09:002016-02-13T17:37:37.971+09:00This blog has been moved. 移転しました<p style="font-size:x-large;">
This blog has been moved. <a href="http://nabedge.mixer2.org">NEW BLOG IS HERE</a>
</p>
<p>移転しました</p>nabedgehttp://www.blogger.com/profile/15249139606699432144noreply@blogger.com0tag:blogger.com,1999:blog-5429098246262962340.post-77861447595995928422015-12-21T22:14:00.001+09:002016-01-05T21:44:08.304+09:00「mavenと書いて達人と読む」という勉強会を4日連続でやった話<p>
このエントリは<a href="http://qiita.com/advent-calendar/2015/java">Java アドベントカレンダー 2015</a>の20日目となります。
ただし今日は12月21日です。<a href="http://qiita.com/n_slender/items/d9f88085091fc9addc89">21日目のエントリ</a>がもう公開されているというレベルです。ごめんなさいごめんなさいごめんなさい。
</p>
<p>
さて、年末年始を前にして何か大きな機能追加とかリリースとかやって「やらかして」しまうとクリスマスも正月もドナドナになってしまうのを避けるために、
この時期はあまり大きな仕事はしないことになっております。そういうスキマ時間にしかできないことを少しやってみようと思いまして、
<a href="http://www.bizreach.co.jp/recruit/">職場</a>のエンジニアを集めてmavenの勉強会をやってみました。題して「mavenと書いて達人と読む」。
</p>
<blockquote>
<a href="http://2.bp.blogspot.com/-Y8lKv2RzFMA/VnfxwbVqVpI/AAAAAAAACRI/XvG3Fsv3ArA/s1600/maven-tatsujin-201512.jpg" imageanchor="1" ><img border="0" src="http://2.bp.blogspot.com/-Y8lKv2RzFMA/VnfxwbVqVpI/AAAAAAAACRI/XvG3Fsv3ArA/s320/maven-tatsujin-201512.jpg" /></a>
</blockquote>
<p>
夕方に30分 x 4日連続。講師は全部自分。はい。2日目で力つきそうになって、4日シリーズにしたことを後悔しましたw。
そもそも自分自身だって達人にはほど遠いのですが、
<a href="http://www.slideshare.net/sogdice/java8jjug-ccc-2015-fall">プロジェクトの中でpom.xmlのメンテをやる人が限られてしまうとこうなる</a>みたいなことがあったので、
やっぱり経験の浅い若手相手に座学っぽくやるのも時には必要なんだなーと思いました。
なお、いまどきgradleでしょ!とか言う話はスルーです。セントラルリポジトリのお世話になったことがないという者だけがmavenに石を投げなさい。
</p>
<p>
そんなわけで、以下、メモです。
</p>
<h3>1日目 maven標準ディレクトリ構造と基本コマンド</h3>
<ol>
<li>ソースコードを動作可能な状態にまで変換することをビルドという。これはスクリプト言語でもコンパイル言語でも変わらない。コンパイル言語の場合にはビルドにはコンパイルという工程が含まれる。ビルドを支援するのがビルドツール。かつてはant、いまはmavenかgradle.</li>
<li>IDE使わずにエディタだけでsrc/main/java/HelloWorld.javaとpom.xmlをつくる</li>
<li>compile, exec:java, package, install など一通りたたいてみる</li>
<li>教科書にあるようなjavac HelloWorld.javaもやってみて、なにがどこにどう生成されるのか、比較してみる</li>
<li>src/main/java, src/main/resources, src/test/java, src/test/resources というシンプルかつ機能的なディレクトリ構造と、依存関係の自動解決というのがmavenの最大の功績。</li>
<li>他のビルドツールを使っていても、結局 src/main/java みたいな構造は一緒であることが多い。</li>
<li>ls ~/.m2/repository してみる。このディレクトリは何なのだろう?は次回以降のお楽しみ。</li>
</ol>
<h3>2日目 依存関係の自動解決、リポジトリという概念</h3>
<ol>
<li>System.out.println("Hello World") のところをlog.info("...")に書き換える。当然まだコンパイルはできない。</li>
<li>このときpomのdependencyにcommons-loggingを追加。mvn compileができるようになる。</li>
<li>HelloWorldというクラスはorg.apache.commons.logging.Logというクラスに「依存している」同様にhelloというartifact(プロジェクト)はcommons-loggingというartifactに「依存している」依存関係をdependencyタグで表す。</li>
<li>ちなみにjavacでやろうとすると javac -claspath "~/.m2/repository/commons-logging/commons-logging/1.1.1/commons-loggin-1.1.1.jar" src/main/java/HelloWorld.java みたいにすればコンパイルできる</li>
<li>コンパイルのときや実行のときにクラスパスをいい感じにやっておいてくれるのがmavenのいいところ。それが依存関係の自動解決。</li>
<li>リポジトリにはローカルとリモートの2種類がある。~/.m2/repositoryがローカル。リモートリポジトリのキャッシュみたいな役割になる(それだけじゃないけど)</li>
<li>mvn help:effective-pom ってやるとセントラルリポジトリのurlがわかるよ。そのurlをブラウザで見てみると。。。</li>
<li>mvn dependency:tree</li>
<li>リモートリポジトリは誰でも立てられる。公開してもいいし、非公開ならインハウスリポジトリってことになる。ex. <a href="http://repository.apache.org">http://repository.apache.org</a> </li>
</ol>
<h3>3日目 推移的な依存関係とビルドライフサイクル</h3>
<p>※この日は疲れていたので内容が薄いw</p>
<ol>
<li>spring-boot-starterとか使って簡単なpom.xmlを作っただけなのにWebアプリがいきなりできあがるマジック</li>
<li>mvn dependency:tree するとすごい数のjar(artifact)がツリー上に見える。これが「推移的」な依存関係。</li>
<li><a href="https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html">ビルドライフサイクル</a>というものがある</li>
</ol>
<h3>4日目 マルチプロジェクト構造</h3>
<ol>
<li>packagingというところにはpom, jar, war みたいな種類を書く。Project Object Model, Java Application Archive, Web Application Archive...</li>
<li>たまにearというやつもあってだな、Enterprise...と口に出した瞬間からjarを含んだwarを複数含んだのがearでWebLogicだかなんだかで動いて起動に15分とかかかってもうねアホか..トラウマに襲われて取り乱すもなんとか平静を取り戻す</li>
<li>parentとmodulesというタグを使って親子関係を形作ることができる。普通のファイルシステムとディレクトリ構造と同じような感じになる。src/main/javaも含めて総合的にこれがmavenの標準ディレクトリ構造。</li>
<li>なお、依存関係(dependency)と親子関係(parent,module)は似て非なる概念なのでご注意。</li>
<li>parentタグにrelativePathを指定して強制的にフラットなディレクトリ構造にしてしまう手法がよく取られる。これはEclipseの制約という歴史的な事情がある。</li>
<li>IntelliJなど、設計思想の段階でビルドツールの存在を前提にしたIDEが台頭してきたおかげで、本来のmaven標準ディレクトリ構造を生かせるようになった。</li>
<li>だからIntelliJ IDEA Ultimateを買う予算をちゃんと引き当ててください。(※実際、買うことになってる)</li>
</ol>
<p>
そろそろ風呂に入って寝たいのでこのへんで。明日はn_slenderさんによる<a href="http://qiita.com/n_slender/items/d9f88085091fc9addc89">PlayFramework 2.4 Java Ebeanでのアプリ開発</a>です!お楽しみに!
</p>
nabedgehttp://www.blogger.com/profile/15249139606699432144noreply@blogger.com0tag:blogger.com,1999:blog-5429098246262962340.post-25504416276972932202015-12-12T16:50:00.000+09:002015-12-12T17:06:45.707+09:00乾杯から始まるSpringFramework入門に顔出してきた<p>
自分とこではSpringは長く使っているので入門ということではないのですが、
「乾杯から始まる」という何気ないその一言にいたく感動しw、行ってきました。
横浜みなとみらいとか久しぶりだったなー。
</p>
<blockquote>
<a href="http://tagbar.connpass.com/event/23448/">乾杯からはじまるSpringFramework入門 (connpass.com)</a>
</blockquote>
<p>
タグバンガーズさんのことは存じませんでしたが、
Java/Springでゴリゴリと仕事する若々しいエンジニア集団(しかもWeb系)って、
いるところにはちゃんといるんだなと再認識しました。
小川さんという方と名刺を交換させていただいたときはどちらの陶芸家の先生だろうなどと思っていたら社長さんでした。
その小川さんが<s>ろくろをまわし始め</s>IntelliJ IDEAでSpringBootフレームワークからのHibernateのEntity作ってからDDL自動生成からので高速コーディングを見せてくれました。
その間私はハイネケン3本を飲み干しておりました。本当にごちそうさまでした。
</p>
<p>
繰り返しになりますが、RoRとかPHPとかが人気の昨今ですが
Java/SpringでゴリゴリWeb系システムつくってる人たちってちゃんといるし、
そこそこ儲かっているんだなと思うとなんだかとても親近感を覚えました。
</p>
<p>
そのまま実家に帰る用事があったので懇親会のあとすぐおいとましました。
次の機会にはぜひ<a href="http://d-cube.connpass.com/">渋谷の自分ところの勉強会</a>かピザパーティにでも顔出していただいて、
なんなら講師としてSpringをご教示いただけたらな、なんて他力本願なことを思いながらクリスマスの華やかなみなとみらいを後にしました。
</p>
<p>
タグバンガーズの皆様、ありがとうございました。小川さん、陶芸家とか書いちゃってすみません。今日も実家で昼酒飲んで酔っているので多めにみてください。
お会いしたSIerの戦士の方々、いろいろお話できてうれしかったです。
私も元SIerですが、<a href="https://jp.stanby.com/ats/bizreach/jobs/20004">Web系の事業会社のエンジニア</a>も、楽しいですよ。
</p>
<p>追記</p>
<p>
名刺入れに小川さんの名刺が無いぞ、はて??と思ったら、勉強会の机の上に名刺を何枚か置いたままだったことを、たったいま思い出しました。
ぐぬぬ。社会人としてあるまじき失礼なことを!!ごめんなさいごめんなさいマジごめんなさい。
</p>
nabedgehttp://www.blogger.com/profile/15249139606699432144noreply@blogger.com0tag:blogger.com,1999:blog-5429098246262962340.post-80132965543833798092015-11-29T13:35:00.000+09:002015-11-29T13:37:08.709+09:00JJUG CCC 2015 Fallに行ってきました<p>
昨日、<a href="http://www.java-users.jp/?page_id=2056">日本Javaユーザーズグループ クロスコミュニティカンファレンス 2015 Fall</a>に行ってきました。
今回も記録更新の参加者数だったそうです。
</p>
<p>
自社のスポンサーセッションとして自分の後輩君が「Java8移行から始めた技術的負債との戦い」と題して登壇しましたので見届けてきました。
</p>
<iframe src="//www.slideshare.net/slideshow/embed_code/key/zOMk8TnrIlBSPD" width="595" height="485" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe> <div style="margin-bottom:5px"> <strong> <a href="//www.slideshare.net/sogdice/java8jjug-ccc-2015-fall" title="Java8移行から始めた技術的負債との戦い(jjug ccc 2015 fall)" target="_blank">Java8移行から始めた技術的負債との戦い(jjug ccc 2015 fall)</a> </strong> from <strong><a href="//www.slideshare.net/sogdice" target="_blank">sogdice</a></strong> </div>
<p>
驚いたことに160人の部屋が満室で立ち見続出。席の間の通路に座り見までしてもらって、それでも入りきらないという状況でした。
Java8移行とか技術的負債とか、どこの現場のエンジニアも一様に悩んでいるがゆえの切実な需要があったということなのでしょう。
</p>
<p>
個人的には 「GH-5 サーバサイドのビュー処理エンジンForneusの開発秘話」というセッションが興味深かったです。
<a href="http://mixer2.org">Mixer2</a>というテンプレートエンジンを作っている自分としては、
登壇者の井上さんが語るJavaのテンプレートエンジンに関する問題意識には非常に納得というか
「ああみんな同じようなこと考えているんだなあ」という意味においてなんだか不思議な安心感と親近感を覚えました。
</p>
<p>
最後に聴講したのは「GH-7 てらだよしおの赤裸々タイム」。
日本におけるJava言語の啓蒙者というかスポークスマン的な存在のてらだよしおさんが
サンマイクロシステムズからオラクル(買収)、そして驚きのマイクロソフトへの転職から数ヶ月たったいま、
なかなか楽しいセキララトークを聞くことができました。
</p>
<p>
転職サイトの開発に携わるエンジニアとしてこれは質問のひとつもしておかねばなるまいと、最後にマイクをお借りしました。
</p>
<blockquote>
「寺田さんがオラクルからMSに転職するために転職サイトを使ったということはないでしょうが、
しかしこの会場の大多数の人は寺田さんほどの知名度はありません。
それでもなお新天地を求めて動くべきときが誰にでも来る可能性があります。
採用する側もエンジニアが欲しいから採用しています。
採用する側、採用される側、それぞれは、なにを考え、なにを問いかけ、なにを準備するべきなのでしょうか?」
</blockquote>
<p>
そんなぼんやりとした私からの問いかけにも、寺田さんは的確に返してくれました。
</p>
<blockquote>
なんでもできるオールマイティな人よりも、(採用される側は)何か一つだけでも強いもの尖ったものを持つことが大事で、(採用する側は)そうした人間のヨコの繋がりを強化していくような形がいいんじゃないか。
</blockquote>
<p>
たしかそんな趣旨のことをこたえてくださいました。
</p>
<blockquote class="twitter-tweet" lang="ja"><p lang="ja" dir="ltr">この質問、これからのわたしのキャリアを考える上ですごく参考になる <a href="https://twitter.com/hashtag/ccc_gh7?src=hash">#ccc_gh7</a> <a href="https://twitter.com/hashtag/jjug_ccc?src=hash">#jjug_ccc</a></p>— Dahlia* (@dahlia_cocoa) <a href="https://twitter.com/dahlia_cocoa/status/670554903866032128">2015, 11月 28</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>
と言ってくれる聴講者の方もいらっしゃったようで、お役に立ててなによりです。
</p>
<p>
なお、じつは質問の手を挙げたときは
</p>
<blockquote class="twitter-tweet" lang="ja"><p lang="ja" dir="ltr">赤い会社とMSとで年収はどのくらい、、、げふんげふん <a href="https://twitter.com/hashtag/jjug_ccc?src=hash">#jjug_ccc</a> <a href="https://twitter.com/hashtag/ccc_gh7?src=hash">#ccc_gh7</a></p>— なべさん (@nabedge) <a href="https://twitter.com/nabedge/status/670553080597905408">2015, 11月 28</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>
という趣旨の質問をしようとしてマイクをもらってからオトナのブレーキがかかって1.5秒のアドリブでこの質問をひねり出した自分をあらためてほめてあげたい日曜日の昼下がりです。
</p>
nabedgehttp://www.blogger.com/profile/15249139606699432144noreply@blogger.com0tag:blogger.com,1999:blog-5429098246262962340.post-49374673646915142512015-11-23T14:38:00.002+09:002015-11-23T14:38:18.222+09:00マイナンバーのチェックデジットを検証するJavaライブラリ"jpn-mynumber"<p>
ソースはgithubに。バイナリとjavadocはmavenセントラルリポジトリに登録済みです。
個人番号と法人番号の両方に対応。
詳しくは <a href="https://github.com/nabedge/jpn-mynumber">https://github.com/nabedge/jpn-mynumber</a> からどうぞ。
</p>
nabedgehttp://www.blogger.com/profile/15249139606699432144noreply@blogger.com0tag:blogger.com,1999:blog-5429098246262962340.post-18962551927568034082015-11-17T12:06:00.001+09:002015-11-17T12:07:19.654+09:00Mixer2 1.3.1をリリース TagTypeUnmatchExceptionは非チェック例外になりました<p>
うっかり薄着で夜更かししてコード書いてたら見事に風邪引いたのか、強烈な頭痛に襲われまくりの秋の朝。
どうにか落ち着いたので、ブログでも更新します。そういえば半年も放置してしまってた。
</p>
<p>
<a href="http://mixer2.org/">Mixer2</a>の1.2.41と1.3.1 をリリースしました。これにて1.2系統は打ち止めとします。
</p>
<p>
まず、html5の<main></main>タグのサポートを追加しました。これは1.2.41と1.3.1の両方です。
今頃mainタグ?って感じですが、Mixer2にHTML5対応実装を最初に追加したのが2012年ごろで、このころはmainタグはまだ勧告候補にすらなっていない、拡張仕様扱いだったのです。今となっては若干記憶があやふやですが、その後もちょこちょこ属性の追加の対応などには追随していたものの、mainタグだけすっぽり抜けて忘れていました(笑)
</p>
<p>
あと、1.3系統ではTagTypeUnmatchException を非チェック例外(extends RuntimeException)にすることにしました。
この例外はたとえばulタグの中にliではなくdivを直接つっこもうとすると発生するやつです。
Java8の時代になって、Lambda式の中での例外の取り回しがかえって難しくなるケースがあることから、思い切って非チェック例外に切り替えることにしました。
だからマイナーバージョン番号も1.3にup。
</p>
<p>
さて、天気がいいので散歩して飯食って仕事しますかね。
</p>
nabedgehttp://www.blogger.com/profile/15249139606699432144noreply@blogger.com0tag:blogger.com,1999:blog-5429098246262962340.post-18897941249664508632015-05-04T13:48:00.001+09:002015-05-05T10:54:31.956+09:00Mixer2 1.2.36 リリース。replaceInner()でタグの中身を一発で置換<p>
先月、Mixer2 1.2.36 をリリースしてました。<a href="http://mixer2.org">http://mixer2.org</a>
目玉はreplaceInner()メソッドで、これはhtmlタグの中身を一発で置換します。
</p>
<h4>Before</h4>
<pre class="brush:java">
Html html = m2e.loadHtmlTemplate(new File("HelloWorld.html"));
html.getById("hellomsg", Div.class).unsetContent();
html.getById("hellomsg", Div.class).getContent().add("Hello World !");
</pre>
<h4>After</h4>
<pre class="brush:java">
Html html = m2e.loadHtmlTemplate(new File("HelloWorld.html"));
html.getById("hellomsg",Div.class).replaceInner("Hello World !");
</pre>
<p>
こんな基本的なことっぽいメソッドを今まで用意していなかった理由は語ると長くって、、まあ要するにJAXB-api周りの取り回しで結構面倒なワナがあったからなのですが、
どうにかねじふせました。リリース直後のバグとりを手伝ってくださった @fjut さんに感謝です!
</p>
nabedgehttp://www.blogger.com/profile/15249139606699432144noreply@blogger.com0tag:blogger.com,1999:blog-5429098246262962340.post-24848449099151394802015-03-22T17:30:00.001+09:002015-03-24T18:29:57.256+09:00java.ext.dirsは廃止の方向だそうです<p>
今月初めの <a href="http://shibuya-java.connpass.com/event/11574/">第10回#渋谷Java</a>で久しぶりに登壇してトークしたのですが、その内容が実は大嘘でしたという話です。
</p>
<p>資料がこれ。</p>
<iframe src="//www.slideshare.net/slideshow/embed_code/45542440" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe> <div style="margin-bottom:5px"> <strong> <a href="//www.slideshare.net/nabedge/201503-java10-java" title="渋谷java−あなたのプロジェクトで気軽にjavaをバージョンアップするために必要なこと" target="_blank">渋谷java−あなたのプロジェクトで気軽にjavaをバージョンアップするために必要なこと</a> </strong> from <strong><a href="//www.slideshare.net/nabedge" target="_blank">nabedge Watanabe</a></strong> </div>
<p>かいつまんで言うと</p>
<ol>
<li>JREには拡張機能機構というのがもともとあって、</li>
<li>$JAVA_HOME/lib/ext (javaのシステムプロパティで言うとjava.ext.dirs)に自前のjarを置くと自動的にクラスパスに含まれるので</li>
<li>そういう形でアプリもJREもセットでサーバにデプロイするようにすればいろいろ設計する手間が省けて何かと幸せになれるかもね</li>
</ol>
<p>
という趣旨でした。
</p>
<h1>ところがぎっちょん</h1>
<p>
2015/3/3つまり第10回#渋谷Javaのたった三日前。Java8u40 がリリースされていました。まったく気にしていなかったのですが、
その<a href="https://www.java.com/ja/download/faq/release_changes.xml">リリースノート</a>には衝撃の内容が。
</p>
<blockquote>
推奨規格オーバーライド機構と拡張機能機構は非推奨であり、今後のリリースで削除される可能性があります。実行時の変更はありません。
「推奨規格オーバーライド」機構または「拡張機能」機構を使用している既存のアプリケーションは、
これらの機構を使用しないよう移行することをお薦めします。これらの機構を既存で使用しているかを識別するために、
-XX:+CheckEndorsedAndExtDirsコマンド行オプションを使用できます。次のいずれかの条件がtrueの場合、失敗します。
<ul>
<li>-Djava.endorsed.dirsまたは-Djava.ext.dirsシステム・プロパティがデフォルトの場所を変更するために設定されているか、</li>
<li>${java.home}/lib/endorsedディレクトリが存在するか、</li>
<li>${java.home}/lib/extにJDKに同梱されているファイル以外のJARファイルが含まれているか、</li>
<li>プラットフォーム固有のシステム全体の拡張ディレクトリにJARファイルが含まれている。</li>
</ul>
JDK 8u40以降のリリースで、-XX:+CheckEndorsedAndExtDirsコマンド行オプションがサポートされます。
</blockquote>
<p>
#渋谷javaの会場で「java1.4,5,6,7,8まである機能がそんな簡単に消えやしませんから安心して使っちゃいましょう!」って高らかに宣言した私の立場ナッシング。
</p>
<p>
詳しくは追ってないのですがどうやらJavaアプリケーションのパッケージング機構に関してJCEで別の議論が進んでいるようで、それにからんで古いほうの機構は削除の方向らしいです。
それにしても少なくともJava1.4以降ずっとあった機能が削除されようとは!しかもこのタイミングでw
</p>
<p>
そんなわけですが、開発したJavaアプリをJREとセットでデプロイしちゃおうぜというアイデアが実現不可能になったわけではまったくないので、普通にJREとアプリとをそれぞれサーバ上に展開し、java -classpath "自作のjarと依存jarの展開先dir/*" com.example.MyMain みたいな感じでclasspathをワイルドカード指定しちゃえばいいと思います。
</p>
nabedgehttp://www.blogger.com/profile/15249139606699432144noreply@blogger.com0tag:blogger.com,1999:blog-5429098246262962340.post-48467595018518180262015-01-18T23:00:00.000+09:002015-01-18T23:00:50.418+09:00去年の秋のJJUG-CCCで講演したら思ったより満足度高かったらしい<p>
もう年も明けて鏡開きも成人式も終わった今日この頃ですが、思い出したかのように、<a href="http://www.java-users.jp/?page_id=1290">去年の秋のJJUG-CCC Fall</a>で講演したときの聴講者アンケート結果が届きました。実際、中の人が次の3月のJJUG-CCC Springのセッションの公募を始めたついでに思い出したんだろうけど(笑)。
</p>
<p>
自分自身、あのあとすぐもう通常のお仕事に忙殺されていて、参加記とかそういうのをまったく書いていなかったことに気づいたので、超遅ればせながらなんか書きのこして置くことにします。
</p>
<p>
まず使った資料ですが、こちら。
</p>
<iframe src="//www.slideshare.net/slideshow/embed_code/41680066" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe> <div style="margin-bottom:5px"> <strong> <a href="//www.slideshare.net/nabedge/java-the-twelve-factor-app" title="Javaでやってみる The Twelve Factor App JJUG-CCC 2014 Fall 講演資料" target="_blank">Javaでやってみる The Twelve Factor App JJUG-CCC 2014 Fall 講演資料</a> </strong> from <strong><a href="//www.slideshare.net/nabedge" target="_blank">nabedge</a></strong> </div>
<p>
見ての通り、それほど難しい内容ではなかったんです。<a href="http://nabedge.blogspot.jp/2013/04/jjug-cccjsp-jaxbmixer2.html">JJUGで喋るのが初めてなわけじゃない</a>とはいえ、しかしやっぱり他のセッションではすんごい人がすんごいエッジの効いたディープな話とかしてるわけで、正直どうなのかなー、教室一杯に人がいたけどツマンネーと思われてたらしゃくだなーとかちょっぴり弱気になってる自分もおりました。
</p>
<p>
ところが、数時間ほど前に届いた参加者アンケート結果の集計によると、満足度はそこそこ高いほうに入っていたようで、我ながらびっくり。考えてみればそうですね、誰もがディープな話を聞きたいわけじゃない、少し現実味を帯びたくらいの話がちょうどいいということもあるのでしょう。
</p>
<p>
きっちり自社CMも入れておいたことだし(笑)、通常業務も年明けで一区切りついたことだし、3月のCall For Paperにもなんかネタ考えて応募してみる気力も出てきたところで、
「R1-5 JavaでやってみるThe Twelve Factor App」に足を運んでくださった皆様にあつく御礼申し上げますとともに、遅ればせながら新年のご挨拶にかえさせていただきます。本年もよろしくお願い申し上げます。
</p>nabedgehttp://www.blogger.com/profile/15249139606699432144noreply@blogger.com0tag:blogger.com,1999:blog-5429098246262962340.post-55870187628883026372014-09-23T22:06:00.002+09:002014-09-23T22:11:04.667+09:00Mixer2 1.2.34でのエンハンス(SpringMVC関連)<p>
今月、<a href="http://mixer2.org/">Mixer2</a>は実は2回リリースしてます。1.2.33と1.2.34。
1.2.33では一部のメソッドをprivateからprotectedにしたことで拡張、改造がしやすくなりました。
1.2.34ではSpringMVC用のAbstractなViewクラスを少し変更しています(下位互換性はありますのでご安心ください)。また、XMLStringUtilというユーティリティクラスを追加しています。
</p>
<p>
まず<a href="http://mixer2.org/site/apidocs/org/mixer2/util/XMLStringUtil.html">XMLStringUtil</a>。これはXHTML(XML)として有効な文字列かどうかを判別したり、無効な文字列を任意の文字(デフォルトだと空白ひとつ)で置換することができます。
<a href="http://www.w3.org/TR/REC-xml/#charsets">XMLで使用できる文字列はw3c.org上で厳密に決められています。</a>簡単に言うと、いわゆるUTF-8の範囲内の文字と、あとは改行、空白、タブ等のごく限られた制御コードのみということです。
XHTMLはXMLのサブセットですから右に同じということになり、Mixer2が使用しているJavaのJAXB実装もこれに厳密に従っています。そのため、妙な制御コード、たとえば改ページ制御コードがxhtmlテンプレート上に含まれていたり、あるいはそれをorg.mixer2.jaxb.xhtml.*配下のタグ型の内部にうっかり仕込もうとすると、saveToStringする段階で例外が発生してしまうことがあります。
<a href="http://mixer2.org/site/apidocs/org/mixer2/util/XMLStringUtil.html">XMLStringUtil</a>はその防波堤となるユーティリティです。
</p>
<p>
次に、SpringMVC用の抽象ビュークラスに新たに<a href="http://mixer2.org/site/apidocs/org/mixer2/spring/webmvc/AbstractMixer2XhtmlView.html#modifyHtmlStringHook%28java.lang.String%29">modifyHtmlStringHook</a>というメソッドを追加しました。
このメソッドは、Mixer2がhtmlオブジェクトをsaveToString()して文字列化したあとに呼ばれ、その後すぐhttp responseするようになっています。
</p>
<p>
デフォルトのままだとスルーパスするだけ(何もしない)ですが、Viewの実装クラス内でこのメソッドをオーバーライドすると、httpレスポンスされる直前のhtml文字列(Html型のインスタンスではなく)を直接操作できます。これによって、Mixer2ではできないこと、たとえばhtmlコメント等の埋め込みが可能です。
たとえば、HTML5未対応なIE8以下を擬似的にhtml5対応させるために、<a href="https://code.google.com/p/html5shiv/">html5.js</a>を使うことがあると思います。
しかし、公式サイトを見ての通り、これは
<pre><!--[if lt IE 9]><script src="dist/html5shiv.js"></script><![endif]--></pre>
のように、IE特有のコンディショナルコメントとして埋め込む必要があります。Mixer2はhtmlコメントを埋め込むことができない(あっても無視してしまう)ので、Mixer2付属のSpringMVC用のビュー/ビューリゾルバでは使用できませんでした。1.2.34以降では、modifyHtmlStringHook() をオーバーライドして、例えば</head>タグのあたりをString#replace()メソッド等を使って狙い撃ちにすれば、上記のコンディショナルコメントを追加することができます。
</p>
<p>
まだ公式マニュアルには実はどちらもまともに書いていません。そのうちちゃんと書かねば。
</p>
nabedgehttp://www.blogger.com/profile/15249139606699432144noreply@blogger.com0tag:blogger.com,1999:blog-5429098246262962340.post-78748724904456971922014-09-21T18:28:00.001+09:002014-09-21T18:32:23.578+09:00#渋谷java でしゃべってきた(@jfutさん、@seri_kさん、ありがとう!)<p>
第8回#渋谷Javaという勉強会で少しばかりしゃべってきました。
</p>
<ul>
<li><a href="http://shibuya-java.connpass.com/event/8212/">第八回 #渋谷java - connpass</a></li>
<li><a href="http://togetter.com/li/721801">第八回 #渋谷java まとめ - Togetterまとめ</a></li>
</ul>
<p>
自分の話した内容はさておき、まず必見なのがこちら。
</p>
<iframe src="//www.slideshare.net/slideshow/embed_code/39317462" width="427" height="356" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe> <div style="margin-bottom:5px"> <strong> <a href="https://www.slideshare.net/jfut/custom-templateengine-onmixer2" title="Mixer2 で作るカスタムテンプレートエンジン #渋谷java" target="_blank">Mixer2 で作るカスタムテンプレートエンジン #渋谷java</a> </strong> from <strong><a href="http://www.slideshare.net/jfut" target="_blank">Jun Futagawa</a></strong> </div>
<p>
<a href="http://mixer2.org">Mixer2</a>を使ってくれている@jfutさんに「なんかしゃべっていただけませんか?」とぶしつけにもお願いしたら、なんかすごいのを用意してLTしていただくことができました。感動です。
</p>
<p>
Mixer2に対する@jfutさんの捉え方というかアプローチはすごく真っ当で、そうなんですよ。Mixer2のAPIはわかりやすくかつ自由度が高いので、自分が必要なヘルパークラス的なものをガンガン作ってしまえば、自分の必要なものに合わせたテンプレート機構を作り上げることができるということです。
</p>
<p>
思えば、個人的にvelocityのマクロを作ったこともありますがなんだかクセがあって他人がメンテできる状態にしづらかったですし、だからといってjspのカスタムタグはなおさらテストを書きづらいわ一生懸命作ってもバッチ処理では使えないわw。
</p>
<p>
@jfutさんに一杯ごちそうしたいところでしたが、あいにく昨日は夜に別の予定をいれてしまっていたので挨拶だけしてお別れしました。(@jfutさん、またの機会に!)
</p>
<p>
一方自分は「QueryDSLとSpringDataでとりあえずCRUD」というテーマで話しました。パワポ資料無しサンプルコードのみのハードボイルドプレゼンで行くぜ!とか言ってたら、
Create(INSERT)とRead(SELECT)やっただけで時間切れでU,Dの話が出来ずじまいという体たらく。
はい、実は前日の暴飲暴食&飲み過ぎのせいで種々の準備と時間の読みとが間に合ってなかっただけですごめんなさいごめんなさいごめんなさい。
サンプルコードと簡単な使い方は公開しておりますのでご興味あるかたはお試しください。
</p>
<ul>
<li><a href="https://github.com/nabedge/querydsl-sample">https://github.com/nabedge/querydsl-sample</a>
</ul>
<p>
特に、多くの方のツッコミどころである「その手のDSLツールでは、selectの時にjoinってどうやるの?」というところまで話す間も無かったのが超反省点です。
とは言っても、コード見ればなんとなくわかるというレベルの話でしかないので、以下をご覧ください。
</p>
<ul>
<li><a href="https://github.com/nabedge/querydsl-sample/blob/master/querydsl-sample-core/src/test/java/com/example/ReadTest2.java#L63">fromとwhereで結合するサンプル</a></li>
<li><a href="https://github.com/nabedge/querydsl-sample/blob/master/querydsl-sample-core/src/test/java/com/example/ReadTest2.java#L84">join句で結合するサンプル</a></li>
</ul>
<p>
最後になりましたが、@seri_kさんがちかぢか東京を離れるため。必然的に#渋谷javaの運営からも距離を置かざるを得ないことになりました。(#渋谷javaは別の有志によってこれまで通り存続します)
初期の立ち上げ、そして1年あまりの運営、本当にありがとうございました。@seri_kさんに、心から感謝と敬意を表します。
</p>
nabedgehttp://www.blogger.com/profile/15249139606699432144noreply@blogger.com0tag:blogger.com,1999:blog-5429098246262962340.post-14711097373572186892014-06-12T22:33:00.000+09:002014-06-12T22:33:04.721+09:00Mixer2 1.2.32 released.<p>
Mixer2 1.2.32 リリースしました。<a href="http://mixer2.org">mixer2.org</a>
</p>
<ul>
<li>タグのremove機能(プルリク感謝)。これはid属性等が無いタグであってもきれいに消しちゃう機能です。いままでそういう削除機能がなかったということではないのですが。(表現が難しいな...)</li>
<li>SpringMVC用のビューリゾルバクラスに、ビュー名に合わせたビュークラスが存在しない場合に例外発生させる/させないの設定オプションを追加しました。</li>
</ul>
<p>
なお、mixer2は独立したxhtml専用のテンプレートエンジンであって、SpringMVCとの組み合わせ専用ということは無いです。念のため。
</p>
nabedgehttp://www.blogger.com/profile/15249139606699432144noreply@blogger.com0tag:blogger.com,1999:blog-5429098246262962340.post-47834328987034291462014-05-24T09:27:00.001+09:002014-06-05T14:18:15.452+09:00あなたのapacheのBasic認証をgoogle 2段階認証に対応させるには<p>
<a href="http://www.google.com/landing/2step/">Googleの2要素認証</a>ですが、数年前のリリース以来、少しずつ普及しているようです。
</p>
<a href="http://1.bp.blogspot.com/-Ns5AdsXCZdk/U3_sgFkQfNI/AAAAAAAAAy0/nHZPuP7Sjp0/s1600/201405-google-auth-screenshot.png" imageanchor="1" ><img border="0" src="http://1.bp.blogspot.com/-Ns5AdsXCZdk/U3_sgFkQfNI/AAAAAAAAAy0/nHZPuP7Sjp0/s1600/201405-google-auth-screenshot.png" /></a>
<p>
ただ、googleのサービス=例えばgmailとか=でしか使えないし、あるいは自分のwebサービスに導入するにはgoogle様に何らかのお布施をしなければならないんでしょ...と思っているあなた!
それは単なる思い込みや誤解です。
</p>
<h3>目標</h3>
<ol>
<li>自分が管理するapache上のコンテンツの一部に認証をかけたいとして、</li>
<li>ユーザー名がfooでパスワードがbarだとする。</li>
<li>導入が比較的お手軽なBasic認証ですませたい。</li>
<li>ただしgoogle2要素認証も使う。スマホのアプリでワンタイムパスワード(以下OTP)を受け取るやつ。</li>
<li>ブラウザ上に出現するbasic認証のダイアログには、アカウントとしてfoo、パスワードとしてbar+OTPを入力する。例えばOTPが123456であればパスワードとして"bar123456"で認証できるようにする</li>
</ol>
<h3>用意するもの</h3>
<ul>
<li>linuxマシン。以下の例ではOracleVirtualBox+Vagrantで構築したCentOS6.5を使用(もっと古いディストリでも大丈夫)</li>
<li>スマートフォン。android,iphoneどっちでも。</li>
</ul>
<h3>手順</h3>
<p>
まず、スマホにGoogle認証アプリをインストールしておく。androidならplayストア、iphoneならitunesで「Google認証」で検索すればすぐ見つかります。
既にインストール済みの人はそれをそのまま使えます。
</p>
<p>
次に、サーバにhttpdやgoogle-authenticatorなどをインストールします。いずれもyumで可能です。ただしgoogle-authenticatorのパッケージはepelリポジトリにしか無いので注意。あとhttpd-develやgccなんかも必要です。
</p>
<pre class="brush:shell">
[vagrant@localhost ~]$ cat /etc/redhat-release
CentOS release 6.5 (Final)
[vagrant@localhost ~]$ sudo yum install http://ftp.riken.jp/Linux/fedora/epel/6/i386/epel-release-6-8.noarch.rpm
[vagrant@localhost ~]$ sudo yum install httpd httpd-devel subversion google-authenticator
[vagrant@localhost ~]$ sudo /etc/init.d/httpd start
</pre>
<p>
この時点で普通にapacheが起動できるはずです。ブラウザでアクセスして確認しておきましょう。iptablesとかは適宜設定しておくか、切っておきましょう。
</p>
<p>
<b>なお、サーバの時計をできるだけ正確に合わせておいてください。google認証はシークレットキーと時刻情報からワンタイムパスワードを割り出すので、
スマホ側とサーバ側とで時計が狂いすぎているとうまく認証できません。</b>
</p>
<p>
さてここで<a href="https://code.google.com/p/google-authenticator-apache-module/">google-authenticator-apache-module</a>の登場です。
コンパイル済みのバイナリもダウンロードできますが、
それは古くてOTPだけの認証しかできない(2要素認証になってない)バージョンなので、
最新ソースをcheckoutして自分でビルドします。
同梱の設定ファイルのコピーも忘れずに。
</p>
<pre class="brush: bash">
$ svn checkout http://google-authenticator-apache-module.googlecode.com/svn/trunk/ google-authenticator-apache-module-read-only
$ cd google-authenticator-apache-module-read-only
$ make
$ sudo make install
$ sudo cp googleauth.conf /etc/httpd/conf.d/
</pre>
<p>
$ sudo vi /etc/httpd/conf.d/googleauth.conf で下記のように編集。(Alias /tmp /tmp を追加しただけ)
</p>
<pre class="brush: bash">
Loadmodule authn_google_module modules/mod_authn_google.so
Alias /tmp /tmp
<Directory /tmp>
Options FollowSymLinks Indexes ExecCGI
AllowOverride All
Order deny,allow
Allow from all
AuthType Basic
AuthName "My Test"
AuthBasicProvider "google_authenticator"
Require valid-user
GoogleAuthUserPath ga_auth
GoogleAuthCookieLife 3600
GoogleAuthEntryWindow 2
</Directory>
</pre>
<p>
次に、ユーザー"foo"用の認証設定ファイルの準備。
最初のほうでインストールしたgoogle-authenticatorコマンドを使います。
</p>
<pre class="brush: bash">
[vagrant@localhost ~]$ google-authenticator
https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/vagrant@localhost.localdomain%3Fsecret%3DOVLUR4T2XXXXXXXX
Your new secret key is: OVLUR4T2XXXXXXXX
Your verification code is 995999
Your emergency scratch codes are:
39831342
73015310
75610143
61758264
10475486
Do you want me to update your "~/.google_authenticator" file (y/n) y
Do you want to disallow multiple uses of the same authentication
token? This restricts you to one login about every 30s, but it increases
your chances to notice or even prevent man-in-the-middle attacks (y/n) y
By default, tokens are good for 30 seconds and in order to compensate for
possible time-skew between the client and the server, we allow an extra
token before and after the current time. If you experience problems with poor
time synchronization, you can increase the window from its default
size of 1:30min to about 4min. Do you want to do so (y/n) y
If the computer that you are logging into isn't hardened against brute-force
login attempts, you can enable rate-limiting for the authentication module.
By default, this limits attackers to no more than 3 login attempts every 30s.
Do you want to enable rate-limiting (y/n) y
[vagrant@localhost ~]$
</pre>
<p>
何やら楽しそうなURLが表示されました。urlをブラウザにコピペして開いてみましょう。
QRコードが表示されるはずです。
スマホのGoogle認証アプリを起動し、右上のメニューから「アカウントを設定」→「バーコードをスキャン」でブラウザに映っているQRコードを読み取ります。
出力されているsecret keyとverification codeを手作業でスマホに入力する方法でももちろんOKですが、面倒です。
</p>
<p>スマホのアプリ画面は次のようになるはずです。赤枠の部分が今回の作業で追加した認証トークンになります。</p>
<div class="separator" style="clear: both; text-align: center;"><a href="http://2.bp.blogspot.com/-pJtoIsLWXgg/U39q-fCwDpI/AAAAAAAAAyk/3dVcQMFqZqQ/s1600/201405-google-auth.png" imageanchor="1" style="margin-bottom: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-pJtoIsLWXgg/U39q-fCwDpI/AAAAAAAAAyk/3dVcQMFqZqQ/s1600/201405-google-auth.png" /></a></div>
<p>
これでスマホのGoogle認証アプリの準備はできました。サーバ側の設定作業に戻ります。
</p>
<p>
さきほどのgoogle-authenticatorコマンドの出力結果が ~/.google_authenticator に保存されています。
それを一部コピペ&編集してapacheのユーザー認証設定として使います。
</p>
<pre class="brush: bash">
[vagrant@localhost ~]$ cat ~/.google_authenticator
OVLUR4XXXXXXXXXX
" RATE_LIMIT 3 30
" WINDOW_SIZE 17
" DISALLOW_REUSE
" TOTP_AUTH
39831342
73015310
75610143
61758264
10475486
</pre>
<p>
この内容を少し改変して、/etc/httpd/ga_auth/[ユーザー名] というファイルに格納します。ここではfooというユーザーにしますので、下のような感じ。
</p>
<pre class="brush: bash">
[vagrant@localhost ~]$ sudo mkdir /etc/httpd/ga_auth
[vagrant@localhost ~]$ sudo vi /etc/httpd/ga_auth/foo
</pre>
<p>
最終的にこんな結果になるように編集しておき、apacheを再起動したら作業完了です!
</p>
<pre class="brush: bash">
[vagrant@localhost ~]$ cat /etc/httpd/ga_auth/foo
OVLUR4XXXXXXXXXX
" RATE_LIMIT 3 30
" WINDOW_SIZE 17
" TOTP_AUTH
" PASSWORD=bar
[vagrant@localhost ~]$ sudo /etc/init.d/httpd restart
</pre>
<p>
PASSWORD=bar というところがポイントです。好きなようにパスワードを決めて書いておいてください。これが2要素認証のうちの第1要素にあたります。
</p>
<p>
いよいよブラウザでapacheにアクセスしてみましょう。/tmpというURIをファイルシステムの/tmpにAliasし、そこだけ2要素認証がかかるようにしたので、
http://サーバのip/tmp というurlにアクセスします。
</p>
<p>
いつものBasic認証ダイアログが出現します。ここでユーザー名はfoo、そしてパスワードの欄は bar + ワンタイムパスワードです。
上の画像で言えば、379076を示しているので、ダイアログのパスワードには bar379076 を入力します。/tmp の配下のファイル一覧が見えれば成功です。
</p>
<h3>補足</h3>
<p>
<a href="https://code.google.com/p/google-authenticator-apache-module/wiki/GoogleAuthenticatorApacheModule">本家のwiki</a>に書いてある通り、できればSSLも使うべきです。
そうすればBasic認証のリクエストヘッダも暗号化通信の対象となるため安心です。あと、Basic認証ではなくDigest認証もできるようですね。ためしてないけど。
</p>
<p>
それから、お気づきの通り、google-authenticatorコマンドはシークレットキーとともにいくつかの緊急用コードも出力してくれます。これはスマホを盗難、紛失、破損などしてOTPを得られなくなってしまった場合に備えての緊急用です。が、google-authenticator-apache-moduleはこれには対応してないようです(詳しく調べてません)。ソースほじろうかと思いましたが疲れたんでこのへんで。
</p>
<p>
Webの安全のために手をつくしてくれているGoogle先生とプログラマー諸氏に感謝!
</p>
nabedgehttp://www.blogger.com/profile/15249139606699432144noreply@blogger.com0tag:blogger.com,1999:blog-5429098246262962340.post-57085678350519930422014-05-06T17:47:00.001+09:002014-05-06T22:06:24.876+09:00spring-bootと組み込みTomcatが便利すぎて鼻血でそう<p>
Tomcat embeded - 組み込み型Tomcat - が正式にサポートされたのは2011年5月のTomcat7.0.14の前後あたりのようです。もう3年も前です。
一方で2014年4月、Spring frameworkはSpring Boot 1.0.0を正式にリリースしました。
</p>
<p>
この二つのニュースを別個に見ると「ふーん」としか思えません。時間軸もズレすぎですし。
しかし、最近、某所でSpring-Bootとtomcat-embededを組み合わせて使ってみたら、便利すぎて鼻血出そうになりました。
</p>
<p>
便利さがうまく伝わるかどうかわかりませんが、せめてメンテついでに<a href="http://mixer2.org/">Mixer2</a>のサンプルアプリで使ってみるか、と思いまして、
<a href="https://github.com/nabedge/mixer2-sample/tree/master/mixer2-fruitshop-springboot">mixer2-fruitshop-springboot</a>を作りました。
動かし方は<a href="http://mixer2.org/site/springmvcsample.html">こちらのページ</a>とほぼ同じ。
</p>
<p>
SpringFrameworkと組み込み型Servletコンテナをうまいこと組み合わせてくれる、という機能はspring-bootの数多くの機能のうちのひとつにすぎませんが、
とにかくここでは組み込みTomcatとの連携機能の話だけにします。
</p>
<p>
とりあえず<a href="https://github.com/nabedge/mixer2-sample/tree/master/mixer2-fruitshop-springboot">mixer2-fruitshop-springboot</a>をざっくりご覧いただきつつ
ポイントを挙げます。
</p>
<ul>
<li> src/main/webapp/WEB-INF/web.xml のようなフォルダやxml設定ファイルはもはや存在しません。こうした旧来型のWebアプリケーションとしての構造は分業開発の妨げになりやすいのですが、これは普通の単純なjavaライブラリとまったく同じ構造です。もちろんこれは、Servlet3.0準拠であることや、あるいは、ビューエンジンとしてjspではなくMixer2を使っているおかげでビューのテンプレートをwebappとかWEB-INFとかそういうところに置く必要が無い、ということによる効果でもあります。</li>
<li><a href="https://github.com/nabedge/mixer2-sample/blob/master/mixer2-fruitshop-springboot/pom.xml">pom.xml</a>のbuildタグ周辺を見てください。実質的にはmaven-jar-pluginとmaven-dependency-pluginが使われているだけです。特別なビルド方式は必要ありません。spring-bootにはmaven用のプラグインもあれこれ用意されているのですが、ビルド方式までもが特定のフレームワーク提供のプラグインに縛られるのは個人的には好みではないのでこの方法を採用しました。これにあとmaven-assembly-pluginを追加して、アプリ本体のjarとlibフォルダ配下に集められるjarをまとめてzip化するようなセッティングをすれば、リリース成果物の生成も簡単です。</li>
<li>pom.xmlのpackaging指定はwarではなくjarです。このwebアプリケーションはmvn packageするとjarファイルになります。いわゆるfat-jarではなく純粋なjarです。tomcat-embeded-x.y.z.jar等の組み込みtomcatライブラリの助けを得ながらwebアプリケーションとして起動します。コマンドラインで言えば java -jar mixer2-fruitshop-springboot-1.0-SNAPSHOT.jar -classpath "lib/*" で起動できます。</li>
<li>サンプルアプリでは<a href="https://github.com/nabedge/mixer2-sample/blob/master/mixer2-fruitshop-springboot/src/main/java/org/mixer2/sample/Server.java">Server</a>クラスにmain()メソッドを置いてあります。eclipse等での開発作業中はこのserverクラスを通常のjavaアプリとして起動し、ブラウザで8080ポートを見て動作確認をします。繰り返しますがwebアプリではあるものの構造上は単なるjavaアプリなので、eclipseでWTPのようなプラグインは必要ありません。tomcatも別途用意する必要がありません。だって組み込みtomcatだから。ただのjavaアプリだから。</li>
<li>tomcatのcontext.xmlやwebアプリとしてのWEB-INF/web.xmlにあたるものは全てjavaコードとして記述します。サンプルアプリでは<a href="https://github.com/nabedge/mixer2-sample/blob/master/mixer2-fruitshop-springboot/src/main/java/org/mixer2/sample/config/MvcConfiguration.java">MvcConfiguration</a>や<a href="https://github.com/nabedge/mixer2-sample/blob/master/mixer2-fruitshop-springboot/src/main/java/org/mixer2/sample/config/SessionTrackingConfigListener.java">SessionTrackingConfigListener</a>にあたります。もちろんここのコード上で設定されている値はspringの種々の機能を使えば、他の設定ファイルやコマンドライン引数等で外側から上書きすることが可能となります。Springのprofile機能も使いこなせるでしょう。</li>
</ul>
<p>
こんな話だけでは便利さが伝わらないかもしれません。とにかくこれはちょっとしたパラダイムシフトですね。
これからは、「tomcatを用意してそこにSpringMVCによるwebアプリケーション(*.warファイル)をdeployする」のではなくて、
「webアプリケーションとtomcatをSpringFramework上で起動する」という感覚になります。もう、webアプリとtomcatを別々に用意する必要はないのです。これらは、ひとつです。
</p>
nabedgehttp://www.blogger.com/profile/15249139606699432144noreply@blogger.com0tag:blogger.com,1999:blog-5429098246262962340.post-12056732033567734252014-04-06T00:27:00.000+09:002014-04-06T00:47:15.765+09:00第5回 #渋谷java でトークしてきた<p>
今日はこんなイベントに参加してきました。
</p>
<blockquote>
<h4><a href="http://connpass.com/event/5482/">第五.五回 #渋谷java - connpass</a></h4>
<p>javaに関することなら何でもありのゆるふわjava LTイベントです。</p>
<p>参加される方はSIerの方や自社プロダクト開発の方やフリーランスの方など様々です。
LTの内容は初心者向け〜ガチ勢向けまで幅広く実施して頂いておりますので初心者の方もモヒカンの方お気軽にどうぞ!</p>
</blockquote>
<p>
2月にやるはずだったのが大雪のため4月に延期になったやつです。
私はセッション枠で20分ほどしゃべらせていただきました。資料がこちら。
</p>
<iframe src="http://www.slideshare.net/slideshow/embed_code/33155664" width="427" height="356" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px 1px 0; margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe>
<div style="margin-bottom:5px"> <strong> <a href="https://www.slideshare.net/nabedge/20140405-maven-5java" title="20140405 mavenセントラルリポジトリへの登録のコツ 第5回渋谷java" target="_blank">20140405 mavenセントラルリポジトリへの登録のコツ 第5回渋谷java</a> </strong> from <strong><a href="http://www.slideshare.net/nabedge" target="_blank">nabedge</a></strong>
</div>
<p>
その場でJenkinsを「ポチっとな」してMixer2のビルドとセントラルリポジトリへのデプロイ作業を生実演でお見せするという試みがけっこうウケたようで、うれしかったです。
ついでなのでプレゼンで語りきれなかったことを少し書きます。
</p>
<p>
perlなら<a href="http://cpan.org">cpan</a>, PHPなら<a href="http://pear.php.net">PEAR</a>やPECL, rubyなら<a href="http://rubygems.org">rubygems</a>
そしてJavaなら<a href="http://search.maven.org">mavenセントラルリポジトリ</a>のように、近代的なプログラミング言語のほとんどが、
パッケージリポジトリ=コンパイル済みで即利用可能な状態のライブラリの集積所=と、それをうまく使いこなすためのコマンド機構を持っています。
</p>
<p>
mavenはビルドツールではありますが、そのキモはmavenセントラルリポジトリとの自動的な連携にあります。これはGradleでもAnt+Ivyでも同じことが言えます。
java以外の言語でも似たようなものです。
だからこそ、現代のプログラマーはパッケージリポジトリのことをもっと意識しそこに貢献すべきです。今日のトークの動機はそこにあります。
ソーシャルコーディングに必要なのはGitHubだけではないのです。
</p>
<p>
mavenセントラルリポジトリにライブラリをupする権限を得るには審査が必要だという話をしましたが、
それはあくまで形式的なものです。
たとえばgroupIdが他とバッテイングしてないかとか、pomの書き方ちゃんとわかっていそうかとか、
MITかGPLかApache2かライセンスをちゃんと表示しているかとか、
なにかの商標にひっかかってなさそうかとか。。。
逆に言うと「おまえの作ったjavaライブラリはmavenセントラルに入れてもいいほどすっげえ便利かどうか」ということは考慮されません。
それはsonatype.orgの中の人が決めることではなく、全世界のjavaユーザーが決めることだからです。
</p>
<p>
門戸は開かれています。さあ、あなたもこれで、javaのOSSライブラリ開発者!
</p>
<p>
なお、他の方のトークで個人的に面白かったのがこちら。
</p>
<iframe src="http://www.slideshare.net/slideshow/embed_code/33162537" width="427" height="356" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px 1px 0; margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe> <div style="margin-bottom:5px"> <strong> <a href="https://www.slideshare.net/kazurof/about-niunit" title="日本語によるJUnitの拡張について" target="_blank">日本語によるJUnitの拡張について</a> </strong> from <strong><a href="http://www.slideshare.net/kazurof" target="_blank">Kazuro Fukuhara</a></strong> </div>
<blockquote><pre>@テスト
public void 文字列マッチャーのテスト() {
文字列("テストなんとか", は("テスト".で始まる()));
}</pre></blockquote>
<p>っておいなんだこれw</p>
<p>
最後になりましたが、運営の@seri_kさんほか会場設営などやってくださっているビズリーチ社の関係者の方々に感謝します。私も結構ガチで転職を考えております。w
</p>
<p>
参考リンク:
<a href="http://togetter.com/li/651597">第五.五回 #渋谷java - Togetterまとめ</a>
</p>nabedgehttp://www.blogger.com/profile/15249139606699432144noreply@blogger.com0tag:blogger.com,1999:blog-5429098246262962340.post-46760513453616173542014-01-28T20:00:00.000+09:002014-01-28T21:01:38.558+09:00Mixer2でページのヘッダとフッタを挿入する方法<p>
「Mixer2でビューを作るとき、いろんなページで共通のヘッダやフッタ部分を挿入するのってどうやるのだろう?」
よくあるケースです。JSPで言えば <jsp:include page="header.jsp"> にしておきつつ、
header.jspファイル内には <div id="header">ヘッダーのなか</div> のように書いておくやつ。
</p>
<p>
しかし、JSP的なやり方だと、ヘッダはヘッダ、フッタはフッタ、のようにバラバラになってしまい、
webデザイナーの立場からするとメンテが面倒なうえに実際の見栄えの確認がしづらくなってしまいます。
Mixer2ではいろいろなやり方がありますが、わかりやすくかつ手っ取り早いのが、<b>パーツ取り用htmlテンプレート作戦</b>です。
</p>
<p>
まず、通常の画面表示用テンプレートの他に、
parts.html のような名前でパーツ取り専用テンプレートを用意し、そこにヘッダとフッタのブロックを自由に書きます。
</p>
<pre>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
</head>
<body>
<div id="header">
実際にヘッダにしたい内容
</div>
これはパーツ取り専用htmlなので実際には出力しませんよ
<div id="footer">
フッタにしたい内容
</div>
</body>
</html>
</pre>
<p>
次に実際に画面に出すテンプレートファイル(fooTemplate.htmlだとします)には次のように書いておきます。
</p>
<pre>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
</head>
<body>
<div id="header">
ここにヘッダがはいる予定です
</div>
実際に出力したいコンテンツ...
<div id="footer">
ここにフッターがはいる予定
</div>
</body>
</html>
</pre>
<p>
画面出力のviewクラスはこんな感じ。(あくまでも模式的な例です)
</p>
<pre class="brush:java">
Html partsHtml = mixer2Engine.loadHtmlTemplate("parts.html");
Div headerDiv = partsHtml.getById("header",Div.class).copy(Div.class);
Div footerDiv = partsHtml.getById("footer",Div.class).copy(Div.class);
Html fooHtml = mixer2Engine.loadHtmlTemplate("fooTemplate.html");
fooHtml.getBody().replaceById("header", headerDiv);
fooHtml.getBody().replaceById("footer", footerDiv);
</pre>
<p>
実際には、テンプレートのロードを何度もやるのはやや非効率です。
共通クラスを切り出して、そこでparts.htmlのロードを一回だけ行ってheader/footer用Divインスタンスの
copy()の結果を返させて、それを使うような感じがよいでしょう。
</p>
<p>
「fooTemplate.html上に <div id="header">ここにヘッダが入る</div> みたいなことを書く手間すら省きたい」という要求も実現可能です。
</p>
<pre class="brush:java">
Html partsHtml = mixer2Engine.loadHtmlTemplate("parts.html");
Div headerDiv = partsHtml.getById("header",Div.class).copy(Div.class);
Div footerDiv = partsHtml.getById("footer",Div.class).copy(Div.class);
Html fooHtml = mixer2Engine.loadHtmlTemplate("fooTemplate.html");
// bodyタグの先頭にヘッダdivを差し込む
fooHtml.getBody().getContent().add(0, headerDiv);
// bodyタグの最後にフッタ用divを差し込む
fooHtml.getBody().getContent().add(footerDiv);
</pre>
<p>
こんな感じ。
</p>
<p>
いかがでしょう。Mixer2でのビュー実装の書き方は様々です。
jspのカスタムタグではなく通常のjavaで書くので柔軟性とテストの書きやすさは段違い、というのがポイントです。
要件に合わせてご自由にどうぞ。
</p>
nabedgehttp://www.blogger.com/profile/15249139606699432144noreply@blogger.com0tag:blogger.com,1999:blog-5429098246262962340.post-64628519265216044132014-01-09T20:12:00.000+09:002014-01-09T20:47:48.539+09:00Java5で動くMixer2をリリースしました(あくまで実験的)<p>
Java5がリリースされたのは2004年10月。そして今はもう2014年です。もうすぐJava8も出ます。
そんな時期にMixer2をjava5でも動かせるようにするってそれ誰得?ww
というツッコミもけっこうありました。(※Mixer2は本来はJava6以上が動作条件です)
</p>
<p>
しかし、世の中にはレガシーなシステムなんていくらでもあるようです。詳しくは言えませんが、
Java1.4(5ですらない!)で現役で稼働しているシステムが存在し今もチビチビ改修していると言う話を、つい先日まのあたりにしました。
Javaから離れてしまいますが、全日空の国内線旅客システムが実はつい最近まで
Fortran(COBOLですらない!)で動いていたというニュースもありましたね。
</p>
<p>
さて、話をMixer2に戻しましょう。
Mixer2はJavaのJAXB-APIを使ってXHTMLを入出力しています。JAXBはJava6以降でJDK/JREに標準搭載となったため、
本来、Java5では動きません。
</p>
<p>
ただ、jaxbはもともと独立したライブラリとしてSunの社内で開発が続き、のちにJava6で初めて実行環境に標準搭載されたという経緯があります。
これはjaxbに限ったことではなく他のapiでも似たような流れをたどることがあります。
</p>
<p>
ということは、jaxbやその関連の、既に公開されているライブラリを、
Mixer2が依存ライブラリとして使用するようにすればJava5でも動くということになります。
そう、実はそれほど遠い道のりではないのです。実際1日2日でできちゃったし。
</p>
<p>
そんなこんなでとにかく、mixer2-java5 version 0.1.2 をリリースしました。
</p>
<ul>
<li>mavenやgradle経由でパッケージリポジトリが使える人は <a href="http://search.maven.org/#artifactdetails|org.mixer2|mixer2-java5|0.1.2|jar">http://search.maven.org/#artifactdetails|org.mixer2|mixer2-java5|0.1.2|jar</a></li>
<li>本体と依存ライブラリのjar一式の形で欲しい人は <a href="http://mixer2.org/dist/">http://mixer2.org/dist/</a></li>
</ul>
<p>
使い方は本家Mixer2とまったく変わりありません。ただし、以下の点にご注意ください。
</p>
<ul>
<li>あくまで実験的なものですので、サポートやバージョンアップはそれほど期待しないでください。</li>
<li>SpringMVC関連機能は削り落としてあります。純粋にテンプレートエンジン機能のみです。</li>
</ul>
nabedgehttp://www.blogger.com/profile/15249139606699432144noreply@blogger.com0tag:blogger.com,1999:blog-5429098246262962340.post-84913770967722972582013-12-28T17:52:00.000+09:002013-12-28T17:52:07.872+09:00Mixer2の最近のリリースでのエンハンス(特にSpringMVC関連)<p>Mixer2-1.2.22をリリースしました。</p>
<p>
実はここ数週間で何回かリリースしましたが、まともにアナウンスしていませんでした。最近のリリースではどこをどういじったか、ざっくりまとめておきます。
</p>
<h3>1. Spring MVCとの組み合わせ方をドキュメントに書きました</h3>
<p>
Mixer2とSpringMVCと組み合わせたサンプルアプリケーションはもともとあったのですが、
javadocはともかく、文章の形では基本的な説明をまとめて書いてはいなかったので、
<a href="http://mixer2.org/site/springmvc.html">Use Mixer2 with Spring MVC</a>というページを公式サイトにつくりました。
なお、もともとほぼ同じことがjavadocにも書いてありましたが、それも少し手直ししました。
<ul>
<li><a href="http://mixer2.org/site/apidocs/org/mixer2/spring/webmvc/AbstractMixer2XhtmlView.html">AbstractMixer2XhtmlView</a></li>
<li><a href="http://mixer2.org/site/apidocs/org/mixer2/spring/webmvc/Mixer2XhtmlViewResolver.html">Mixer2XhtmlViewResolver</a></li>
</ul>
</p>
<p>
※誤解の無いように念のため書いておきますが、Mixer2それ自体は他のライブラリ等への依存性が非常に少ない、独立性の高いxhtmlテンプレートエンジンです。
Webアプリケーションフレームワークと組み合わせて使うのが便利なことは確かですが、
<b>必ずSpringMVCやSAStrutsと組み合わせないと何もできないということは全くありません。</b>
</p>
<h3>2. Spring MVCでMixer2もJSPも両方使いたくてもうまく動かないのを直しました</h3>
<p>
公式サイトの説明のように
</p>
<pre class="brush:xml">
<bean id="mixer2Engine" class="org.mixer2.Mixer2Engine" />
<bean class="org.mixer2.spring.webmvc.Mixer2XhtmlViewResolver">
<property name="order" value="1" />
<property name="prefix" value="classpath:m2mockup/m2template/" />
<property name="suffix" value=".html" />
<property name="basePackage" value="com.example.yourproject.web.view" />
<property name="mixer2Engine" ref="mixer2Engine" />
</bean>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="order" value="2" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp"/>
</bean>
</pre>
<p>
と書けば、コントローラから返されたview名を使ってMixer2ViewResolverがhtmlテンプレートファイルを見つけられなかった場合には、
そのままInternalResourceViewResolverへ処理が移って、view名に該当するjspが使われる...はずだったのですが、
実際にはMixer2VeiwResolverがhtmlテンプレートを見つけられなかった段階でいきなりFileNotFoundExceptionになってしまっていました。
</p>
<p>
それではまずいので、ちゃんと次のリゾルバーに処理が移るように直しました。このへんは、SpringMVCのマニュアルにも書かれている通りにしてみた、という感じです。
</p>
<blockquote>
<h4>17.5.2 Chaining ViewResolvers</h4>
"The contract of a view resolver specifies that a view resolver can return null to indicate the view could not be found. Not all view resolvers do this ..."
(ビューリゾルバーの実装ルールとしては、ビューを見つけられない場合にはnullを返すことができますよ。ただ全部のビューリゾルバーがそうしてるわけじゃなくケースバイケース...)
<br />
<a href="http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/mvc.html">Spring MVC reference 3.2.x</a>より
</blockquote>
<p>
ただし、従来の挙動(見つからなければ即座にFileNotFoundException)でよいという人のために、
この機能をオフにする設定方法も用意しておきました。細かいことは<a href="http://mixer2.org/site/apidocs/org/mixer2/spring/webmvc/Mixer2XhtmlViewResolver.html">Mixer2XhtmlViewResolverのjavadoc</a>に書いてあります。
</p>
<h3>3. headタグの中ではremoveById()等が動かないことがあるのを直しました</h3>
<p>
単純にバグです。
</p>
<h3>4. 恥ずかしいミススペルを直しました</h3>
<p>
<a href="http://mixer2.org/site/apidocs/org/mixer2/xhtml/PathAjuster.html">PathAjuster</a>クラスはクラス名自体の綴りが間違っていることが今頃発覚w。
機能はそのままで<a href="http://mixer2.org/site/apidocs/org/mixer2/xhtml/PathAdjuster.html">PathAdjuster</a>クラスとして作り直しました。
古い方のクラスは@Deprecatedにしておきましたが、こういうので後方互換性を失うのはまずいのでたぶんずっと消さずに残しておくと思います。
</p>
<h3>5. HTML5でAタグの中のDIVタグ等が消えるのを直しました</h3>
<p>
<a href="https://groups.google.com/forum/#!topic/mixer2-ja/lcyWD_Fm83Q">Mixer2-jaメーリングリスト</a>のほうでもらったバグ報告の対応です。
</p>
<p>
htmlテンプレートとしてmixer2Engineがロードするとき、テンプレート上のaタグの中にインライン要素(spanとかimgとか)が入ってるのはokだが、
ブロック要素(divとかpとか)が入っているとそれが消えてしまうという現象です。
</p>
<p>
これはちょっと盲点でした。というのは、html4.xまでの規格では、aタグの中にブロック要素を入れるのはNGなのです。
Mixer2はJAXBを使ってhtml(xhtml)を読み込むので、そういったところも厳格にNG扱いで、該当要素を無かったことにします。
ところが、html5ではaタグの中にブロック要素も入れられるようになりました。
<a href="http://www.html5.jp/html5doctor/block-level-links-in-html-5.html">HTML5 の “ブロック・レベル“ リンク</a>というやつです。
Mixer2のhtml5に対する対応の不足、というバグとして対応しました。
</p>
<p>
ここ数週間のMixer2のエンハンス、ざっくり解説してみました。安心して最新版をご利用ください。今後ともごひいきに!
</p>
nabedgehttp://www.blogger.com/profile/15249139606699432144noreply@blogger.com0tag:blogger.com,1999:blog-5429098246262962340.post-7243067388067246582013-12-23T10:00:00.000+09:002013-12-23T10:00:05.231+09:00JAX-RSのビューとしてMixer2を使ってみる<p>
こんにちは。nabedgeこと渡辺です。
<a href="http://nabedge.blogspot.jp/2013/12/mixer2springmvcver-1217.html">ひとつ前の記事</a>はJava Advent Calendar2013のやつでしたが、
今日は<a href="http://www.adventar.org/calendars/152">Java <b>EE</b> Advent Calendar 2013</a>の23日目なんです。
JavaじゃなくてJava<b>EE</b>です。ここでSpringMVCがどうのとか言っちゃうといろんな人が(コンコン、おや誰かきたようだ
</p>
<p>
そんなわけで、JavaEE規格の中でもWeb系エンジニアにとって最も身近な、JAX-RSのお話です。
</p>
<p>
今年の3月頃、
<a href="http://d.hatena.ne.jp/aoe-tk/20130317/1363527825">JAX-RSはHTML Webアプリケーションを開発するのに充分なフレームワークであるか? - AOEの日記</a>
というエントリが結構話題になりまして、そこではこんな話もありました。
</p>
<blockquote>
<h4>テンプレート処理パートの実装について</h4>
(中略)<br />
ただ、普通のJSPプログラミングであるため、エラー時にメッセージやハイライトをしたり、条件に応じた表示変更と言った処理もゴリゴリ実装する必要があります。これが地味にめんどかったりします。少し大きな規模の開発案件になった場合はある程度プレゼンテーションレイヤで必要となるライブラリを整備してあげる必要があると思います。
</blockquote>
<p>
そのとおりです。javaのmvcフレームワークは、案外どれも「ビューはjsp(jsf)で」と一言書いてあるだけです。
<b>しかし現実世界に置けるM,V,CのViewは、それほど単純ではありません。むしろ、ビューは十分に複雑です。</b>
</p>
<p>
JAX-RSの設計思想として、httpレスポンスをhtmlではなくjsonやxmlで返すことに主眼を置いているように思えます。
素直に考えると、クライアントサイドはJavaScript等で実装しサーバーから受け取ったjsonやxmlを料理せよ、ということでしょうし、
実際そうしようとしている開発現場も増えてきているかもしれません。
しかしそのためにはBackbone.jsやAngular.jsといったクライアントサイドMVCフレームワークの使い方も覚えなければなりません。
Webデザイナーの仕事とうまく歩調を合わせることまで考えると、道のりは険しそうです。
</p>
<p>
話をサーバーサイドに戻しましょう。
Viewを実装するために、jsp、jsfあるいはVelocityやThymeleafのようなテンプレートエンジンの特殊文法を覚えたり、
それでも足りなくてカスタムタグやプラグインを書き、気がつけばWebデザイナーさんの仕事は置いてけぼりになっている。
そんなことになるくらいなら、<b>はじめからViewをjavaで普通に書けばいいじゃない!
テンプレートは普通のhtml/cssで!</b>それが<a href="http://mixer2.org/">Mixer2</a>の存在理由です。
</p>
<p>
前置きが長くなりましたがとにかく、html主体のwebアプリケーションを、JAX-RSとMixer2で作る、簡単なサンプルを作ってみました。
ソースは <a href="https://github.com/nabedge/mixer2-sample/tree/master/mixer2-jaxrs-sample">https://github.com/nabedge/mixer2-sample/tree/master/mixer2-jaxrs-sample</a>
です。
</p>
<p>
jax-rs実装にはjersey、サーバはtomcatを想定しています。(あっ、なんでglassfishじゃねーんだって言われそう^^;)
</p>
<p>
ポイントは二つ。まず一つ目が、リソースクラスのメソッドの戻り値がorg.mixer2.jaxb.xhtml.Html型であることです。
<a href="https://github.com/nabedge/mixer2-sample/blob/master/mixer2-jaxrs-sample/src/main/java/org/mixer2/sample/IndexResource.java">IntexResource.java</a>をご覧ください。
</p>
<pre class="brush:java">
@GET
@Produces(MediaType.TEXT_HTML)
public Html index(@QueryParam(value = "message") String message)
throws IOException, TagTypeUnmatchException {
// loading template
String template = "m2mockup/m2template/index.html";
InputStream is = this.getClass().getClassLoader()
.getResourceAsStream(template);
Html html = mixer2Engine.loadHtmlTemplate(is);
// replace content in <div id="message"> tag
if (message != null) {
Div div = html.getBody().getById("message", Div.class);
div.unsetContent();
div.getContent().add(message);
}
// replace static file path
Pattern pattern = Pattern.compile("^\\.+/.*m2static/(.*)$");
PathAjuster.replacePath(html, pattern, "m2static/$1");
// return html object
return html;
}
</pre>
<p>
Html型を返されたjerseyは、それを処理しうるMessageBodyWriterを探して引き継いでくれます。
それが<a href="https://github.com/nabedge/mixer2-sample/blob/master/mixer2-jaxrs-sample/src/main/java/org/mixer2/sample/Mixer2Writer.java">Mixer2Writer.java</a>
です。
</p>
<pre class="brush:java">
@Provider
@Produces(MediaType.TEXT_HTML)
public class Mixer2Writer implements MessageBodyWriter<Html> {
// -- snip --
@Override
public void writeTo(Html html, Class<?> type, Type genericType, Annotation[] annotations,
MediaType mediaType, MultivaluedMap<String, Object> multivaluedMap,
OutputStream outputStream) throws IOException, WebApplicationException {
// marshalling html object to string.
String str = mixer2Engine.saveToString(html);
OutputStreamWriter writer = new OutputStreamWriter(outputStream, "UTF-8");
writer.write(str);
writer.flush();
}
}
</pre>
<p>
Html型のインスタンスをMixer2Engineに渡して文字列化し、そのまま出力しているだけです。
</p>
<p>
いろいろ急いでしまったので、突っ込みどころだらけです。リソースクラス内でビューの処理もやってしまっている点はイケてなくて、
本来なら<a href="https://jersey.java.net/apidocs/latest/jersey/org/glassfish/jersey/server/mvc/Viewable.html">Viewable</a>
や<a href="https://jersey.java.net/apidocs/latest/jersey/org/glassfish/jersey/server/mvc/spi/ViewableContext.html">ViewableContext</a>
をうまく実装して切り分けるべきでしょう。そもそもJavaEEだっつってんのになんでGlassFishじゃなくtomcatで試しているんだとか。
Mixer2Engineの呼び出しもCDIを使うほうがJavaEEらしくなるでしょう。
</p>
<p>
このサンプル、どなたか試していただいて、もちょっとカッコよくしていただけませんか?
マサカリも歓迎ですが、Pull Requestはもっと歓迎です。だってほら、クリスマスだし。
</p>
nabedgehttp://www.blogger.com/profile/15249139606699432144noreply@blogger.com0tag:blogger.com,1999:blog-5429098246262962340.post-7477132637850024622013-12-08T00:20:00.000+09:002013-12-08T00:28:04.946+09:00Mixer2のSpringMVC連携機能がver 1.2.17でさらに進化!<p>こんばんは。<a href="https://github.com/nabedge/">nabedge</a>こと渡辺です。
この記事は<a href="http://www.adventar.org/calendars/145">Java Advent Calendar 2013</a>の8日目です。</p>
<p>さて、私が作っている<a href="http://mixer2.org/">Mixer2</a>というテンプレートエンジンですが、
秋口に秀逸な pull request をいただいたので、ありがたくマージしてversion1.2.17をリリースしました。</p>
<p>本当は先週リリースした1.2.14で既にマージ済みだったのですが、
JavaDocに書いたサンプルコードのとおりに書くと動かない(笑)というヤバいのがあったのでリリースしなおしました。
そのJavaDocを書いたのはプルリクをくれた人ではなく私です。
さらに言うと、リリース作業で凡ミスして1.2.15と1.2.16を欠番にしてしまったのも私です。 ^^;)
</p>
<p>そんなことはさておき、何が新しくなったのかというとSpringMVCとMixer2を連携させるためのViewとViewResolverです。
とりあえず<a href="https://github.com/nabedge/mixer2-sample/blob/master/mixer2-fruitshop-springmvc/src/main/java/org/mixer2/sample/web/controller/CheckoutController.java">フルーツショップサンプルアプリケーションの商品配送先住所の入力画面用のコントローラ</a>で説明してみます。</p>
<pre class="brush:java">
@RequestMapping(value = "/shipping")
public String shipping(Model model,
@RequestParam(value = "redirected", required = false) boolean redirected,
@Valid Shipping shipping, Errors errors) {
model.addAttribute("shipping", shipping);
model.addAttribute("redirected", redirected);
model.addAttribute("errors", errors);
return "checkout/shipping";
// 以前のMixer2ではここで return "shippingView" のように、
// springコンテナ上にDI済みのviewクラスの名称を
// 与える必要があったが、新しいMixer2では
// テンプレートファイルのパスでよい。
// そしてテンプレートファイルのパスは
// Viewクラスのパッケージ名/クラス名とそのまま紐づくルール。
}
</pre>
<p>コントローラの戻り値はテンプレートファイルのパスそのものです。
つまり<b>戻り値の書き方はInternalResourceViewResolver + JSPを使う場合と同じでいい</b>ところがポイントです。</p>
<p>次に、<a href="https://github.com/nabedge/mixer2-sample/blob/master/mixer2-fruitshop-springmvc/src/main/java/org/mixer2/sample/web/view/ItemView.java">配送先住所の入力画面のViewクラス</a>を見てみましょう。</p>
<pre class="brush:java">
// Viewクラスに@ComponentのようなDIアノテーションは不要。
// 新しいViewResolverが代わりにやってくれる。
public class ItemView extends AbstractMixer2XhtmlView {
@Autowired
protected FooBar fooBar;
// もちろんSpringコンテナから任意の
// オブジェクトをDIで受け取れる
@Override
protected Html renderHtml(Html html,
Map<String, Object> model,
HttpServletRequest request,
HttpServletResponse response)
throws TagTypeUnmatchException {
// Html html = mixer2Engine.loadHtmlTemplate(filePath);
// のようなコードは不要。
// 新しくなったAbstractMixer2XhtmlViewが、
// コントローラのメソッドの戻り値で指定された
// パスを使ってあらかじめテンプレートをロードして
// Htmlオブジェクトに格納済み。
@SuppressWarnings("unchecked")
List<Category> categoryList = (List<Category>) model.get("categoryList");
Item item = (Item) model.get("item");
// embed item box
replaceItemBox(html, item);
// 途中は省略
return html;
}
</pre>
<p>
ここでSpringの設定のほうを見てみます。
</p>
<pre class="brush:xml">
<bean id="mixer2Engine"
class="org.mixer2.Mixer2Engine"
scope="singleton" />
<bean class="org.mixer2.spring.webmvc.Mixer2XhtmlViewResolver">
<property name="order"
value="1" />
<property name="prefix"
value="classpath:m2mockup/m2template/" />
<property name="suffix"
value=".html" />
<property name="basePackage"
value="org.mixer2.sample.web.view" />
<property name="mixer2Engine"
ref="mixer2Engine" />
</bean>
</pre>
<p>
Mixer2XhtmlViewResolverのprefix,suffix,basePackageのプロパティがポイントです。
つまり、コントローラのメソッドの戻り値が "foo" の場合、<br />
org.mixer2.sample.web.view.FooView がビュークラスで、<br />
クラスパス上の m2mockup/m2template/foo.html がテンプレートファイルです。
</p>
<p>
コントローラのメソッドの戻り値が "foo/bar" の場合、<br />
org.mixer2.sample.web.view.foo.BarView がビュークラスで、<br />
m2mockup/m2template/foo/bar.html がテンプレートファイルということになります。
</p>
<p>
もちろんビュークラスはAbstractMixer2XhtmlViewを継承していなければなりません。
なお、複数のテンプレートを組み合わせてhtmlを生成したい場合は、ビュークラス内で
getMixer2Engine()でいつでもエンジンを使えますので、好きなテンプレートをいくらでもロード可能です。
</p>
<p>
クレバーなプルリクをくださった<a href="https://github.com/kazuki43zoo">kazuki43zoo</a>さんに感謝!
</p>
<p>
<a href="http://www.adventar.org/calendars/145">Java Advent Calendar 2013</a>、
次はJavaFXの大御所、<a href="https://twitter.com/skrb">skrb</a>さんです。
</p>
nabedgehttp://www.blogger.com/profile/15249139606699432144noreply@blogger.com0tag:blogger.com,1999:blog-5429098246262962340.post-942195663428296832013-11-27T19:30:00.000+09:002013-11-27T23:10:42.788+09:00メールアドレスとRFCの話<p>
確かに定期的に繰り返される話題ですね。
</p>
<blockquote style="padding:4px; border:solid 1px black;">
<h4><a href="http://d.hatena.ne.jp/nekoruri/20131127/1385521425"> 「メールアドレスのルール」なんて使ってはいけない3つの理由</a></h4>
問題点1. メールアドレスに関して、RFCなんてそもそも守られていない<br />
<br />
2009年以前に登録されたDoCoMo携帯のメールアドレスなど、quoted-stringじゃないのにピリオド連続するものが実在している以上、彼らを許容するべきです。<br />
<br />
<b>今そこにある実装 >> (越えられない壁) >> RFC です。</b>
</blockquote>
<p>
※2009年以前に登録されたDoCoMo携帯のメールアドレスっていうのはつまり、
foo....bar@docomo.ne.jp みたいにドットが連続してたりするアドレス(RFC的にはNG)のことを指します。
</p>
<p>
んで、「今そこにある実装」を重視すべきなのであれば、以下も重視したうえで、
「やはり彼らを許容すべきではない」という結論も得られてしまいます。
</p>
<ul>
<li><a href="http://support.microsoft.com/kb/940620/ja">Outlook から RFC で認められていない形式のメール アドレスにメールを送信すると、配信不能メールが返され送信できない</a></li>
<li><a href="http://support.microsoft.com/kb/2439987/ja">Exchange 2010 で @ の直前にピリオドがあるなどの RFC に準拠していない SMTP アドレスを含むメッセージを受信できない</a></li>
</ul>
<p>ケースバイケースでしょう。</p>
<p>
合わせて読みたい:<a href="http://www.slideshare.net/kawada_hiroshi/internet-explorerie">Internet Explorer はIE特化アプリから一時的に日本を救ってくれたけど次回はもう助けてくれないよという 警告</a>
</p>
nabedgehttp://www.blogger.com/profile/15249139606699432144noreply@blogger.com0tag:blogger.com,1999:blog-5429098246262962340.post-39470947955237969342013-11-24T17:02:00.000+09:002013-11-24T17:02:03.778+09:00DevLove現場甲子園でしゃべってきました<p>
もう先々週のことなんですが、<a href="http://devlove.doorkeeper.jp/events/5464">DevLOVE現場甲子園2013</a>というイベントでしゃべってきました。
</p>
<h4><a href="http://www.slideshare.net/nabedge/201311-webmixer2-devlove">webデザイナとエンジニアのチームワークを加速させるテンプレートエンジンmixer2 devlove現場甲子園
</a></h4>
<iframe src="http://www.slideshare.net/slideshow/embed_code/28061270" width="427" height="356" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC;border-width:1px 1px 0;margin-bottom:5px" allowfullscreen> </iframe> <div style="margin-bottom:5px"> <strong> <a href="https://www.slideshare.net/nabedge/201311-webmixer2-devlove" title="201311 webデザイナとエンジニアのチームワークを加速させるテンプレートエンジンmixer2 devlove現場甲子園" target="_blank">201311 webデザイナとエンジニアのチームワークを加速させるテンプレートエンジンmixer2 devlove現場甲子園</a> </strong> from <strong><a href="http://www.slideshare.net/nabedge" target="_blank">nabedge</a></strong> </div>
<p>
Mixer2ネタであることはともかく、プレゼン資料自体の使い回し感は否めません。すいませんすいませんすいません。
</p>
<p>ほかの方もプレゼンもなかなか面白かったです。
webデザイナーの秋葉さんのプレゼンとか→
「<a href="http://www.slideshare.net/toooommmmmmmmy/devlove-koshien-akb20131108publish">【DevLOVE甲子園2013】UIと画面遷移を設計するときに 破綻しないようにするための、 ひと手間</a>」</p>
<p>あと、「<a href="http://www.slideshare.net/sugiim250/ss-28067522">バラバラの同僚を社内勉強会でつなげよう</a>」っていうやつもなかなか。</p>
<p>
最後になりましたが、devloveスタッフの方、本当にご苦労様でした。ありがとうございました。
</p>
nabedgehttp://www.blogger.com/profile/15249139606699432144noreply@blogger.com0tag:blogger.com,1999:blog-5429098246262962340.post-90237134455650674582013-10-26T13:19:00.001+09:002013-10-26T13:25:10.682+09:00log4j2にログを集める<p>
log4j, slf4j, logback, commons-logging... こんがらがりませんか?僕はこんがらがりました。
</p>
<p>
ある実験的なWebアプリの開発の過程では、ログを最終的に何に集約するか?logbackか?それとも...?と、迷い、
結局<b>log4j2</b>に集約しました。これはそのメモみたいなものです。
</p>
<p>
なお、「slf4j+logbackのほうがナウでヤングだろ」といったご意見はスルーです。好みとかポリシーの問題です。
また、いにしえより伝わるlog4j1.xではなく、<a href="http://logging.apache.org/log4j/2.x/">log4j2.x</a>っていうところもポイントです。
java.util.logging?えーっ?!却下。
</p>
<h3>1. 前提とか方針とか</h3>
<ul>
<li>新規のJava-Webアプリを開発する。そのコード上で使うLoggerにはlog4j2を使う。</li>
<li>ベースはSpringMVCフレームワーク。spring自身は内部でcommons-loggingを使っているので、それもlog4j2に集められるように設定する。</li>
<li>Spring以外にもいろいろOSSライブラリを使うが、それが吐くログもできる限りlog4j2に集める。例えば、内部でslf4j-apiを使ってるOSSが最近はとても多い。</li>
<li>設定はlog4j2.xmlに集める。とりあえずWebアプリ内部に同梱する。</li>
<li>ビルドツールはmavenを使う</li>
</ul>
<h3>2. mavenのpom.xml</h3>
<p>
dependenciesタグ内で先に書いてあるほうが優先されるので、ログ出力ライブラリは上のほうに書いておくのが無難です。log4j-coreがもちろんlog4j2の本体。
log4j-jclがcommons-loggingによる出力をlog4j2に中継させるやつ。log4j-slf4j-implはslf4jによる出力を(以下略)
</p>
<pre class="brush:xml">
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.0-beta8</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jcl</artifactId>
<version>2.0-beta8</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.0-beta8</version>
</dependency>
... other dependency...
</dependencies>
</pre>
<p>
maven使いじゃない人のために、これで実際どんなjarがビルドパスに入ってくれるのか、書いておきます。こんだけ。
</p>
<pre>
log4j-core-2.0-beta8.jar
log4j-api-2.0-beta8.jar
log4j-jcl-2.0-beta8.jar
commons-logging-1.1.1.jar
log4j-slf4j-impl-2.0-beta8.jar
slf4j-api-1.7.5.jar
slf4j-ext-1.7.5.jar
cal10n-api-0.7.4.jar
</pre>
<h3>3. log4j2.xml</h3>
<p>log4j2.xmlをsrc/main/resourcesに置く。root(要するにデフォルト値)を設定するほか、
ログ出力を制御したいクラス名、パッケージ名に対して出力レベルや出力先(appender)を設定します。</p>
<script type="syntaxhighlighter" class="brush: xml"><![CDATA[
<configuration>
<appenders>
<Console name="console">
<PatternLayout pattern="%d{yyyy-mm-dd HH:mm:ss.SSS} %-5level %logger{32} %msg%n" />
</Console>
</appenders>
<loggers>
<logger name="org.springframework"
level="debug" additivity="false">
<appender-ref ref="console" />
</logger>
<logger name="com.example.myapp"
level="debug" additivity="false">
<appender-ref ref="console" />
</logger>
<root level="info">
<appender-ref ref="console" />
</root>
</loggers>
</configuration>
]]></script>
<h3>4. コードを書く</h3>
<pre class="brush:java">
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Foo {
private static Logger logger = LogManager.getLogger();
public void bar(String a, String b) {
logger.debug("a={},b={}", a, b);
}
}
</pre>
<p>
ログに変数をいれたいときに、logger.debug("a=" + a + ",b=" + b ) などとやってしまいがちですが、
実はこれ、ログ出力メソッドよりも先に+演算子による文字列連結の方が先に実行されますので、性能影響が出ます。
logger.debug()なんて本番環境ではオフにすると思いますが、それでも文字列連結は無駄に実行されてしまうのです。
どの程度の性能差が出るかは
<a href="http://logging.apache.org/log4j/2.x/performance.html">Performance - Apache Log4j 2</a>
に詳しく解説されています。
せっかくlog4j2を使うのですから、{}記号によるプレースホルダ機能を使うようにしましょう。
</p>
<p>
また、log4j1.xのときは、<br />
provate static Logger logger = Logger.getLogger(<b>Foo.class</b>);<br />
のように、ロガー名として自クラスを明示的に与えてloggerを作る必要がありましたが、
log4j2のLogManagerでは省略できます。
log4j2のほうが好みな理由はこれが地味に便利だからかも。
</p>
nabedgehttp://www.blogger.com/profile/15249139606699432144noreply@blogger.com0tag:blogger.com,1999:blog-5429098246262962340.post-37557151602551510942013-10-01T20:08:00.000+09:002013-10-01T20:08:01.145+09:00Mixer2 as XHTML snippet generator<p>
<a href="http://mixer2.org/">Mixer2 is the xhtml dedicated template engine.</a>
Because Mixer2 use JAXB (Java Architecture for XML Binding) internally,
the usage is not only as a template engine,
but also, Mixer2 can be used in another way.
</p>
<p>
Mixer2 has some different functionality.
</p>
<ol>
<li>as a alternative to JSP, Velocity, and other template engine technology</li>
<li>as a XHTML parser</li>
<li>as as XHTML tag snippet generator</li>
</ol>
<p>
In thie post, I introduce "XHTML snippet generator" functionality of Mixer2.
</p>
<p>
You must fix up your html template as "full html"
like "<html>...</html>"
in order to use mixer2Engine.loadHtmlTemplate() .
</p>
<p>
But if you need to output xhtml tag using mixer2Engine.saveToString(),
you can get any tag snippet as string.
So, you can create some helper class like custom tag of JSP.
</p>
<p>
For example,
If you must use jsp as the base template but also you want to use Mixer2,
You can use them combine them.
</p>
<p>
<b><a href="http://3.bp.blogspot.com/-qOzmgy97bcw/UkpsiAIDGxI/AAAAAAAAALw/yfjNi9hjkjU/s1600/mixer2-as-tag-snippet-generator.png" imageanchor="1"><img border="0" src="http://3.bp.blogspot.com/-qOzmgy97bcw/UkpsiAIDGxI/AAAAAAAAALw/yfjNi9hjkjU/s320/mixer2-as-tag-snippet-generator.png" /></a></b>
</p>
<p>
If you create the new tag instance, use "new" the tag classes.
Also you can use TagCreator.
</p>
<pre class="brush:java;">Div div = TagCreator.div();
Span span = TagCreator.span();
span.getContent().add("Hello World !");
span.setStyle("color:red;");
div.getContent().add(span);
String result = mixer2Engine.saveToString(div);
System.out.println(result);
</pre>
<p>output:</p>
<pre class="brush:html;">
<div><span style="color: red;">Hello World !</span></div>
</pre>
<p>
If you create table tag, you can use TableBuilder.
</p>
<pre class="brush:java;">
String[][] data = new String[][]{
// id, name, price
{"1", "cookie", "2.50"},
{"2", "candy", "3.75"}
};
TableBuilder tBuilder = new TableBuilder();
for (String[] row : data) {
tBuilder
.addTr()
.addTd(row[0])
.addTd(row[1])
.addTd(row[2]);
}
Table table = tBuilder.build();
String str = mixer2Engine.saveToString(table);
System.out.println(str);
</pre>
<p>output:</p>
<pre class="brush:html;"><table>
<tbody>
<tr>
<td>1</td>
<td>cookie</td>
<td>2.50</td>
</tr>
<tr>
<td>2</td>
<td>candy</td>
<td>3.75</td>
</tr>
</tbody></table>
</pre>
<p>
For more detail of TableBuilder, see
<a href="http://mixer2.org/site/tablebuilder.html">Mixer2 official site</a>.
</p>
<p>
How about it ?
Mixer2 and other template technology can exist together.
Try <a href="http://mixer2.org/">Mixer2</a> !
</p>
nabedgehttp://www.blogger.com/profile/15249139606699432144noreply@blogger.com0tag:blogger.com,1999:blog-5429098246262962340.post-4190668644902508722013-10-01T20:05:00.000+09:002013-10-01T20:05:00.455+09:00XHTMLタグスニペット生成器としてのMixer2<a href="http://mixer2.org/">Mixer2はXHTML専用のテンプレートエンジンです</a>。
しかし、Mixer2が内部でJAXB(Java Architecture for XML Binding)を使用しているため、
単なるテンプレートエンジンにとどまらない使い方が可能です。
<br />
大きく分けて、Mixer2には次のような側面があります。
<br />
<ol>
<li>JSPやVelocityに代わる技術としてのMixer2</li>
<li>XHTMLパーサーとしてのMixer2</li>
<li>XHTMLタグスニペット生成器としてのMixer2</li>
</ol>
この記事では、3番目の、XHTMLタグスニペット生成器としてのMixer2の使い方を紹介します。
<br />
Mixer2は、XHTMLをパース - loadHtmlTemplate() - する場合には
フルHTML、つまり<html>...</html>までのHTML全体を与える必要があります。
<br />
しかしXHTMLタグを出力 - saveToString() - する場合には
任意のタグのみをString化することが可能です。
この特徴をうまく使えば、JSPのカスタムタグのようなものを
簡単なJavaコーディングのみで作ることができます。
<br />
たとえば、ベースとしてJSPを使いつつもMixer2を活用したい場合、下の図のような使い方が可能です。
<br />
<b><a href="http://3.bp.blogspot.com/-qOzmgy97bcw/UkpsiAIDGxI/AAAAAAAAALw/yfjNi9hjkjU/s1600/mixer2-as-tag-snippet-generator.png" imageanchor="1"><img border="0" src="http://3.bp.blogspot.com/-qOzmgy97bcw/UkpsiAIDGxI/AAAAAAAAALw/yfjNi9hjkjU/s320/mixer2-as-tag-snippet-generator.png" /></a></b>
<br />
タグを新規に作る場合は目的のタグ型クラスを new すればよいのですが、
TagCreatorクラスでも可能です。
TagCreatorのほうがeclipse等のIDE上でコード補完が効くので便利です。
<br />
<pre class="brush:java;">Div div = TagCreator.div();
Span span = TagCreator.span();
span.getContent().add("Hello World !");
span.setStyle("color:red;");
div.getContent().add(span);
String result = mixer2Engine.saveToString(div);
System.out.println(result);
</pre>
output:
<br />
<pre class="brush:html;"><div>
<span style="color: red;">Hello World !</span></div>
</pre>
table タグを作る場合にはTableBuilderクラスが便利です。
<br />
<pre class="brush:java;">String[][] data = new String[][]{
// id, name, price
{"1", "cookie", "2.50"},
{"2", "candy", "3.75"}
};
TableBuilder tBuilder = new TableBuilder();
for (String[] row : data) {
tBuilder
.addTr()
.addTd(row[0])
.addTd(row[1])
.addTd(row[2]);
}
Table table = tBuilder.build();
String str = mixer2Engine.saveToString(table);
System.out.println(str);
</pre>
output:
<br />
<pre class="brush:html;"><table>
<tbody>
<tr>
<td>1</td>
<td>cookie</td>
<td>2.50</td>
</tr>
<tr>
<td>2</td>
<td>candy</td>
<td>3.75</td>
</tr>
</tbody></table>
</pre>
For more detail of TableBuilder, see
<a href="http://mixer2.org/site/tablebuilder.html">Mixer2 official site</a>.
<br />
いかがでしたか?
できあがったタグオブジェクトをstring化したあとなら
jspやvelocityに埋め込むこともできます。
Mixer2と他のテンプレートエンジンの共存は十分に可能です。
ぜひ組み合わせ技も考えてみてください。
nabedgehttp://www.blogger.com/profile/15249139606699432144noreply@blogger.com0