Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
SpringMVCとmixer2で作るWebアプリのキホン
Search
Yu Watanabe
January 24, 2013
Technology
0
94
SpringMVCとmixer2で作る Webアプリのキホン
WebデザイナーフレンドリーなJavaテンプレートエンジン"Mixer2"と、SpringMVCフレームワークを組み合わせての開発
Yu Watanabe
January 24, 2013
Tweet
Share
More Decks by Yu Watanabe
See All by Yu Watanabe
JUnitテストをCI環境で並列で実行する方法とその速度, スケーラビリティ
nabedge
4
2k
クラウド時代だからSpring-Retryフレームワーク
nabedge
0
46
ツール比較しながら語るO/RマッパーとDBマイグレーション
nabedge
0
65
JavaでWebサービスを作り続けるための戦略と戦術
nabedge
0
39
サーバーサイドな人がフロントエンド技術と仲良くするはじめの一歩
nabedge
0
35
Selenium再入門
nabedge
0
36
Webエンジニアがスタートダッシュをキメるためのローカル開発環境の勘所
nabedge
0
38
テストゼロからイチに進むための戦略と戦術
nabedge
0
40
jOOQってなんて読むの?から始めるSpringBootとO/Rマッパーの世界
nabedge
0
72
Other Decks in Technology
See All in Technology
【Startup CTO of the Year 2024 / Audience Award】アセンド取締役CTO 丹羽健
niwatakeru
0
950
【Pycon mini 東海 2024】Google Colaboratoryで試すVLM
kazuhitotakahashi
2
490
Taming you application's environments
salaboy
0
180
複雑なState管理からの脱却
sansantech
PRO
1
140
AWS Media Services 最新サービスアップデート 2024
eijikominami
0
190
誰も全体を知らない ~ ロールの垣根を超えて引き上げる開発生産性 / Boosting Development Productivity Across Roles
kakehashi
1
220
ISUCONに強くなるかもしれない日々の過ごしかた/Findy ISUCON 2024-11-14
fujiwara3
8
870
なぜ今 AI Agent なのか _近藤憲児
kenjikondobai
4
1.3k
The Rise of LLMOps
asei
5
1.3k
Amazon CloudWatch Network Monitor のススメ
yuki_ink
1
200
dev 補講: プロダクトセキュリティ / Product security overview
wa6sn
1
2.3k
TypeScript、上達の瞬間
sadnessojisan
46
13k
Featured
See All Featured
Intergalactic Javascript Robots from Outer Space
tanoku
269
27k
Optimizing for Happiness
mojombo
376
70k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
126
18k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
506
140k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
27
4.3k
Designing for humans not robots
tammielis
250
25k
A designer walks into a library…
pauljervisheath
203
24k
The Cost Of JavaScript in 2023
addyosmani
45
6.7k
What's in a price? How to price your products and services
michaelherold
243
12k
How to train your dragon (web standard)
notwaldorf
88
5.7k
Speed Design
sergeychernyshev
24
610
10 Git Anti Patterns You Should be Aware of
lemiorhan
654
59k
Transcript
SpringMVCとmixer2で作る Webアプリのキホン Basic Web Application with SpringMVC & mixer2 Spring勉強会
by #JSUG at VMWare-Japan 2013-01-24
プロローグ PROLOGUE 2
クリスマスイブのとあるツイート 3
MacBookじゃなくてスイマセン... 4
SpringMVCとmixer2で作る Webアプリのキホン なんかこのタイトルもダサく 思えてきた...
とりあえずタイトル変えてみる!
Webデザイナーさんと 仲良く仕事するための SpringMVCとmixer2 2013-01-24 Spring勉強会
自己紹介 • わたなべ • SI屋の技術屋さん • @nabedge •
[email protected]
•
http://nabedge.blogspot.jp/ 8
目次 1. SpringMVC 2. テンプレートエンジン 3. Mixer2をHelloWorldで解説 4. Why mixer2
? 5. SpringMVCとmixer2の組み合わせの勘所 6. コントローラとビューに対するテスト 7. Webアプリの分割開発 8. まとめ 9. FAQ 9
10 1. Spring MVC
SpringMVC • JavaでWebアプリをつくりためのMVCフレー ムワーク。 • 生のサーブレット&JSPで作るより100倍作り やすい。 • 大昔のStrutsより10倍は学習しやすい •
ライバルとしてはSeasarのSAStrutsとか。 • Spring3.Xになって以降はSAStrutsよりもさら に使いやすくなった! • 詳しくは「Spring3入門」を読みましょう。 11
12 2. テンプレートエンジン
テンプレートエンジン 13 JSP:一番身近なテンプレートエンジン こんにちは <% if (name == null) {
%> ゲストさん <% } else { %> <%= name %>さん <% } %> 通常のJava言語、EL式、カスタムタグで書く
テンプレートエンジン 14 Velocity:Javaでは老舗のテンプレートエンジン こんにちは #if (name == null) { ゲストさん
#else ${name}さん #end VTL = Velocity Template Languageで書く
テンプレートエンジン 15 FreeMarker:最近人気のテンプレートエンジン こんにちは <#if name?has_content> ${name}さん <#else> ゲストさん </#if>
FTL = Freemarker Template Languageで書く
テンプレートエンジン 16 Mixer2:Webデザイナーと仲良く仕事するため のテンプレートエンジン こんにちは <span id=“name”>ななし</span>さん String name =
“ヤマダ”; Span span = html.getById(“name”, Span.class); span.getContent.clear(); span.getContent.add(name); // これで <span id=“name”>ヤマダ</span>さん // になる テンプレートファイル(*.html)は純粋なXHTMLとCSS 値の埋め込みやロジックは普通のJavaで書く(*.java)
17 3. mixer2を HelloWorld(SpringMVC編) で解説 http://mixer2.org/site/springmvcsample.html
補足:タグとJava型 18 <html>…</html> ⇔ org.mixer2.jaxb.xhtml.Html <div>…</div> ⇔ org.mixer2.jaxb.xhtml.Div (ほか全120種類くらいのタグすべてを実装済み) HTMLタグとJavaオブジェクトを相互マッピング
タグの属性はJavaオブジェクトのプロパティにマッピング。 setter/getterメソッドでアクセス <div id=“foo”>…</div> をテンプレートとしてロードすると String id = div.getId(); // これでidに”foo”が入る (html4/5のすべての属性を実装済み)
補足:複数要素はListになる 19 <html> <body> <p>Hello World</p> foo <span>bar</span> </body> </html>
index 型 0 P 1 String 2 Span Html html = mixer2Engine .loadHtmlTemplate( “template.html”); java.util.List<Object> list = html.getBody() .getContent(); listの中身 template.html
ちょっと一息 20 •水分補給 •時間を確認 10分か15分くらい?
21 4. Why mixer2 ?
最大のメリット 22 htmlモックアップを JSPに書き変えずに そのまま使える
23 デモ (フルーツショップサンプルアプリ編) https://github.com/nabedge/mixer2- sample/tree/master/mixer2-fruitshop-springmvc 「github mixer2-fruitshop-springmvc」 でググるとすぐ見つかります。
24 5. Mixer2とSpringMVCを 組み合わせる場合の勘所
勘所 1. コントローラクラスの肥大化を防ぐ 2. aタグやimgタグの相対パスの書き換え 3. <mvc:resources />で静的リソースを出 力 4.
上の2,3を生かすためのおススメディレ クトリ構造 25
26 コントローラクラスの肥大化を防ぐ
ふつうのコントローラとJSP 27 @Controller public class ItemController { @RequestMapping(value = "/item/{itemId}")
public ModelAndView showItem(@PathVariable long itemId) { // DBから商品情報を取得 Item item = itemService.getItem(itemId); // modelAndViewにitemを詰めて返す retern new ModelAndView(“item.jsp”, “item”, item); } <%@page pageEncoding="UTF-8"%> <html> <body> <span>商品名:${item.name}</span> </body> </html> 商品情報を表示するコントローラクラス JSP
コントローラの肥大化を防ぐ 28 @RequestMapping(value = "/item/{itemId}") public ModelAndView showItem(@PathVariable long itemId)
{ // DBから商品情報を取得 Item item = itemService.getItem(itemId); // テンプレートのロード String mainTemplate = "classpath:m2mockup/m2template/item.html" File file = ResourceUtils.getFile(mainTemplate); Html html = mixer2Engine.loadHtmlTemplate(file); // 商品情報のdivタグ Div itemBox = html.getBody().getById("itemBox", Div.class); // 商品名を書き込む itemBox.getById("itemName", H1.class).getContent().clear(); itemBox.getById("itemName", H1.class).getContent().add(item.getName()); // 価格、説明、その他もろもろも... このへんが肥大化 してしまう
コントローラの肥大化を防ぐ 29 @RequestMapping(value = "/item/{itemId}") public ModelAndView showItem(@PathVariable long itemId)
{ // DBから商品情報を取得 Item item = itemService.getItem(itemId); // テンプレートのロード String mainTemplate = "classpath:m2mockup/m2template/item.html" File file = ResourceUtils.getFile(mainTemplate); Html html = mixer2Engine.loadHtmlTemplate(file); // 商品情報を埋め込む ItemHelper.replaceItemBox(html, item); …… ヘルパークラスに切り 出せば1行で済む
コントローラの肥大化を防ぐ 30 public class ItemHelper { public static void replaceItemBox(Html
html, Item item) { // 商品情報を入れるdivタグを取得 Div itemBox = html.getBody().getById("itemBox", Div.class); // divの中のH1やSpanの中にDBから取得した値を入れる itemBox.getById("itemName", H1.class).getContent().clear(); itemBox.getById("itemName", H1.class).getContent().add(item.getName()); itemBox.getById("itemPrice", Span.class).getContent().clear(); itemBox.getById("itemPrice", Span.class).getContent().add( item.getPrice().toString()); itemBox.getById("itemDescription", Div.class).getContent().clear(); itemBox.getById("itemDescription", Div.class).getContent().add( item.getDescription()); ヘルパーはごく単純なstaticメソッドでよい テンプレのhtml DBから取得した商品情報
相対パスの書き換え 31 <a class=“topPageAnchor” href="../m2template/index.html"> <img src="../m2static/img/fruitshop-logo.png" /> </a> 左上のロゴはトップページへ
のリンク テンプレートファイルではこうなってるけど <a class=“topPageAnchor” href=“/[contextPath]/"> <img src="/[contextPath]/m2static/img/fruitshop-logo.png" /> </a> 実際の出力ではこうしなきゃならない
相対パスの書き換え 32 String ctx = "xxx"; // コンテキストパスを取得しておく for (A
a : html.getDescendants("topPageAnchor", A.class)) { a.setHref(ctx + "/"); } “topPageAnchor”というclass属性を持つすべてのaタグのhref属 性を書き変える Mixer2ではすべてのタグ型が下記のメソッドを持っている • getDescendants()メソッド:該当するすべての子孫タグをList で取得 • getById()メソッド:id属性でタグを1個だけ取得 • 他にもreplace系とかremove系のメソッドもあります。
相対パスの書き換え 33 // <img src="" /> for (Img img :
tagObj.getDescendants(Img.class)) { if (img.isSetSrc()) { String src = img.getSrc(); img.setSrc(convertPath(src)); } } Imgタグのsrc属性、styleタグのhref属性なども同様 convertPathメソッドは、 ../m2static/ のような文字列を /[contextPath]/m2static/ に置換している
34 <mvc:resources />で 静的リソースを出力
Java/Webアプリでの静的ファイルの配置 35 http://localhost:8080/[contextPath]/foo/bar.png src └─main ├─java ├─resources └─webapp └─foo └─bar.png
※maven標準ディレクトリ構造です 普通ならdocroot配下に置く。 さもないとブラウザからアク セス不可能
Java/Webアプリでの静的ファイルの配置 36 src └─main ├─java ├─resources │ │ applicationContext.xml │
│ │ └─m2mockup │ ├─m2static │ │ └─img │ │ logo.png │ │ │ └─m2template │ index.html │ item.html │ └─webapp テンプレートhtmlと画像 やCSSをまとめて resources配下に置く。 クラスパス上に置くほう が、Javaコードから扱い やすいから!
DispatcherServletのstatic resource機能 • Spring3.X以降、DispatcherServletは、http リクエストをコントローラクラスに中継する機 能だけでなく、静的リソースを直接レスポンス する機能がある 37
Java/Webアプリでの静的ファイルの配置 38 <mvc:resources mapping="/m2static/**" location="classpath:/m2mockup/m2static/" cache-period="60" /> src/main/resources/mvc-dispatcher-servlet.xml の抜粋 1.
http://.../contextPath/m2static/** というURLへの アクセスに対して 2. クラスパスから /m2mockup/m2static/** というリ ソースを探してそれを返す 3. そのとき Cache-Control: max-age=60 のような httpレスポンスヘッダつきで返す
ただし、注意しないと、、、! 39 src └─main ├─java ├─resources │ └─m2mockup │ ├─img
│ │ logo.png │ └─item.html └─webapp 1. こういうディレクトリ構造で <mvc:resources mapping= "/m2mockup/**" location= "classpath:/m2mockup/"/> 2. こういう設定をしてしまうと 3. 画像やCSSだけでなく、テンプレートhtmlにもそのままアクセス できてしまう!(もちろんまずい) http://…/[ContextPath]/m2mockup/img/logo.png http://…/[ContextPath]/m2mockup/item.html
だから、これがオススメ構造 40 src └─main ├─java ├─resources │ │ applicationContext.xml │
│ │ └─m2mockup │ ├─m2static │ │ └─img │ │ logo.png │ │ │ └─m2template │ index.html │ item.html │ └─webapp m2mockup配下にモック アップhtmlを作る 画像やCSSはm2static配下に 置いて、 <mvc:resources /> の設定での出力対象にする htmlテンプレートは m2template配下に
これでデザイナとプログラマが仲良く仕事できる! 41 プログラマとデザイナの取り決め事項 1. htmlモックアップは src/main/resources/m2mockup の下に作 ろうぜ。 2. ただし*.htmlはm2template,それ以外は
m2staticの配下でたのむ。 3. 商品情報のdivタグはid=“itemBox”にしよう。 4. 商品名はspanタグでid=“itemName” 5. …..その他の情報も同様にclass属性やid属性を決 めておけばよい。
42 もちろん 「htmlをjspに書き変える」 という退屈な作業は不要
43 6. コントローラとビューに対するテスト
ざっくりした流れ 1. JunitコードのランナーとしてSpringJUnit4ClassRunner を 使えば、DIコンテナが勝手にいい感じで起動してくれる。 2. HttpServletRequest, HttpServletResponseのモックをイン スタンス化する 3.
モックのrequestにテスト対象のURIやパラメータをセット 4. そのrequestオブジェクトをリクエストハンドラに渡すと疑似 リクエストが発生し、コントローラクラスに渡される。 5. コントローラの該当メソッドが戻り値として返す ModelAndViewオブジェクトにhtmlStringが入っている。 6. このhtmlStringの中をMixer2Engineで再度Htmlオブジェク ト化する 7. Htmlオブジェクトの中をAssertすればよい。 44
45 実際のテストコードで説明します https://github.com/nabedge/mixer2- sample/blob/master/mixer2-fruitshop- springmvc/src/test/java/org/mixer2/samp le/web/controller/ItemControllerTest.java
最後の給水 46 •水分補給 •時間を確認 40分くらい?
47 Webアプリの分割開発
普通のWebアプリプロジェクト(maven形式) 48 Javaクラスとか このへん Javaクラス以外は src/main/webapp 静的ファイル このへん JSPとか このへん
普通のWebアプリを分割開発するときのカベ 1. Javaクラスや、その設定ファイル (*.properties,*.xml,*.sql)は別プロジェクト化 してjar化してWebアプリ側から依存関係を つくればいい。 – つまり、Javaライブラリは分割開発可能 2. しかし、src/main/webapp
配下に置くような JSP,静的リソース、設定ファイル類(MVCで 言うとViewの周辺)は、プロジェクト分割& 別パッケージ化が難しい。 49
Mixer2を使うと 1. Mixer2は、Viewを普通のjavaコードで取 扱う。 2. そのテンプレートもJavaコードから見ると ただのリソースファイルとして扱える。 3. よって、普通のJavaライブラリ同様に分割 が可能。
50
デモ • デモでお見せします。 プロジェクト間依存関係はこんな感 じ m2flowershop-web(.war) m2flowershop-front(.jar) m2flowershop-cart(.jar) m2flowershop-resource(.jar) 51
後日談 • ※結局、当日までにサンプルのコーディング が間に合わなかったのでこのデモはやってま せん。(^^; 52
53 7. まとめ
まとめ • SpringMVCはシンプルで使いやすいフレームワーク • mixer2とSpringMVCは良いコンビ • ディレクトリ構造を考えたうえでSpringMVCの静的リ ソース出力機能と組み合わせれば、htmlモックアップ をjspに書き変える作業は不要 •
jspでは難しい、ビューに対するテストの自動化も可 能 • htmlテンプレートファイルと静的ファイル(ex.画像)と Javaクラスをjarパッケージ化できるので、Webアプリ の分割開発すら可能。 54
FAQ • Q. モックアップHTMLはクラスパス上に置かなきゃダメですか? – A. Mixer2EngineのloadHtmlTemplateメソッドはjava.io.File, String, StringBufferのいずれかでテンプレートhtmlを読めます。したがってOSのファイ ルシステム上でもDB上でもどこでもOKです。
– ※後日談:ver1.1.14 以降、InputStreamからも読めるようになりました。 • Q. WEB-INF/view/mixer2view.jsp を通じて結局jspを使っているのはダ サくないですか? – A. 実はその通りです。本来は、コントローラのメソッドの戻り値としてHtmlオブ ジェクトを返すだけで済むようなViewResolverを実装するべきです。誰か作っ て!(Pull Request熱烈歓迎!) • Q. mixer2を使う場合はJSPは完全に排除しなきゃだめですか?既存の taglibも使いたいのですが? – A. 可能です。たとえば、 *.htmlで用意したテンプレートを読み込んで、その一部 のタグだけを部分マーシャルし、jsp上に埋め込むことも可能です。 55
56 ご静聴ありがとうございました