springmvcとmixer2で作るwebアプリのキホン 2013-01-24 spring勉強会 #jsug

56
SpringMVCmixer2で作る Webアプリのキホン Basic Web Application with SpringMVC & mixer2 Spring勉強会 by #JSUG at VMWare-Japan 2013-01-24

Upload: yu-watanabe

Post on 22-Apr-2015

4.786 views

Category:

Technology


2 download

DESCRIPTION

 

TRANSCRIPT

Page 1: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

SpringMVCとmixer2で作る

Webアプリのキホン

Basic Web Application

with SpringMVC amp 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勉強会

自己紹介

bull わたなべ

bull SI屋の技術屋さん

bull nabedge

bull nabedgegmailcom

bull httpnabedgeblogspotjp

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

bull JavaでWebアプリをつくりためのMVCフレームワーク

bull 生のサーブレットJSPで作るより100倍作りやすい

bull 大昔のStrutsより10倍は学習しやすい

bull ライバルとしてはSeasarのSAStrutsとか

bull Spring3Xになって以降はSAStrutsよりもさらに使いやすくなった

bull 詳しくは「Spring3入門」を読みましょう

11

12

2 テンプレートエンジン

テンプレートエンジン

13

JSP一番身近なテンプレートエンジン

こんにちは

lt if (name == null) gt

ゲストさん

lt else gt

lt= name gtさん

lt gt

通常のJava言語EL式カスタムタグで書く

テンプレートエンジン

14

VelocityJavaでは老舗のテンプレートエンジン

こんにちは

if (name == null)

ゲストさん

else

$nameさん

end

VTL = Velocity Template Languageで書く

テンプレートエンジン

15

FreeMarker最近人気のテンプレートエンジン

こんにちは

ltif namehas_contentgt

$nameさん

ltelsegt

ゲストさん

ltifgt

FTL = Freemarker Template Languageで書く

テンプレートエンジン

16

Mixer2Webデザイナーと仲良く仕事するためのテンプレートエンジン

こんにちは

ltspan id=ldquonamerdquogtななしltspangtさん

String name = ldquoヤマダrdquo

Span span = htmlgetById(ldquonamerdquo Spanclass)

spangetContentclear()

spangetContentadd(name)

これで ltspan id=ldquonamerdquogtヤマダltspangtさん

になる

テンプレートファイル(html)は純粋なXHTMLとCSS

値の埋め込みやロジックは普通のJavaで書く(java)

17

3 mixer2を

HelloWorld(SpringMVC編) で解説

httpmixer2orgsitespringmvcsamplehtml

補足タグとJava型

18

lthtmlgthelliplthtmlgt hArr orgmixer2jaxbxhtmlHtml

ltdivgthellipltdivgt hArr orgmixer2jaxbxhtmlDiv

(ほか全120種類くらいのタグすべてを実装済み)

HTMLタグとJavaオブジェクトを相互マッピング

タグの属性はJavaオブジェクトのプロパティにマッピングsettergetterメソッドでアクセス

ltdiv id=ldquofoordquogthellipltdivgt

をテンプレートとしてロードすると

String id = divgetId() これでidにrdquofoordquoが入る

(html45のすべての属性を実装済み)

補足複数要素はListになる

19

lthtmlgt

ltbodygt

ltpgtHello Worldltpgt

foo

ltspangtbarltspangt

ltbodygt

lthtmlgt

index 型

0 P

1 String

2 Span

Html html = mixer2Engine

loadHtmlTemplate(

ldquotemplatehtmlrdquo)

javautilListltObjectgt list

= htmlgetBody()

getContent()

listの中身 templatehtml

ちょっと一息

20

bull水分補給

bull時間を確認 10分か15分くらい

21

4 Why mixer2

最大のメリット

22

htmlモックアップを

JSPに書き変えずに

そのまま使える

23

デモ (フルーツショップサンプルアプリ編)

httpsgithubcomnabedgemixer2-

sampletreemastermixer2-fruitshop-springmvc

「github mixer2-fruitshop-springmvc」 でググるとすぐ見つかります

24

5 Mixer2とSpringMVCを

組み合わせる場合の勘所

勘所

1 コントローラクラスの肥大化を防ぐ

2 aタグやimgタグの相対パスの書き換え

3 ltmvcresources gtで静的リソースを出力

4 上の23を生かすためのおススメディレクトリ構造

25

26

コントローラクラスの肥大化を防ぐ

ふつうのコントローラとJSP

27

Controller

public class ItemController

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

modelAndViewにitemを詰めて返す

retern new ModelAndView(ldquoitemjsprdquo ldquoitemrdquo item)

ltpage pageEncoding=UTF-8gt

lthtmlgt

ltbodygt

ltspangt商品名$itemnameltspangt

ltbodygt

lthtmlgt

商品情報を表示するコントローラクラス

JSP

コントローラの肥大化を防ぐ

28

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報のdivタグ

Div itemBox = htmlgetBody()getById(itemBox Divclass)

商品名を書き込む

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

価格説明その他もろもろも

このへんが肥大化してしまう

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 2: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

プロローグ PROLOGUE

2

クリスマスイブのとあるツイート

3

MacBookじゃなくてスイマセン

4

SpringMVCとmixer2で作る

Webアプリのキホン

なんかこのタイトルもダサく思えてきた

とりあえずタイトル変えてみる

Webデザイナーさんと

仲良く仕事するための

SpringMVCとmixer2

2013-01-24

Spring勉強会

自己紹介

bull わたなべ

bull SI屋の技術屋さん

bull nabedge

bull nabedgegmailcom

bull httpnabedgeblogspotjp

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

bull JavaでWebアプリをつくりためのMVCフレームワーク

bull 生のサーブレットJSPで作るより100倍作りやすい

bull 大昔のStrutsより10倍は学習しやすい

bull ライバルとしてはSeasarのSAStrutsとか

bull Spring3Xになって以降はSAStrutsよりもさらに使いやすくなった

bull 詳しくは「Spring3入門」を読みましょう

11

12

2 テンプレートエンジン

テンプレートエンジン

13

JSP一番身近なテンプレートエンジン

こんにちは

lt if (name == null) gt

ゲストさん

lt else gt

lt= name gtさん

lt gt

通常のJava言語EL式カスタムタグで書く

テンプレートエンジン

14

VelocityJavaでは老舗のテンプレートエンジン

こんにちは

if (name == null)

ゲストさん

else

$nameさん

end

VTL = Velocity Template Languageで書く

テンプレートエンジン

15

FreeMarker最近人気のテンプレートエンジン

こんにちは

ltif namehas_contentgt

$nameさん

ltelsegt

ゲストさん

ltifgt

FTL = Freemarker Template Languageで書く

テンプレートエンジン

16

Mixer2Webデザイナーと仲良く仕事するためのテンプレートエンジン

こんにちは

ltspan id=ldquonamerdquogtななしltspangtさん

String name = ldquoヤマダrdquo

Span span = htmlgetById(ldquonamerdquo Spanclass)

spangetContentclear()

spangetContentadd(name)

これで ltspan id=ldquonamerdquogtヤマダltspangtさん

になる

テンプレートファイル(html)は純粋なXHTMLとCSS

値の埋め込みやロジックは普通のJavaで書く(java)

17

3 mixer2を

HelloWorld(SpringMVC編) で解説

httpmixer2orgsitespringmvcsamplehtml

補足タグとJava型

18

lthtmlgthelliplthtmlgt hArr orgmixer2jaxbxhtmlHtml

ltdivgthellipltdivgt hArr orgmixer2jaxbxhtmlDiv

(ほか全120種類くらいのタグすべてを実装済み)

HTMLタグとJavaオブジェクトを相互マッピング

タグの属性はJavaオブジェクトのプロパティにマッピングsettergetterメソッドでアクセス

ltdiv id=ldquofoordquogthellipltdivgt

をテンプレートとしてロードすると

String id = divgetId() これでidにrdquofoordquoが入る

(html45のすべての属性を実装済み)

補足複数要素はListになる

19

lthtmlgt

ltbodygt

ltpgtHello Worldltpgt

foo

ltspangtbarltspangt

ltbodygt

lthtmlgt

index 型

0 P

1 String

2 Span

Html html = mixer2Engine

loadHtmlTemplate(

ldquotemplatehtmlrdquo)

javautilListltObjectgt list

= htmlgetBody()

getContent()

listの中身 templatehtml

ちょっと一息

20

bull水分補給

bull時間を確認 10分か15分くらい

21

4 Why mixer2

最大のメリット

22

htmlモックアップを

JSPに書き変えずに

そのまま使える

23

デモ (フルーツショップサンプルアプリ編)

httpsgithubcomnabedgemixer2-

sampletreemastermixer2-fruitshop-springmvc

「github mixer2-fruitshop-springmvc」 でググるとすぐ見つかります

24

5 Mixer2とSpringMVCを

組み合わせる場合の勘所

勘所

1 コントローラクラスの肥大化を防ぐ

2 aタグやimgタグの相対パスの書き換え

3 ltmvcresources gtで静的リソースを出力

4 上の23を生かすためのおススメディレクトリ構造

25

26

コントローラクラスの肥大化を防ぐ

ふつうのコントローラとJSP

27

Controller

public class ItemController

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

modelAndViewにitemを詰めて返す

retern new ModelAndView(ldquoitemjsprdquo ldquoitemrdquo item)

ltpage pageEncoding=UTF-8gt

lthtmlgt

ltbodygt

ltspangt商品名$itemnameltspangt

ltbodygt

lthtmlgt

商品情報を表示するコントローラクラス

JSP

コントローラの肥大化を防ぐ

28

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報のdivタグ

Div itemBox = htmlgetBody()getById(itemBox Divclass)

商品名を書き込む

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

価格説明その他もろもろも

このへんが肥大化してしまう

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 3: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

クリスマスイブのとあるツイート

3

MacBookじゃなくてスイマセン

4

SpringMVCとmixer2で作る

Webアプリのキホン

なんかこのタイトルもダサく思えてきた

とりあえずタイトル変えてみる

Webデザイナーさんと

仲良く仕事するための

SpringMVCとmixer2

2013-01-24

Spring勉強会

自己紹介

bull わたなべ

bull SI屋の技術屋さん

bull nabedge

bull nabedgegmailcom

bull httpnabedgeblogspotjp

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

bull JavaでWebアプリをつくりためのMVCフレームワーク

bull 生のサーブレットJSPで作るより100倍作りやすい

bull 大昔のStrutsより10倍は学習しやすい

bull ライバルとしてはSeasarのSAStrutsとか

bull Spring3Xになって以降はSAStrutsよりもさらに使いやすくなった

bull 詳しくは「Spring3入門」を読みましょう

11

12

2 テンプレートエンジン

テンプレートエンジン

13

JSP一番身近なテンプレートエンジン

こんにちは

lt if (name == null) gt

ゲストさん

lt else gt

lt= name gtさん

lt gt

通常のJava言語EL式カスタムタグで書く

テンプレートエンジン

14

VelocityJavaでは老舗のテンプレートエンジン

こんにちは

if (name == null)

ゲストさん

else

$nameさん

end

VTL = Velocity Template Languageで書く

テンプレートエンジン

15

FreeMarker最近人気のテンプレートエンジン

こんにちは

ltif namehas_contentgt

$nameさん

ltelsegt

ゲストさん

ltifgt

FTL = Freemarker Template Languageで書く

テンプレートエンジン

16

Mixer2Webデザイナーと仲良く仕事するためのテンプレートエンジン

こんにちは

ltspan id=ldquonamerdquogtななしltspangtさん

String name = ldquoヤマダrdquo

Span span = htmlgetById(ldquonamerdquo Spanclass)

spangetContentclear()

spangetContentadd(name)

これで ltspan id=ldquonamerdquogtヤマダltspangtさん

になる

テンプレートファイル(html)は純粋なXHTMLとCSS

値の埋め込みやロジックは普通のJavaで書く(java)

17

3 mixer2を

HelloWorld(SpringMVC編) で解説

httpmixer2orgsitespringmvcsamplehtml

補足タグとJava型

18

lthtmlgthelliplthtmlgt hArr orgmixer2jaxbxhtmlHtml

ltdivgthellipltdivgt hArr orgmixer2jaxbxhtmlDiv

(ほか全120種類くらいのタグすべてを実装済み)

HTMLタグとJavaオブジェクトを相互マッピング

タグの属性はJavaオブジェクトのプロパティにマッピングsettergetterメソッドでアクセス

ltdiv id=ldquofoordquogthellipltdivgt

をテンプレートとしてロードすると

String id = divgetId() これでidにrdquofoordquoが入る

(html45のすべての属性を実装済み)

補足複数要素はListになる

19

lthtmlgt

ltbodygt

ltpgtHello Worldltpgt

foo

ltspangtbarltspangt

ltbodygt

lthtmlgt

index 型

0 P

1 String

2 Span

Html html = mixer2Engine

loadHtmlTemplate(

ldquotemplatehtmlrdquo)

javautilListltObjectgt list

= htmlgetBody()

getContent()

listの中身 templatehtml

ちょっと一息

20

bull水分補給

bull時間を確認 10分か15分くらい

21

4 Why mixer2

最大のメリット

22

htmlモックアップを

JSPに書き変えずに

そのまま使える

23

デモ (フルーツショップサンプルアプリ編)

httpsgithubcomnabedgemixer2-

sampletreemastermixer2-fruitshop-springmvc

「github mixer2-fruitshop-springmvc」 でググるとすぐ見つかります

24

5 Mixer2とSpringMVCを

組み合わせる場合の勘所

勘所

1 コントローラクラスの肥大化を防ぐ

2 aタグやimgタグの相対パスの書き換え

3 ltmvcresources gtで静的リソースを出力

4 上の23を生かすためのおススメディレクトリ構造

25

26

コントローラクラスの肥大化を防ぐ

ふつうのコントローラとJSP

27

Controller

public class ItemController

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

modelAndViewにitemを詰めて返す

retern new ModelAndView(ldquoitemjsprdquo ldquoitemrdquo item)

ltpage pageEncoding=UTF-8gt

lthtmlgt

ltbodygt

ltspangt商品名$itemnameltspangt

ltbodygt

lthtmlgt

商品情報を表示するコントローラクラス

JSP

コントローラの肥大化を防ぐ

28

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報のdivタグ

Div itemBox = htmlgetBody()getById(itemBox Divclass)

商品名を書き込む

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

価格説明その他もろもろも

このへんが肥大化してしまう

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 4: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

MacBookじゃなくてスイマセン

4

SpringMVCとmixer2で作る

Webアプリのキホン

なんかこのタイトルもダサく思えてきた

とりあえずタイトル変えてみる

Webデザイナーさんと

仲良く仕事するための

SpringMVCとmixer2

2013-01-24

Spring勉強会

自己紹介

bull わたなべ

bull SI屋の技術屋さん

bull nabedge

bull nabedgegmailcom

bull httpnabedgeblogspotjp

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

bull JavaでWebアプリをつくりためのMVCフレームワーク

bull 生のサーブレットJSPで作るより100倍作りやすい

bull 大昔のStrutsより10倍は学習しやすい

bull ライバルとしてはSeasarのSAStrutsとか

bull Spring3Xになって以降はSAStrutsよりもさらに使いやすくなった

bull 詳しくは「Spring3入門」を読みましょう

11

12

2 テンプレートエンジン

テンプレートエンジン

13

JSP一番身近なテンプレートエンジン

こんにちは

lt if (name == null) gt

ゲストさん

lt else gt

lt= name gtさん

lt gt

通常のJava言語EL式カスタムタグで書く

テンプレートエンジン

14

VelocityJavaでは老舗のテンプレートエンジン

こんにちは

if (name == null)

ゲストさん

else

$nameさん

end

VTL = Velocity Template Languageで書く

テンプレートエンジン

15

FreeMarker最近人気のテンプレートエンジン

こんにちは

ltif namehas_contentgt

$nameさん

ltelsegt

ゲストさん

ltifgt

FTL = Freemarker Template Languageで書く

テンプレートエンジン

16

Mixer2Webデザイナーと仲良く仕事するためのテンプレートエンジン

こんにちは

ltspan id=ldquonamerdquogtななしltspangtさん

String name = ldquoヤマダrdquo

Span span = htmlgetById(ldquonamerdquo Spanclass)

spangetContentclear()

spangetContentadd(name)

これで ltspan id=ldquonamerdquogtヤマダltspangtさん

になる

テンプレートファイル(html)は純粋なXHTMLとCSS

値の埋め込みやロジックは普通のJavaで書く(java)

17

3 mixer2を

HelloWorld(SpringMVC編) で解説

httpmixer2orgsitespringmvcsamplehtml

補足タグとJava型

18

lthtmlgthelliplthtmlgt hArr orgmixer2jaxbxhtmlHtml

ltdivgthellipltdivgt hArr orgmixer2jaxbxhtmlDiv

(ほか全120種類くらいのタグすべてを実装済み)

HTMLタグとJavaオブジェクトを相互マッピング

タグの属性はJavaオブジェクトのプロパティにマッピングsettergetterメソッドでアクセス

ltdiv id=ldquofoordquogthellipltdivgt

をテンプレートとしてロードすると

String id = divgetId() これでidにrdquofoordquoが入る

(html45のすべての属性を実装済み)

補足複数要素はListになる

19

lthtmlgt

ltbodygt

ltpgtHello Worldltpgt

foo

ltspangtbarltspangt

ltbodygt

lthtmlgt

index 型

0 P

1 String

2 Span

Html html = mixer2Engine

loadHtmlTemplate(

ldquotemplatehtmlrdquo)

javautilListltObjectgt list

= htmlgetBody()

getContent()

listの中身 templatehtml

ちょっと一息

20

bull水分補給

bull時間を確認 10分か15分くらい

21

4 Why mixer2

最大のメリット

22

htmlモックアップを

JSPに書き変えずに

そのまま使える

23

デモ (フルーツショップサンプルアプリ編)

httpsgithubcomnabedgemixer2-

sampletreemastermixer2-fruitshop-springmvc

「github mixer2-fruitshop-springmvc」 でググるとすぐ見つかります

24

5 Mixer2とSpringMVCを

組み合わせる場合の勘所

勘所

1 コントローラクラスの肥大化を防ぐ

2 aタグやimgタグの相対パスの書き換え

3 ltmvcresources gtで静的リソースを出力

4 上の23を生かすためのおススメディレクトリ構造

25

26

コントローラクラスの肥大化を防ぐ

ふつうのコントローラとJSP

27

Controller

public class ItemController

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

modelAndViewにitemを詰めて返す

retern new ModelAndView(ldquoitemjsprdquo ldquoitemrdquo item)

ltpage pageEncoding=UTF-8gt

lthtmlgt

ltbodygt

ltspangt商品名$itemnameltspangt

ltbodygt

lthtmlgt

商品情報を表示するコントローラクラス

JSP

コントローラの肥大化を防ぐ

28

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報のdivタグ

Div itemBox = htmlgetBody()getById(itemBox Divclass)

商品名を書き込む

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

価格説明その他もろもろも

このへんが肥大化してしまう

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 5: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

SpringMVCとmixer2で作る

Webアプリのキホン

なんかこのタイトルもダサく思えてきた

とりあえずタイトル変えてみる

Webデザイナーさんと

仲良く仕事するための

SpringMVCとmixer2

2013-01-24

Spring勉強会

自己紹介

bull わたなべ

bull SI屋の技術屋さん

bull nabedge

bull nabedgegmailcom

bull httpnabedgeblogspotjp

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

bull JavaでWebアプリをつくりためのMVCフレームワーク

bull 生のサーブレットJSPで作るより100倍作りやすい

bull 大昔のStrutsより10倍は学習しやすい

bull ライバルとしてはSeasarのSAStrutsとか

bull Spring3Xになって以降はSAStrutsよりもさらに使いやすくなった

bull 詳しくは「Spring3入門」を読みましょう

11

12

2 テンプレートエンジン

テンプレートエンジン

13

JSP一番身近なテンプレートエンジン

こんにちは

lt if (name == null) gt

ゲストさん

lt else gt

lt= name gtさん

lt gt

通常のJava言語EL式カスタムタグで書く

テンプレートエンジン

14

VelocityJavaでは老舗のテンプレートエンジン

こんにちは

if (name == null)

ゲストさん

else

$nameさん

end

VTL = Velocity Template Languageで書く

テンプレートエンジン

15

FreeMarker最近人気のテンプレートエンジン

こんにちは

ltif namehas_contentgt

$nameさん

ltelsegt

ゲストさん

ltifgt

FTL = Freemarker Template Languageで書く

テンプレートエンジン

16

Mixer2Webデザイナーと仲良く仕事するためのテンプレートエンジン

こんにちは

ltspan id=ldquonamerdquogtななしltspangtさん

String name = ldquoヤマダrdquo

Span span = htmlgetById(ldquonamerdquo Spanclass)

spangetContentclear()

spangetContentadd(name)

これで ltspan id=ldquonamerdquogtヤマダltspangtさん

になる

テンプレートファイル(html)は純粋なXHTMLとCSS

値の埋め込みやロジックは普通のJavaで書く(java)

17

3 mixer2を

HelloWorld(SpringMVC編) で解説

httpmixer2orgsitespringmvcsamplehtml

補足タグとJava型

18

lthtmlgthelliplthtmlgt hArr orgmixer2jaxbxhtmlHtml

ltdivgthellipltdivgt hArr orgmixer2jaxbxhtmlDiv

(ほか全120種類くらいのタグすべてを実装済み)

HTMLタグとJavaオブジェクトを相互マッピング

タグの属性はJavaオブジェクトのプロパティにマッピングsettergetterメソッドでアクセス

ltdiv id=ldquofoordquogthellipltdivgt

をテンプレートとしてロードすると

String id = divgetId() これでidにrdquofoordquoが入る

(html45のすべての属性を実装済み)

補足複数要素はListになる

19

lthtmlgt

ltbodygt

ltpgtHello Worldltpgt

foo

ltspangtbarltspangt

ltbodygt

lthtmlgt

index 型

0 P

1 String

2 Span

Html html = mixer2Engine

loadHtmlTemplate(

ldquotemplatehtmlrdquo)

javautilListltObjectgt list

= htmlgetBody()

getContent()

listの中身 templatehtml

ちょっと一息

20

bull水分補給

bull時間を確認 10分か15分くらい

21

4 Why mixer2

最大のメリット

22

htmlモックアップを

JSPに書き変えずに

そのまま使える

23

デモ (フルーツショップサンプルアプリ編)

httpsgithubcomnabedgemixer2-

sampletreemastermixer2-fruitshop-springmvc

「github mixer2-fruitshop-springmvc」 でググるとすぐ見つかります

24

5 Mixer2とSpringMVCを

組み合わせる場合の勘所

勘所

1 コントローラクラスの肥大化を防ぐ

2 aタグやimgタグの相対パスの書き換え

3 ltmvcresources gtで静的リソースを出力

4 上の23を生かすためのおススメディレクトリ構造

25

26

コントローラクラスの肥大化を防ぐ

ふつうのコントローラとJSP

27

Controller

public class ItemController

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

modelAndViewにitemを詰めて返す

retern new ModelAndView(ldquoitemjsprdquo ldquoitemrdquo item)

ltpage pageEncoding=UTF-8gt

lthtmlgt

ltbodygt

ltspangt商品名$itemnameltspangt

ltbodygt

lthtmlgt

商品情報を表示するコントローラクラス

JSP

コントローラの肥大化を防ぐ

28

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報のdivタグ

Div itemBox = htmlgetBody()getById(itemBox Divclass)

商品名を書き込む

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

価格説明その他もろもろも

このへんが肥大化してしまう

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 6: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

とりあえずタイトル変えてみる

Webデザイナーさんと

仲良く仕事するための

SpringMVCとmixer2

2013-01-24

Spring勉強会

自己紹介

bull わたなべ

bull SI屋の技術屋さん

bull nabedge

bull nabedgegmailcom

bull httpnabedgeblogspotjp

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

bull JavaでWebアプリをつくりためのMVCフレームワーク

bull 生のサーブレットJSPで作るより100倍作りやすい

bull 大昔のStrutsより10倍は学習しやすい

bull ライバルとしてはSeasarのSAStrutsとか

bull Spring3Xになって以降はSAStrutsよりもさらに使いやすくなった

bull 詳しくは「Spring3入門」を読みましょう

11

12

2 テンプレートエンジン

テンプレートエンジン

13

JSP一番身近なテンプレートエンジン

こんにちは

lt if (name == null) gt

ゲストさん

lt else gt

lt= name gtさん

lt gt

通常のJava言語EL式カスタムタグで書く

テンプレートエンジン

14

VelocityJavaでは老舗のテンプレートエンジン

こんにちは

if (name == null)

ゲストさん

else

$nameさん

end

VTL = Velocity Template Languageで書く

テンプレートエンジン

15

FreeMarker最近人気のテンプレートエンジン

こんにちは

ltif namehas_contentgt

$nameさん

ltelsegt

ゲストさん

ltifgt

FTL = Freemarker Template Languageで書く

テンプレートエンジン

16

Mixer2Webデザイナーと仲良く仕事するためのテンプレートエンジン

こんにちは

ltspan id=ldquonamerdquogtななしltspangtさん

String name = ldquoヤマダrdquo

Span span = htmlgetById(ldquonamerdquo Spanclass)

spangetContentclear()

spangetContentadd(name)

これで ltspan id=ldquonamerdquogtヤマダltspangtさん

になる

テンプレートファイル(html)は純粋なXHTMLとCSS

値の埋め込みやロジックは普通のJavaで書く(java)

17

3 mixer2を

HelloWorld(SpringMVC編) で解説

httpmixer2orgsitespringmvcsamplehtml

補足タグとJava型

18

lthtmlgthelliplthtmlgt hArr orgmixer2jaxbxhtmlHtml

ltdivgthellipltdivgt hArr orgmixer2jaxbxhtmlDiv

(ほか全120種類くらいのタグすべてを実装済み)

HTMLタグとJavaオブジェクトを相互マッピング

タグの属性はJavaオブジェクトのプロパティにマッピングsettergetterメソッドでアクセス

ltdiv id=ldquofoordquogthellipltdivgt

をテンプレートとしてロードすると

String id = divgetId() これでidにrdquofoordquoが入る

(html45のすべての属性を実装済み)

補足複数要素はListになる

19

lthtmlgt

ltbodygt

ltpgtHello Worldltpgt

foo

ltspangtbarltspangt

ltbodygt

lthtmlgt

index 型

0 P

1 String

2 Span

Html html = mixer2Engine

loadHtmlTemplate(

ldquotemplatehtmlrdquo)

javautilListltObjectgt list

= htmlgetBody()

getContent()

listの中身 templatehtml

ちょっと一息

20

bull水分補給

bull時間を確認 10分か15分くらい

21

4 Why mixer2

最大のメリット

22

htmlモックアップを

JSPに書き変えずに

そのまま使える

23

デモ (フルーツショップサンプルアプリ編)

httpsgithubcomnabedgemixer2-

sampletreemastermixer2-fruitshop-springmvc

「github mixer2-fruitshop-springmvc」 でググるとすぐ見つかります

24

5 Mixer2とSpringMVCを

組み合わせる場合の勘所

勘所

1 コントローラクラスの肥大化を防ぐ

2 aタグやimgタグの相対パスの書き換え

3 ltmvcresources gtで静的リソースを出力

4 上の23を生かすためのおススメディレクトリ構造

25

26

コントローラクラスの肥大化を防ぐ

ふつうのコントローラとJSP

27

Controller

public class ItemController

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

modelAndViewにitemを詰めて返す

retern new ModelAndView(ldquoitemjsprdquo ldquoitemrdquo item)

ltpage pageEncoding=UTF-8gt

lthtmlgt

ltbodygt

ltspangt商品名$itemnameltspangt

ltbodygt

lthtmlgt

商品情報を表示するコントローラクラス

JSP

コントローラの肥大化を防ぐ

28

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報のdivタグ

Div itemBox = htmlgetBody()getById(itemBox Divclass)

商品名を書き込む

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

価格説明その他もろもろも

このへんが肥大化してしまう

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 7: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

Webデザイナーさんと

仲良く仕事するための

SpringMVCとmixer2

2013-01-24

Spring勉強会

自己紹介

bull わたなべ

bull SI屋の技術屋さん

bull nabedge

bull nabedgegmailcom

bull httpnabedgeblogspotjp

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

bull JavaでWebアプリをつくりためのMVCフレームワーク

bull 生のサーブレットJSPで作るより100倍作りやすい

bull 大昔のStrutsより10倍は学習しやすい

bull ライバルとしてはSeasarのSAStrutsとか

bull Spring3Xになって以降はSAStrutsよりもさらに使いやすくなった

bull 詳しくは「Spring3入門」を読みましょう

11

12

2 テンプレートエンジン

テンプレートエンジン

13

JSP一番身近なテンプレートエンジン

こんにちは

lt if (name == null) gt

ゲストさん

lt else gt

lt= name gtさん

lt gt

通常のJava言語EL式カスタムタグで書く

テンプレートエンジン

14

VelocityJavaでは老舗のテンプレートエンジン

こんにちは

if (name == null)

ゲストさん

else

$nameさん

end

VTL = Velocity Template Languageで書く

テンプレートエンジン

15

FreeMarker最近人気のテンプレートエンジン

こんにちは

ltif namehas_contentgt

$nameさん

ltelsegt

ゲストさん

ltifgt

FTL = Freemarker Template Languageで書く

テンプレートエンジン

16

Mixer2Webデザイナーと仲良く仕事するためのテンプレートエンジン

こんにちは

ltspan id=ldquonamerdquogtななしltspangtさん

String name = ldquoヤマダrdquo

Span span = htmlgetById(ldquonamerdquo Spanclass)

spangetContentclear()

spangetContentadd(name)

これで ltspan id=ldquonamerdquogtヤマダltspangtさん

になる

テンプレートファイル(html)は純粋なXHTMLとCSS

値の埋め込みやロジックは普通のJavaで書く(java)

17

3 mixer2を

HelloWorld(SpringMVC編) で解説

httpmixer2orgsitespringmvcsamplehtml

補足タグとJava型

18

lthtmlgthelliplthtmlgt hArr orgmixer2jaxbxhtmlHtml

ltdivgthellipltdivgt hArr orgmixer2jaxbxhtmlDiv

(ほか全120種類くらいのタグすべてを実装済み)

HTMLタグとJavaオブジェクトを相互マッピング

タグの属性はJavaオブジェクトのプロパティにマッピングsettergetterメソッドでアクセス

ltdiv id=ldquofoordquogthellipltdivgt

をテンプレートとしてロードすると

String id = divgetId() これでidにrdquofoordquoが入る

(html45のすべての属性を実装済み)

補足複数要素はListになる

19

lthtmlgt

ltbodygt

ltpgtHello Worldltpgt

foo

ltspangtbarltspangt

ltbodygt

lthtmlgt

index 型

0 P

1 String

2 Span

Html html = mixer2Engine

loadHtmlTemplate(

ldquotemplatehtmlrdquo)

javautilListltObjectgt list

= htmlgetBody()

getContent()

listの中身 templatehtml

ちょっと一息

20

bull水分補給

bull時間を確認 10分か15分くらい

21

4 Why mixer2

最大のメリット

22

htmlモックアップを

JSPに書き変えずに

そのまま使える

23

デモ (フルーツショップサンプルアプリ編)

httpsgithubcomnabedgemixer2-

sampletreemastermixer2-fruitshop-springmvc

「github mixer2-fruitshop-springmvc」 でググるとすぐ見つかります

24

5 Mixer2とSpringMVCを

組み合わせる場合の勘所

勘所

1 コントローラクラスの肥大化を防ぐ

2 aタグやimgタグの相対パスの書き換え

3 ltmvcresources gtで静的リソースを出力

4 上の23を生かすためのおススメディレクトリ構造

25

26

コントローラクラスの肥大化を防ぐ

ふつうのコントローラとJSP

27

Controller

public class ItemController

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

modelAndViewにitemを詰めて返す

retern new ModelAndView(ldquoitemjsprdquo ldquoitemrdquo item)

ltpage pageEncoding=UTF-8gt

lthtmlgt

ltbodygt

ltspangt商品名$itemnameltspangt

ltbodygt

lthtmlgt

商品情報を表示するコントローラクラス

JSP

コントローラの肥大化を防ぐ

28

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報のdivタグ

Div itemBox = htmlgetBody()getById(itemBox Divclass)

商品名を書き込む

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

価格説明その他もろもろも

このへんが肥大化してしまう

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 8: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

自己紹介

bull わたなべ

bull SI屋の技術屋さん

bull nabedge

bull nabedgegmailcom

bull httpnabedgeblogspotjp

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

bull JavaでWebアプリをつくりためのMVCフレームワーク

bull 生のサーブレットJSPで作るより100倍作りやすい

bull 大昔のStrutsより10倍は学習しやすい

bull ライバルとしてはSeasarのSAStrutsとか

bull Spring3Xになって以降はSAStrutsよりもさらに使いやすくなった

bull 詳しくは「Spring3入門」を読みましょう

11

12

2 テンプレートエンジン

テンプレートエンジン

13

JSP一番身近なテンプレートエンジン

こんにちは

lt if (name == null) gt

ゲストさん

lt else gt

lt= name gtさん

lt gt

通常のJava言語EL式カスタムタグで書く

テンプレートエンジン

14

VelocityJavaでは老舗のテンプレートエンジン

こんにちは

if (name == null)

ゲストさん

else

$nameさん

end

VTL = Velocity Template Languageで書く

テンプレートエンジン

15

FreeMarker最近人気のテンプレートエンジン

こんにちは

ltif namehas_contentgt

$nameさん

ltelsegt

ゲストさん

ltifgt

FTL = Freemarker Template Languageで書く

テンプレートエンジン

16

Mixer2Webデザイナーと仲良く仕事するためのテンプレートエンジン

こんにちは

ltspan id=ldquonamerdquogtななしltspangtさん

String name = ldquoヤマダrdquo

Span span = htmlgetById(ldquonamerdquo Spanclass)

spangetContentclear()

spangetContentadd(name)

これで ltspan id=ldquonamerdquogtヤマダltspangtさん

になる

テンプレートファイル(html)は純粋なXHTMLとCSS

値の埋め込みやロジックは普通のJavaで書く(java)

17

3 mixer2を

HelloWorld(SpringMVC編) で解説

httpmixer2orgsitespringmvcsamplehtml

補足タグとJava型

18

lthtmlgthelliplthtmlgt hArr orgmixer2jaxbxhtmlHtml

ltdivgthellipltdivgt hArr orgmixer2jaxbxhtmlDiv

(ほか全120種類くらいのタグすべてを実装済み)

HTMLタグとJavaオブジェクトを相互マッピング

タグの属性はJavaオブジェクトのプロパティにマッピングsettergetterメソッドでアクセス

ltdiv id=ldquofoordquogthellipltdivgt

をテンプレートとしてロードすると

String id = divgetId() これでidにrdquofoordquoが入る

(html45のすべての属性を実装済み)

補足複数要素はListになる

19

lthtmlgt

ltbodygt

ltpgtHello Worldltpgt

foo

ltspangtbarltspangt

ltbodygt

lthtmlgt

index 型

0 P

1 String

2 Span

Html html = mixer2Engine

loadHtmlTemplate(

ldquotemplatehtmlrdquo)

javautilListltObjectgt list

= htmlgetBody()

getContent()

listの中身 templatehtml

ちょっと一息

20

bull水分補給

bull時間を確認 10分か15分くらい

21

4 Why mixer2

最大のメリット

22

htmlモックアップを

JSPに書き変えずに

そのまま使える

23

デモ (フルーツショップサンプルアプリ編)

httpsgithubcomnabedgemixer2-

sampletreemastermixer2-fruitshop-springmvc

「github mixer2-fruitshop-springmvc」 でググるとすぐ見つかります

24

5 Mixer2とSpringMVCを

組み合わせる場合の勘所

勘所

1 コントローラクラスの肥大化を防ぐ

2 aタグやimgタグの相対パスの書き換え

3 ltmvcresources gtで静的リソースを出力

4 上の23を生かすためのおススメディレクトリ構造

25

26

コントローラクラスの肥大化を防ぐ

ふつうのコントローラとJSP

27

Controller

public class ItemController

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

modelAndViewにitemを詰めて返す

retern new ModelAndView(ldquoitemjsprdquo ldquoitemrdquo item)

ltpage pageEncoding=UTF-8gt

lthtmlgt

ltbodygt

ltspangt商品名$itemnameltspangt

ltbodygt

lthtmlgt

商品情報を表示するコントローラクラス

JSP

コントローラの肥大化を防ぐ

28

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報のdivタグ

Div itemBox = htmlgetBody()getById(itemBox Divclass)

商品名を書き込む

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

価格説明その他もろもろも

このへんが肥大化してしまう

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 9: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

目次

1 SpringMVC

2 テンプレートエンジン

3 Mixer2をHelloWorldで解説

4 Why mixer2

5 SpringMVCとmixer2の組み合わせの勘所

6 コントローラとビューに対するテスト

7 Webアプリの分割開発

8 まとめ

9 FAQ

9

10

1 Spring MVC

SpringMVC

bull JavaでWebアプリをつくりためのMVCフレームワーク

bull 生のサーブレットJSPで作るより100倍作りやすい

bull 大昔のStrutsより10倍は学習しやすい

bull ライバルとしてはSeasarのSAStrutsとか

bull Spring3Xになって以降はSAStrutsよりもさらに使いやすくなった

bull 詳しくは「Spring3入門」を読みましょう

11

12

2 テンプレートエンジン

テンプレートエンジン

13

JSP一番身近なテンプレートエンジン

こんにちは

lt if (name == null) gt

ゲストさん

lt else gt

lt= name gtさん

lt gt

通常のJava言語EL式カスタムタグで書く

テンプレートエンジン

14

VelocityJavaでは老舗のテンプレートエンジン

こんにちは

if (name == null)

ゲストさん

else

$nameさん

end

VTL = Velocity Template Languageで書く

テンプレートエンジン

15

FreeMarker最近人気のテンプレートエンジン

こんにちは

ltif namehas_contentgt

$nameさん

ltelsegt

ゲストさん

ltifgt

FTL = Freemarker Template Languageで書く

テンプレートエンジン

16

Mixer2Webデザイナーと仲良く仕事するためのテンプレートエンジン

こんにちは

ltspan id=ldquonamerdquogtななしltspangtさん

String name = ldquoヤマダrdquo

Span span = htmlgetById(ldquonamerdquo Spanclass)

spangetContentclear()

spangetContentadd(name)

これで ltspan id=ldquonamerdquogtヤマダltspangtさん

になる

テンプレートファイル(html)は純粋なXHTMLとCSS

値の埋め込みやロジックは普通のJavaで書く(java)

17

3 mixer2を

HelloWorld(SpringMVC編) で解説

httpmixer2orgsitespringmvcsamplehtml

補足タグとJava型

18

lthtmlgthelliplthtmlgt hArr orgmixer2jaxbxhtmlHtml

ltdivgthellipltdivgt hArr orgmixer2jaxbxhtmlDiv

(ほか全120種類くらいのタグすべてを実装済み)

HTMLタグとJavaオブジェクトを相互マッピング

タグの属性はJavaオブジェクトのプロパティにマッピングsettergetterメソッドでアクセス

ltdiv id=ldquofoordquogthellipltdivgt

をテンプレートとしてロードすると

String id = divgetId() これでidにrdquofoordquoが入る

(html45のすべての属性を実装済み)

補足複数要素はListになる

19

lthtmlgt

ltbodygt

ltpgtHello Worldltpgt

foo

ltspangtbarltspangt

ltbodygt

lthtmlgt

index 型

0 P

1 String

2 Span

Html html = mixer2Engine

loadHtmlTemplate(

ldquotemplatehtmlrdquo)

javautilListltObjectgt list

= htmlgetBody()

getContent()

listの中身 templatehtml

ちょっと一息

20

bull水分補給

bull時間を確認 10分か15分くらい

21

4 Why mixer2

最大のメリット

22

htmlモックアップを

JSPに書き変えずに

そのまま使える

23

デモ (フルーツショップサンプルアプリ編)

httpsgithubcomnabedgemixer2-

sampletreemastermixer2-fruitshop-springmvc

「github mixer2-fruitshop-springmvc」 でググるとすぐ見つかります

24

5 Mixer2とSpringMVCを

組み合わせる場合の勘所

勘所

1 コントローラクラスの肥大化を防ぐ

2 aタグやimgタグの相対パスの書き換え

3 ltmvcresources gtで静的リソースを出力

4 上の23を生かすためのおススメディレクトリ構造

25

26

コントローラクラスの肥大化を防ぐ

ふつうのコントローラとJSP

27

Controller

public class ItemController

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

modelAndViewにitemを詰めて返す

retern new ModelAndView(ldquoitemjsprdquo ldquoitemrdquo item)

ltpage pageEncoding=UTF-8gt

lthtmlgt

ltbodygt

ltspangt商品名$itemnameltspangt

ltbodygt

lthtmlgt

商品情報を表示するコントローラクラス

JSP

コントローラの肥大化を防ぐ

28

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報のdivタグ

Div itemBox = htmlgetBody()getById(itemBox Divclass)

商品名を書き込む

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

価格説明その他もろもろも

このへんが肥大化してしまう

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 10: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

10

1 Spring MVC

SpringMVC

bull JavaでWebアプリをつくりためのMVCフレームワーク

bull 生のサーブレットJSPで作るより100倍作りやすい

bull 大昔のStrutsより10倍は学習しやすい

bull ライバルとしてはSeasarのSAStrutsとか

bull Spring3Xになって以降はSAStrutsよりもさらに使いやすくなった

bull 詳しくは「Spring3入門」を読みましょう

11

12

2 テンプレートエンジン

テンプレートエンジン

13

JSP一番身近なテンプレートエンジン

こんにちは

lt if (name == null) gt

ゲストさん

lt else gt

lt= name gtさん

lt gt

通常のJava言語EL式カスタムタグで書く

テンプレートエンジン

14

VelocityJavaでは老舗のテンプレートエンジン

こんにちは

if (name == null)

ゲストさん

else

$nameさん

end

VTL = Velocity Template Languageで書く

テンプレートエンジン

15

FreeMarker最近人気のテンプレートエンジン

こんにちは

ltif namehas_contentgt

$nameさん

ltelsegt

ゲストさん

ltifgt

FTL = Freemarker Template Languageで書く

テンプレートエンジン

16

Mixer2Webデザイナーと仲良く仕事するためのテンプレートエンジン

こんにちは

ltspan id=ldquonamerdquogtななしltspangtさん

String name = ldquoヤマダrdquo

Span span = htmlgetById(ldquonamerdquo Spanclass)

spangetContentclear()

spangetContentadd(name)

これで ltspan id=ldquonamerdquogtヤマダltspangtさん

になる

テンプレートファイル(html)は純粋なXHTMLとCSS

値の埋め込みやロジックは普通のJavaで書く(java)

17

3 mixer2を

HelloWorld(SpringMVC編) で解説

httpmixer2orgsitespringmvcsamplehtml

補足タグとJava型

18

lthtmlgthelliplthtmlgt hArr orgmixer2jaxbxhtmlHtml

ltdivgthellipltdivgt hArr orgmixer2jaxbxhtmlDiv

(ほか全120種類くらいのタグすべてを実装済み)

HTMLタグとJavaオブジェクトを相互マッピング

タグの属性はJavaオブジェクトのプロパティにマッピングsettergetterメソッドでアクセス

ltdiv id=ldquofoordquogthellipltdivgt

をテンプレートとしてロードすると

String id = divgetId() これでidにrdquofoordquoが入る

(html45のすべての属性を実装済み)

補足複数要素はListになる

19

lthtmlgt

ltbodygt

ltpgtHello Worldltpgt

foo

ltspangtbarltspangt

ltbodygt

lthtmlgt

index 型

0 P

1 String

2 Span

Html html = mixer2Engine

loadHtmlTemplate(

ldquotemplatehtmlrdquo)

javautilListltObjectgt list

= htmlgetBody()

getContent()

listの中身 templatehtml

ちょっと一息

20

bull水分補給

bull時間を確認 10分か15分くらい

21

4 Why mixer2

最大のメリット

22

htmlモックアップを

JSPに書き変えずに

そのまま使える

23

デモ (フルーツショップサンプルアプリ編)

httpsgithubcomnabedgemixer2-

sampletreemastermixer2-fruitshop-springmvc

「github mixer2-fruitshop-springmvc」 でググるとすぐ見つかります

24

5 Mixer2とSpringMVCを

組み合わせる場合の勘所

勘所

1 コントローラクラスの肥大化を防ぐ

2 aタグやimgタグの相対パスの書き換え

3 ltmvcresources gtで静的リソースを出力

4 上の23を生かすためのおススメディレクトリ構造

25

26

コントローラクラスの肥大化を防ぐ

ふつうのコントローラとJSP

27

Controller

public class ItemController

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

modelAndViewにitemを詰めて返す

retern new ModelAndView(ldquoitemjsprdquo ldquoitemrdquo item)

ltpage pageEncoding=UTF-8gt

lthtmlgt

ltbodygt

ltspangt商品名$itemnameltspangt

ltbodygt

lthtmlgt

商品情報を表示するコントローラクラス

JSP

コントローラの肥大化を防ぐ

28

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報のdivタグ

Div itemBox = htmlgetBody()getById(itemBox Divclass)

商品名を書き込む

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

価格説明その他もろもろも

このへんが肥大化してしまう

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 11: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

SpringMVC

bull JavaでWebアプリをつくりためのMVCフレームワーク

bull 生のサーブレットJSPで作るより100倍作りやすい

bull 大昔のStrutsより10倍は学習しやすい

bull ライバルとしてはSeasarのSAStrutsとか

bull Spring3Xになって以降はSAStrutsよりもさらに使いやすくなった

bull 詳しくは「Spring3入門」を読みましょう

11

12

2 テンプレートエンジン

テンプレートエンジン

13

JSP一番身近なテンプレートエンジン

こんにちは

lt if (name == null) gt

ゲストさん

lt else gt

lt= name gtさん

lt gt

通常のJava言語EL式カスタムタグで書く

テンプレートエンジン

14

VelocityJavaでは老舗のテンプレートエンジン

こんにちは

if (name == null)

ゲストさん

else

$nameさん

end

VTL = Velocity Template Languageで書く

テンプレートエンジン

15

FreeMarker最近人気のテンプレートエンジン

こんにちは

ltif namehas_contentgt

$nameさん

ltelsegt

ゲストさん

ltifgt

FTL = Freemarker Template Languageで書く

テンプレートエンジン

16

Mixer2Webデザイナーと仲良く仕事するためのテンプレートエンジン

こんにちは

ltspan id=ldquonamerdquogtななしltspangtさん

String name = ldquoヤマダrdquo

Span span = htmlgetById(ldquonamerdquo Spanclass)

spangetContentclear()

spangetContentadd(name)

これで ltspan id=ldquonamerdquogtヤマダltspangtさん

になる

テンプレートファイル(html)は純粋なXHTMLとCSS

値の埋め込みやロジックは普通のJavaで書く(java)

17

3 mixer2を

HelloWorld(SpringMVC編) で解説

httpmixer2orgsitespringmvcsamplehtml

補足タグとJava型

18

lthtmlgthelliplthtmlgt hArr orgmixer2jaxbxhtmlHtml

ltdivgthellipltdivgt hArr orgmixer2jaxbxhtmlDiv

(ほか全120種類くらいのタグすべてを実装済み)

HTMLタグとJavaオブジェクトを相互マッピング

タグの属性はJavaオブジェクトのプロパティにマッピングsettergetterメソッドでアクセス

ltdiv id=ldquofoordquogthellipltdivgt

をテンプレートとしてロードすると

String id = divgetId() これでidにrdquofoordquoが入る

(html45のすべての属性を実装済み)

補足複数要素はListになる

19

lthtmlgt

ltbodygt

ltpgtHello Worldltpgt

foo

ltspangtbarltspangt

ltbodygt

lthtmlgt

index 型

0 P

1 String

2 Span

Html html = mixer2Engine

loadHtmlTemplate(

ldquotemplatehtmlrdquo)

javautilListltObjectgt list

= htmlgetBody()

getContent()

listの中身 templatehtml

ちょっと一息

20

bull水分補給

bull時間を確認 10分か15分くらい

21

4 Why mixer2

最大のメリット

22

htmlモックアップを

JSPに書き変えずに

そのまま使える

23

デモ (フルーツショップサンプルアプリ編)

httpsgithubcomnabedgemixer2-

sampletreemastermixer2-fruitshop-springmvc

「github mixer2-fruitshop-springmvc」 でググるとすぐ見つかります

24

5 Mixer2とSpringMVCを

組み合わせる場合の勘所

勘所

1 コントローラクラスの肥大化を防ぐ

2 aタグやimgタグの相対パスの書き換え

3 ltmvcresources gtで静的リソースを出力

4 上の23を生かすためのおススメディレクトリ構造

25

26

コントローラクラスの肥大化を防ぐ

ふつうのコントローラとJSP

27

Controller

public class ItemController

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

modelAndViewにitemを詰めて返す

retern new ModelAndView(ldquoitemjsprdquo ldquoitemrdquo item)

ltpage pageEncoding=UTF-8gt

lthtmlgt

ltbodygt

ltspangt商品名$itemnameltspangt

ltbodygt

lthtmlgt

商品情報を表示するコントローラクラス

JSP

コントローラの肥大化を防ぐ

28

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報のdivタグ

Div itemBox = htmlgetBody()getById(itemBox Divclass)

商品名を書き込む

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

価格説明その他もろもろも

このへんが肥大化してしまう

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 12: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

12

2 テンプレートエンジン

テンプレートエンジン

13

JSP一番身近なテンプレートエンジン

こんにちは

lt if (name == null) gt

ゲストさん

lt else gt

lt= name gtさん

lt gt

通常のJava言語EL式カスタムタグで書く

テンプレートエンジン

14

VelocityJavaでは老舗のテンプレートエンジン

こんにちは

if (name == null)

ゲストさん

else

$nameさん

end

VTL = Velocity Template Languageで書く

テンプレートエンジン

15

FreeMarker最近人気のテンプレートエンジン

こんにちは

ltif namehas_contentgt

$nameさん

ltelsegt

ゲストさん

ltifgt

FTL = Freemarker Template Languageで書く

テンプレートエンジン

16

Mixer2Webデザイナーと仲良く仕事するためのテンプレートエンジン

こんにちは

ltspan id=ldquonamerdquogtななしltspangtさん

String name = ldquoヤマダrdquo

Span span = htmlgetById(ldquonamerdquo Spanclass)

spangetContentclear()

spangetContentadd(name)

これで ltspan id=ldquonamerdquogtヤマダltspangtさん

になる

テンプレートファイル(html)は純粋なXHTMLとCSS

値の埋め込みやロジックは普通のJavaで書く(java)

17

3 mixer2を

HelloWorld(SpringMVC編) で解説

httpmixer2orgsitespringmvcsamplehtml

補足タグとJava型

18

lthtmlgthelliplthtmlgt hArr orgmixer2jaxbxhtmlHtml

ltdivgthellipltdivgt hArr orgmixer2jaxbxhtmlDiv

(ほか全120種類くらいのタグすべてを実装済み)

HTMLタグとJavaオブジェクトを相互マッピング

タグの属性はJavaオブジェクトのプロパティにマッピングsettergetterメソッドでアクセス

ltdiv id=ldquofoordquogthellipltdivgt

をテンプレートとしてロードすると

String id = divgetId() これでidにrdquofoordquoが入る

(html45のすべての属性を実装済み)

補足複数要素はListになる

19

lthtmlgt

ltbodygt

ltpgtHello Worldltpgt

foo

ltspangtbarltspangt

ltbodygt

lthtmlgt

index 型

0 P

1 String

2 Span

Html html = mixer2Engine

loadHtmlTemplate(

ldquotemplatehtmlrdquo)

javautilListltObjectgt list

= htmlgetBody()

getContent()

listの中身 templatehtml

ちょっと一息

20

bull水分補給

bull時間を確認 10分か15分くらい

21

4 Why mixer2

最大のメリット

22

htmlモックアップを

JSPに書き変えずに

そのまま使える

23

デモ (フルーツショップサンプルアプリ編)

httpsgithubcomnabedgemixer2-

sampletreemastermixer2-fruitshop-springmvc

「github mixer2-fruitshop-springmvc」 でググるとすぐ見つかります

24

5 Mixer2とSpringMVCを

組み合わせる場合の勘所

勘所

1 コントローラクラスの肥大化を防ぐ

2 aタグやimgタグの相対パスの書き換え

3 ltmvcresources gtで静的リソースを出力

4 上の23を生かすためのおススメディレクトリ構造

25

26

コントローラクラスの肥大化を防ぐ

ふつうのコントローラとJSP

27

Controller

public class ItemController

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

modelAndViewにitemを詰めて返す

retern new ModelAndView(ldquoitemjsprdquo ldquoitemrdquo item)

ltpage pageEncoding=UTF-8gt

lthtmlgt

ltbodygt

ltspangt商品名$itemnameltspangt

ltbodygt

lthtmlgt

商品情報を表示するコントローラクラス

JSP

コントローラの肥大化を防ぐ

28

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報のdivタグ

Div itemBox = htmlgetBody()getById(itemBox Divclass)

商品名を書き込む

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

価格説明その他もろもろも

このへんが肥大化してしまう

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 13: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

テンプレートエンジン

13

JSP一番身近なテンプレートエンジン

こんにちは

lt if (name == null) gt

ゲストさん

lt else gt

lt= name gtさん

lt gt

通常のJava言語EL式カスタムタグで書く

テンプレートエンジン

14

VelocityJavaでは老舗のテンプレートエンジン

こんにちは

if (name == null)

ゲストさん

else

$nameさん

end

VTL = Velocity Template Languageで書く

テンプレートエンジン

15

FreeMarker最近人気のテンプレートエンジン

こんにちは

ltif namehas_contentgt

$nameさん

ltelsegt

ゲストさん

ltifgt

FTL = Freemarker Template Languageで書く

テンプレートエンジン

16

Mixer2Webデザイナーと仲良く仕事するためのテンプレートエンジン

こんにちは

ltspan id=ldquonamerdquogtななしltspangtさん

String name = ldquoヤマダrdquo

Span span = htmlgetById(ldquonamerdquo Spanclass)

spangetContentclear()

spangetContentadd(name)

これで ltspan id=ldquonamerdquogtヤマダltspangtさん

になる

テンプレートファイル(html)は純粋なXHTMLとCSS

値の埋め込みやロジックは普通のJavaで書く(java)

17

3 mixer2を

HelloWorld(SpringMVC編) で解説

httpmixer2orgsitespringmvcsamplehtml

補足タグとJava型

18

lthtmlgthelliplthtmlgt hArr orgmixer2jaxbxhtmlHtml

ltdivgthellipltdivgt hArr orgmixer2jaxbxhtmlDiv

(ほか全120種類くらいのタグすべてを実装済み)

HTMLタグとJavaオブジェクトを相互マッピング

タグの属性はJavaオブジェクトのプロパティにマッピングsettergetterメソッドでアクセス

ltdiv id=ldquofoordquogthellipltdivgt

をテンプレートとしてロードすると

String id = divgetId() これでidにrdquofoordquoが入る

(html45のすべての属性を実装済み)

補足複数要素はListになる

19

lthtmlgt

ltbodygt

ltpgtHello Worldltpgt

foo

ltspangtbarltspangt

ltbodygt

lthtmlgt

index 型

0 P

1 String

2 Span

Html html = mixer2Engine

loadHtmlTemplate(

ldquotemplatehtmlrdquo)

javautilListltObjectgt list

= htmlgetBody()

getContent()

listの中身 templatehtml

ちょっと一息

20

bull水分補給

bull時間を確認 10分か15分くらい

21

4 Why mixer2

最大のメリット

22

htmlモックアップを

JSPに書き変えずに

そのまま使える

23

デモ (フルーツショップサンプルアプリ編)

httpsgithubcomnabedgemixer2-

sampletreemastermixer2-fruitshop-springmvc

「github mixer2-fruitshop-springmvc」 でググるとすぐ見つかります

24

5 Mixer2とSpringMVCを

組み合わせる場合の勘所

勘所

1 コントローラクラスの肥大化を防ぐ

2 aタグやimgタグの相対パスの書き換え

3 ltmvcresources gtで静的リソースを出力

4 上の23を生かすためのおススメディレクトリ構造

25

26

コントローラクラスの肥大化を防ぐ

ふつうのコントローラとJSP

27

Controller

public class ItemController

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

modelAndViewにitemを詰めて返す

retern new ModelAndView(ldquoitemjsprdquo ldquoitemrdquo item)

ltpage pageEncoding=UTF-8gt

lthtmlgt

ltbodygt

ltspangt商品名$itemnameltspangt

ltbodygt

lthtmlgt

商品情報を表示するコントローラクラス

JSP

コントローラの肥大化を防ぐ

28

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報のdivタグ

Div itemBox = htmlgetBody()getById(itemBox Divclass)

商品名を書き込む

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

価格説明その他もろもろも

このへんが肥大化してしまう

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 14: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

テンプレートエンジン

14

VelocityJavaでは老舗のテンプレートエンジン

こんにちは

if (name == null)

ゲストさん

else

$nameさん

end

VTL = Velocity Template Languageで書く

テンプレートエンジン

15

FreeMarker最近人気のテンプレートエンジン

こんにちは

ltif namehas_contentgt

$nameさん

ltelsegt

ゲストさん

ltifgt

FTL = Freemarker Template Languageで書く

テンプレートエンジン

16

Mixer2Webデザイナーと仲良く仕事するためのテンプレートエンジン

こんにちは

ltspan id=ldquonamerdquogtななしltspangtさん

String name = ldquoヤマダrdquo

Span span = htmlgetById(ldquonamerdquo Spanclass)

spangetContentclear()

spangetContentadd(name)

これで ltspan id=ldquonamerdquogtヤマダltspangtさん

になる

テンプレートファイル(html)は純粋なXHTMLとCSS

値の埋め込みやロジックは普通のJavaで書く(java)

17

3 mixer2を

HelloWorld(SpringMVC編) で解説

httpmixer2orgsitespringmvcsamplehtml

補足タグとJava型

18

lthtmlgthelliplthtmlgt hArr orgmixer2jaxbxhtmlHtml

ltdivgthellipltdivgt hArr orgmixer2jaxbxhtmlDiv

(ほか全120種類くらいのタグすべてを実装済み)

HTMLタグとJavaオブジェクトを相互マッピング

タグの属性はJavaオブジェクトのプロパティにマッピングsettergetterメソッドでアクセス

ltdiv id=ldquofoordquogthellipltdivgt

をテンプレートとしてロードすると

String id = divgetId() これでidにrdquofoordquoが入る

(html45のすべての属性を実装済み)

補足複数要素はListになる

19

lthtmlgt

ltbodygt

ltpgtHello Worldltpgt

foo

ltspangtbarltspangt

ltbodygt

lthtmlgt

index 型

0 P

1 String

2 Span

Html html = mixer2Engine

loadHtmlTemplate(

ldquotemplatehtmlrdquo)

javautilListltObjectgt list

= htmlgetBody()

getContent()

listの中身 templatehtml

ちょっと一息

20

bull水分補給

bull時間を確認 10分か15分くらい

21

4 Why mixer2

最大のメリット

22

htmlモックアップを

JSPに書き変えずに

そのまま使える

23

デモ (フルーツショップサンプルアプリ編)

httpsgithubcomnabedgemixer2-

sampletreemastermixer2-fruitshop-springmvc

「github mixer2-fruitshop-springmvc」 でググるとすぐ見つかります

24

5 Mixer2とSpringMVCを

組み合わせる場合の勘所

勘所

1 コントローラクラスの肥大化を防ぐ

2 aタグやimgタグの相対パスの書き換え

3 ltmvcresources gtで静的リソースを出力

4 上の23を生かすためのおススメディレクトリ構造

25

26

コントローラクラスの肥大化を防ぐ

ふつうのコントローラとJSP

27

Controller

public class ItemController

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

modelAndViewにitemを詰めて返す

retern new ModelAndView(ldquoitemjsprdquo ldquoitemrdquo item)

ltpage pageEncoding=UTF-8gt

lthtmlgt

ltbodygt

ltspangt商品名$itemnameltspangt

ltbodygt

lthtmlgt

商品情報を表示するコントローラクラス

JSP

コントローラの肥大化を防ぐ

28

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報のdivタグ

Div itemBox = htmlgetBody()getById(itemBox Divclass)

商品名を書き込む

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

価格説明その他もろもろも

このへんが肥大化してしまう

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 15: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

テンプレートエンジン

15

FreeMarker最近人気のテンプレートエンジン

こんにちは

ltif namehas_contentgt

$nameさん

ltelsegt

ゲストさん

ltifgt

FTL = Freemarker Template Languageで書く

テンプレートエンジン

16

Mixer2Webデザイナーと仲良く仕事するためのテンプレートエンジン

こんにちは

ltspan id=ldquonamerdquogtななしltspangtさん

String name = ldquoヤマダrdquo

Span span = htmlgetById(ldquonamerdquo Spanclass)

spangetContentclear()

spangetContentadd(name)

これで ltspan id=ldquonamerdquogtヤマダltspangtさん

になる

テンプレートファイル(html)は純粋なXHTMLとCSS

値の埋め込みやロジックは普通のJavaで書く(java)

17

3 mixer2を

HelloWorld(SpringMVC編) で解説

httpmixer2orgsitespringmvcsamplehtml

補足タグとJava型

18

lthtmlgthelliplthtmlgt hArr orgmixer2jaxbxhtmlHtml

ltdivgthellipltdivgt hArr orgmixer2jaxbxhtmlDiv

(ほか全120種類くらいのタグすべてを実装済み)

HTMLタグとJavaオブジェクトを相互マッピング

タグの属性はJavaオブジェクトのプロパティにマッピングsettergetterメソッドでアクセス

ltdiv id=ldquofoordquogthellipltdivgt

をテンプレートとしてロードすると

String id = divgetId() これでidにrdquofoordquoが入る

(html45のすべての属性を実装済み)

補足複数要素はListになる

19

lthtmlgt

ltbodygt

ltpgtHello Worldltpgt

foo

ltspangtbarltspangt

ltbodygt

lthtmlgt

index 型

0 P

1 String

2 Span

Html html = mixer2Engine

loadHtmlTemplate(

ldquotemplatehtmlrdquo)

javautilListltObjectgt list

= htmlgetBody()

getContent()

listの中身 templatehtml

ちょっと一息

20

bull水分補給

bull時間を確認 10分か15分くらい

21

4 Why mixer2

最大のメリット

22

htmlモックアップを

JSPに書き変えずに

そのまま使える

23

デモ (フルーツショップサンプルアプリ編)

httpsgithubcomnabedgemixer2-

sampletreemastermixer2-fruitshop-springmvc

「github mixer2-fruitshop-springmvc」 でググるとすぐ見つかります

24

5 Mixer2とSpringMVCを

組み合わせる場合の勘所

勘所

1 コントローラクラスの肥大化を防ぐ

2 aタグやimgタグの相対パスの書き換え

3 ltmvcresources gtで静的リソースを出力

4 上の23を生かすためのおススメディレクトリ構造

25

26

コントローラクラスの肥大化を防ぐ

ふつうのコントローラとJSP

27

Controller

public class ItemController

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

modelAndViewにitemを詰めて返す

retern new ModelAndView(ldquoitemjsprdquo ldquoitemrdquo item)

ltpage pageEncoding=UTF-8gt

lthtmlgt

ltbodygt

ltspangt商品名$itemnameltspangt

ltbodygt

lthtmlgt

商品情報を表示するコントローラクラス

JSP

コントローラの肥大化を防ぐ

28

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報のdivタグ

Div itemBox = htmlgetBody()getById(itemBox Divclass)

商品名を書き込む

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

価格説明その他もろもろも

このへんが肥大化してしまう

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 16: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

テンプレートエンジン

16

Mixer2Webデザイナーと仲良く仕事するためのテンプレートエンジン

こんにちは

ltspan id=ldquonamerdquogtななしltspangtさん

String name = ldquoヤマダrdquo

Span span = htmlgetById(ldquonamerdquo Spanclass)

spangetContentclear()

spangetContentadd(name)

これで ltspan id=ldquonamerdquogtヤマダltspangtさん

になる

テンプレートファイル(html)は純粋なXHTMLとCSS

値の埋め込みやロジックは普通のJavaで書く(java)

17

3 mixer2を

HelloWorld(SpringMVC編) で解説

httpmixer2orgsitespringmvcsamplehtml

補足タグとJava型

18

lthtmlgthelliplthtmlgt hArr orgmixer2jaxbxhtmlHtml

ltdivgthellipltdivgt hArr orgmixer2jaxbxhtmlDiv

(ほか全120種類くらいのタグすべてを実装済み)

HTMLタグとJavaオブジェクトを相互マッピング

タグの属性はJavaオブジェクトのプロパティにマッピングsettergetterメソッドでアクセス

ltdiv id=ldquofoordquogthellipltdivgt

をテンプレートとしてロードすると

String id = divgetId() これでidにrdquofoordquoが入る

(html45のすべての属性を実装済み)

補足複数要素はListになる

19

lthtmlgt

ltbodygt

ltpgtHello Worldltpgt

foo

ltspangtbarltspangt

ltbodygt

lthtmlgt

index 型

0 P

1 String

2 Span

Html html = mixer2Engine

loadHtmlTemplate(

ldquotemplatehtmlrdquo)

javautilListltObjectgt list

= htmlgetBody()

getContent()

listの中身 templatehtml

ちょっと一息

20

bull水分補給

bull時間を確認 10分か15分くらい

21

4 Why mixer2

最大のメリット

22

htmlモックアップを

JSPに書き変えずに

そのまま使える

23

デモ (フルーツショップサンプルアプリ編)

httpsgithubcomnabedgemixer2-

sampletreemastermixer2-fruitshop-springmvc

「github mixer2-fruitshop-springmvc」 でググるとすぐ見つかります

24

5 Mixer2とSpringMVCを

組み合わせる場合の勘所

勘所

1 コントローラクラスの肥大化を防ぐ

2 aタグやimgタグの相対パスの書き換え

3 ltmvcresources gtで静的リソースを出力

4 上の23を生かすためのおススメディレクトリ構造

25

26

コントローラクラスの肥大化を防ぐ

ふつうのコントローラとJSP

27

Controller

public class ItemController

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

modelAndViewにitemを詰めて返す

retern new ModelAndView(ldquoitemjsprdquo ldquoitemrdquo item)

ltpage pageEncoding=UTF-8gt

lthtmlgt

ltbodygt

ltspangt商品名$itemnameltspangt

ltbodygt

lthtmlgt

商品情報を表示するコントローラクラス

JSP

コントローラの肥大化を防ぐ

28

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報のdivタグ

Div itemBox = htmlgetBody()getById(itemBox Divclass)

商品名を書き込む

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

価格説明その他もろもろも

このへんが肥大化してしまう

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 17: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

17

3 mixer2を

HelloWorld(SpringMVC編) で解説

httpmixer2orgsitespringmvcsamplehtml

補足タグとJava型

18

lthtmlgthelliplthtmlgt hArr orgmixer2jaxbxhtmlHtml

ltdivgthellipltdivgt hArr orgmixer2jaxbxhtmlDiv

(ほか全120種類くらいのタグすべてを実装済み)

HTMLタグとJavaオブジェクトを相互マッピング

タグの属性はJavaオブジェクトのプロパティにマッピングsettergetterメソッドでアクセス

ltdiv id=ldquofoordquogthellipltdivgt

をテンプレートとしてロードすると

String id = divgetId() これでidにrdquofoordquoが入る

(html45のすべての属性を実装済み)

補足複数要素はListになる

19

lthtmlgt

ltbodygt

ltpgtHello Worldltpgt

foo

ltspangtbarltspangt

ltbodygt

lthtmlgt

index 型

0 P

1 String

2 Span

Html html = mixer2Engine

loadHtmlTemplate(

ldquotemplatehtmlrdquo)

javautilListltObjectgt list

= htmlgetBody()

getContent()

listの中身 templatehtml

ちょっと一息

20

bull水分補給

bull時間を確認 10分か15分くらい

21

4 Why mixer2

最大のメリット

22

htmlモックアップを

JSPに書き変えずに

そのまま使える

23

デモ (フルーツショップサンプルアプリ編)

httpsgithubcomnabedgemixer2-

sampletreemastermixer2-fruitshop-springmvc

「github mixer2-fruitshop-springmvc」 でググるとすぐ見つかります

24

5 Mixer2とSpringMVCを

組み合わせる場合の勘所

勘所

1 コントローラクラスの肥大化を防ぐ

2 aタグやimgタグの相対パスの書き換え

3 ltmvcresources gtで静的リソースを出力

4 上の23を生かすためのおススメディレクトリ構造

25

26

コントローラクラスの肥大化を防ぐ

ふつうのコントローラとJSP

27

Controller

public class ItemController

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

modelAndViewにitemを詰めて返す

retern new ModelAndView(ldquoitemjsprdquo ldquoitemrdquo item)

ltpage pageEncoding=UTF-8gt

lthtmlgt

ltbodygt

ltspangt商品名$itemnameltspangt

ltbodygt

lthtmlgt

商品情報を表示するコントローラクラス

JSP

コントローラの肥大化を防ぐ

28

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報のdivタグ

Div itemBox = htmlgetBody()getById(itemBox Divclass)

商品名を書き込む

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

価格説明その他もろもろも

このへんが肥大化してしまう

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 18: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

補足タグとJava型

18

lthtmlgthelliplthtmlgt hArr orgmixer2jaxbxhtmlHtml

ltdivgthellipltdivgt hArr orgmixer2jaxbxhtmlDiv

(ほか全120種類くらいのタグすべてを実装済み)

HTMLタグとJavaオブジェクトを相互マッピング

タグの属性はJavaオブジェクトのプロパティにマッピングsettergetterメソッドでアクセス

ltdiv id=ldquofoordquogthellipltdivgt

をテンプレートとしてロードすると

String id = divgetId() これでidにrdquofoordquoが入る

(html45のすべての属性を実装済み)

補足複数要素はListになる

19

lthtmlgt

ltbodygt

ltpgtHello Worldltpgt

foo

ltspangtbarltspangt

ltbodygt

lthtmlgt

index 型

0 P

1 String

2 Span

Html html = mixer2Engine

loadHtmlTemplate(

ldquotemplatehtmlrdquo)

javautilListltObjectgt list

= htmlgetBody()

getContent()

listの中身 templatehtml

ちょっと一息

20

bull水分補給

bull時間を確認 10分か15分くらい

21

4 Why mixer2

最大のメリット

22

htmlモックアップを

JSPに書き変えずに

そのまま使える

23

デモ (フルーツショップサンプルアプリ編)

httpsgithubcomnabedgemixer2-

sampletreemastermixer2-fruitshop-springmvc

「github mixer2-fruitshop-springmvc」 でググるとすぐ見つかります

24

5 Mixer2とSpringMVCを

組み合わせる場合の勘所

勘所

1 コントローラクラスの肥大化を防ぐ

2 aタグやimgタグの相対パスの書き換え

3 ltmvcresources gtで静的リソースを出力

4 上の23を生かすためのおススメディレクトリ構造

25

26

コントローラクラスの肥大化を防ぐ

ふつうのコントローラとJSP

27

Controller

public class ItemController

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

modelAndViewにitemを詰めて返す

retern new ModelAndView(ldquoitemjsprdquo ldquoitemrdquo item)

ltpage pageEncoding=UTF-8gt

lthtmlgt

ltbodygt

ltspangt商品名$itemnameltspangt

ltbodygt

lthtmlgt

商品情報を表示するコントローラクラス

JSP

コントローラの肥大化を防ぐ

28

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報のdivタグ

Div itemBox = htmlgetBody()getById(itemBox Divclass)

商品名を書き込む

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

価格説明その他もろもろも

このへんが肥大化してしまう

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 19: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

補足複数要素はListになる

19

lthtmlgt

ltbodygt

ltpgtHello Worldltpgt

foo

ltspangtbarltspangt

ltbodygt

lthtmlgt

index 型

0 P

1 String

2 Span

Html html = mixer2Engine

loadHtmlTemplate(

ldquotemplatehtmlrdquo)

javautilListltObjectgt list

= htmlgetBody()

getContent()

listの中身 templatehtml

ちょっと一息

20

bull水分補給

bull時間を確認 10分か15分くらい

21

4 Why mixer2

最大のメリット

22

htmlモックアップを

JSPに書き変えずに

そのまま使える

23

デモ (フルーツショップサンプルアプリ編)

httpsgithubcomnabedgemixer2-

sampletreemastermixer2-fruitshop-springmvc

「github mixer2-fruitshop-springmvc」 でググるとすぐ見つかります

24

5 Mixer2とSpringMVCを

組み合わせる場合の勘所

勘所

1 コントローラクラスの肥大化を防ぐ

2 aタグやimgタグの相対パスの書き換え

3 ltmvcresources gtで静的リソースを出力

4 上の23を生かすためのおススメディレクトリ構造

25

26

コントローラクラスの肥大化を防ぐ

ふつうのコントローラとJSP

27

Controller

public class ItemController

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

modelAndViewにitemを詰めて返す

retern new ModelAndView(ldquoitemjsprdquo ldquoitemrdquo item)

ltpage pageEncoding=UTF-8gt

lthtmlgt

ltbodygt

ltspangt商品名$itemnameltspangt

ltbodygt

lthtmlgt

商品情報を表示するコントローラクラス

JSP

コントローラの肥大化を防ぐ

28

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報のdivタグ

Div itemBox = htmlgetBody()getById(itemBox Divclass)

商品名を書き込む

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

価格説明その他もろもろも

このへんが肥大化してしまう

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 20: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

ちょっと一息

20

bull水分補給

bull時間を確認 10分か15分くらい

21

4 Why mixer2

最大のメリット

22

htmlモックアップを

JSPに書き変えずに

そのまま使える

23

デモ (フルーツショップサンプルアプリ編)

httpsgithubcomnabedgemixer2-

sampletreemastermixer2-fruitshop-springmvc

「github mixer2-fruitshop-springmvc」 でググるとすぐ見つかります

24

5 Mixer2とSpringMVCを

組み合わせる場合の勘所

勘所

1 コントローラクラスの肥大化を防ぐ

2 aタグやimgタグの相対パスの書き換え

3 ltmvcresources gtで静的リソースを出力

4 上の23を生かすためのおススメディレクトリ構造

25

26

コントローラクラスの肥大化を防ぐ

ふつうのコントローラとJSP

27

Controller

public class ItemController

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

modelAndViewにitemを詰めて返す

retern new ModelAndView(ldquoitemjsprdquo ldquoitemrdquo item)

ltpage pageEncoding=UTF-8gt

lthtmlgt

ltbodygt

ltspangt商品名$itemnameltspangt

ltbodygt

lthtmlgt

商品情報を表示するコントローラクラス

JSP

コントローラの肥大化を防ぐ

28

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報のdivタグ

Div itemBox = htmlgetBody()getById(itemBox Divclass)

商品名を書き込む

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

価格説明その他もろもろも

このへんが肥大化してしまう

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 21: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

21

4 Why mixer2

最大のメリット

22

htmlモックアップを

JSPに書き変えずに

そのまま使える

23

デモ (フルーツショップサンプルアプリ編)

httpsgithubcomnabedgemixer2-

sampletreemastermixer2-fruitshop-springmvc

「github mixer2-fruitshop-springmvc」 でググるとすぐ見つかります

24

5 Mixer2とSpringMVCを

組み合わせる場合の勘所

勘所

1 コントローラクラスの肥大化を防ぐ

2 aタグやimgタグの相対パスの書き換え

3 ltmvcresources gtで静的リソースを出力

4 上の23を生かすためのおススメディレクトリ構造

25

26

コントローラクラスの肥大化を防ぐ

ふつうのコントローラとJSP

27

Controller

public class ItemController

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

modelAndViewにitemを詰めて返す

retern new ModelAndView(ldquoitemjsprdquo ldquoitemrdquo item)

ltpage pageEncoding=UTF-8gt

lthtmlgt

ltbodygt

ltspangt商品名$itemnameltspangt

ltbodygt

lthtmlgt

商品情報を表示するコントローラクラス

JSP

コントローラの肥大化を防ぐ

28

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報のdivタグ

Div itemBox = htmlgetBody()getById(itemBox Divclass)

商品名を書き込む

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

価格説明その他もろもろも

このへんが肥大化してしまう

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 22: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

最大のメリット

22

htmlモックアップを

JSPに書き変えずに

そのまま使える

23

デモ (フルーツショップサンプルアプリ編)

httpsgithubcomnabedgemixer2-

sampletreemastermixer2-fruitshop-springmvc

「github mixer2-fruitshop-springmvc」 でググるとすぐ見つかります

24

5 Mixer2とSpringMVCを

組み合わせる場合の勘所

勘所

1 コントローラクラスの肥大化を防ぐ

2 aタグやimgタグの相対パスの書き換え

3 ltmvcresources gtで静的リソースを出力

4 上の23を生かすためのおススメディレクトリ構造

25

26

コントローラクラスの肥大化を防ぐ

ふつうのコントローラとJSP

27

Controller

public class ItemController

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

modelAndViewにitemを詰めて返す

retern new ModelAndView(ldquoitemjsprdquo ldquoitemrdquo item)

ltpage pageEncoding=UTF-8gt

lthtmlgt

ltbodygt

ltspangt商品名$itemnameltspangt

ltbodygt

lthtmlgt

商品情報を表示するコントローラクラス

JSP

コントローラの肥大化を防ぐ

28

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報のdivタグ

Div itemBox = htmlgetBody()getById(itemBox Divclass)

商品名を書き込む

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

価格説明その他もろもろも

このへんが肥大化してしまう

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 23: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

23

デモ (フルーツショップサンプルアプリ編)

httpsgithubcomnabedgemixer2-

sampletreemastermixer2-fruitshop-springmvc

「github mixer2-fruitshop-springmvc」 でググるとすぐ見つかります

24

5 Mixer2とSpringMVCを

組み合わせる場合の勘所

勘所

1 コントローラクラスの肥大化を防ぐ

2 aタグやimgタグの相対パスの書き換え

3 ltmvcresources gtで静的リソースを出力

4 上の23を生かすためのおススメディレクトリ構造

25

26

コントローラクラスの肥大化を防ぐ

ふつうのコントローラとJSP

27

Controller

public class ItemController

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

modelAndViewにitemを詰めて返す

retern new ModelAndView(ldquoitemjsprdquo ldquoitemrdquo item)

ltpage pageEncoding=UTF-8gt

lthtmlgt

ltbodygt

ltspangt商品名$itemnameltspangt

ltbodygt

lthtmlgt

商品情報を表示するコントローラクラス

JSP

コントローラの肥大化を防ぐ

28

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報のdivタグ

Div itemBox = htmlgetBody()getById(itemBox Divclass)

商品名を書き込む

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

価格説明その他もろもろも

このへんが肥大化してしまう

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 24: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

24

5 Mixer2とSpringMVCを

組み合わせる場合の勘所

勘所

1 コントローラクラスの肥大化を防ぐ

2 aタグやimgタグの相対パスの書き換え

3 ltmvcresources gtで静的リソースを出力

4 上の23を生かすためのおススメディレクトリ構造

25

26

コントローラクラスの肥大化を防ぐ

ふつうのコントローラとJSP

27

Controller

public class ItemController

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

modelAndViewにitemを詰めて返す

retern new ModelAndView(ldquoitemjsprdquo ldquoitemrdquo item)

ltpage pageEncoding=UTF-8gt

lthtmlgt

ltbodygt

ltspangt商品名$itemnameltspangt

ltbodygt

lthtmlgt

商品情報を表示するコントローラクラス

JSP

コントローラの肥大化を防ぐ

28

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報のdivタグ

Div itemBox = htmlgetBody()getById(itemBox Divclass)

商品名を書き込む

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

価格説明その他もろもろも

このへんが肥大化してしまう

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 25: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

勘所

1 コントローラクラスの肥大化を防ぐ

2 aタグやimgタグの相対パスの書き換え

3 ltmvcresources gtで静的リソースを出力

4 上の23を生かすためのおススメディレクトリ構造

25

26

コントローラクラスの肥大化を防ぐ

ふつうのコントローラとJSP

27

Controller

public class ItemController

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

modelAndViewにitemを詰めて返す

retern new ModelAndView(ldquoitemjsprdquo ldquoitemrdquo item)

ltpage pageEncoding=UTF-8gt

lthtmlgt

ltbodygt

ltspangt商品名$itemnameltspangt

ltbodygt

lthtmlgt

商品情報を表示するコントローラクラス

JSP

コントローラの肥大化を防ぐ

28

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報のdivタグ

Div itemBox = htmlgetBody()getById(itemBox Divclass)

商品名を書き込む

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

価格説明その他もろもろも

このへんが肥大化してしまう

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 26: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

26

コントローラクラスの肥大化を防ぐ

ふつうのコントローラとJSP

27

Controller

public class ItemController

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

modelAndViewにitemを詰めて返す

retern new ModelAndView(ldquoitemjsprdquo ldquoitemrdquo item)

ltpage pageEncoding=UTF-8gt

lthtmlgt

ltbodygt

ltspangt商品名$itemnameltspangt

ltbodygt

lthtmlgt

商品情報を表示するコントローラクラス

JSP

コントローラの肥大化を防ぐ

28

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報のdivタグ

Div itemBox = htmlgetBody()getById(itemBox Divclass)

商品名を書き込む

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

価格説明その他もろもろも

このへんが肥大化してしまう

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 27: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

ふつうのコントローラとJSP

27

Controller

public class ItemController

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

modelAndViewにitemを詰めて返す

retern new ModelAndView(ldquoitemjsprdquo ldquoitemrdquo item)

ltpage pageEncoding=UTF-8gt

lthtmlgt

ltbodygt

ltspangt商品名$itemnameltspangt

ltbodygt

lthtmlgt

商品情報を表示するコントローラクラス

JSP

コントローラの肥大化を防ぐ

28

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報のdivタグ

Div itemBox = htmlgetBody()getById(itemBox Divclass)

商品名を書き込む

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

価格説明その他もろもろも

このへんが肥大化してしまう

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 28: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

コントローラの肥大化を防ぐ

28

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報のdivタグ

Div itemBox = htmlgetBody()getById(itemBox Divclass)

商品名を書き込む

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

価格説明その他もろもろも

このへんが肥大化してしまう

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 29: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

コントローラの肥大化を防ぐ

29

RequestMapping(value = itemitemId)

public ModelAndView showItem(PathVariable long itemId)

DBから商品情報を取得

Item item = itemServicegetItem(itemId)

テンプレートのロード

String mainTemplate = classpathm2mockupm2templateitemhtml

File file = ResourceUtilsgetFile(mainTemplate)

Html html = mixer2EngineloadHtmlTemplate(file)

商品情報を埋め込む

ItemHelperreplaceItemBox(html item)

helliphellip ヘルパークラスに切り出せば1行で済む

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 30: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

コントローラの肥大化を防ぐ

30

public class ItemHelper

public static void replaceItemBox(Html html Item item)

商品情報を入れるdivタグを取得

Div itemBox = htmlgetBody()getById(itemBox Divclass)

divの中のH1やSpanの中にDBから取得した値を入れる

itemBoxgetById(itemName H1class)getContent()clear()

itemBoxgetById(itemName H1class)getContent()add(itemgetName())

itemBoxgetById(itemPrice Spanclass)getContent()clear()

itemBoxgetById(itemPrice Spanclass)getContent()add(

itemgetPrice()toString())

itemBoxgetById(itemDescription Divclass)getContent()clear()

itemBoxgetById(itemDescription Divclass)getContent()add(

itemgetDescription())

ヘルパーはごく単純なstaticメソッドでよい

テンプレのhtml DBから取得した商品情報

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 31: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

相対パスの書き換え

31

lta class=ldquotopPageAnchorrdquo

href=m2templateindexhtmlgt

ltimg src=m2staticimgfruitshop-logopng gt

ltagt

左上のロゴはトップページへのリンク

テンプレートファイルではこうなってるけど

lta class=ldquotopPageAnchorrdquo

href=ldquo[contextPath]gt

ltimg src=[contextPath]m2staticimgfruitshop-logopng gt

ltagt

実際の出力ではこうしなきゃならない

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 32: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

相対パスの書き換え

32

String ctx = xxx コンテキストパスを取得しておく

for (A a htmlgetDescendants(topPageAnchor Aclass))

asetHref(ctx + )

ldquotopPageAnchorrdquoというclass属性を持つすべてのaタグのhref属性を書き変える

Mixer2ではすべてのタグ型が下記のメソッドを持っている

bull getDescendants()メソッド該当するすべての子孫タグをList

で取得

bull getById()メソッドid属性でタグを1個だけ取得

bull 他にもreplace系とかremove系のメソッドもあります

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 33: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

相対パスの書き換え

33

ltimg src= gt

for (Img img tagObjgetDescendants(Imgclass))

if (imgisSetSrc())

String src = imggetSrc()

imgsetSrc(convertPath(src))

Imgタグのsrc属性styleタグのhref属性なども同様

convertPathメソッドは

m2static

のような文字列を

[contextPath]m2static

に置換している

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 34: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

34

ltmvcresources gtで

静的リソースを出力

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 35: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

JavaWebアプリでの静的ファイルの配置

35

httplocalhost8080[contextPath]foobarpng

src main java resources webapp foo barpng

maven標準ディレクトリ構造です

普通ならdocroot配下に置く

さもないとブラウザからアクセス不可能

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 36: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

JavaWebアプリでの静的ファイルの配置

36

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

テンプレートhtmlと画像やCSSをまとめてresources配下に置く

クラスパス上に置くほうがJavaコードから扱いやすいから

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 37: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

DispatcherServletのstatic resource機能

bull Spring3X以降DispatcherServletはhttp

リクエストをコントローラクラスに中継する機能だけでなく静的リソースを直接レスポンスする機能がある

37

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 38: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

JavaWebアプリでの静的ファイルの配置

38

ltmvcresources mapping=m2static location=classpathm2mockupm2static cache-period=60 gt

srcmainresourcesmvc-dispatcher-servletxml の抜粋

1 httpcontextPathm2static というURLへのアクセスに対して

2 クラスパスから m2mockupm2static というリソースを探してそれを返す

3 そのとき Cache-Control max-age=60 のようなhttpレスポンスヘッダつきで返す

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 39: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

ただし注意しないと

39

src main java resources m2mockup img logopng itemhtml webapp

1 こういうディレクトリ構造で

ltmvcresources mapping= m2mockup location= classpathm2mockupgt

2 こういう設定をしてしまうと

3 画像やCSSだけでなくテンプレートhtmlにもそのままアクセスできてしまう(もちろんまずい)

httphellip[ContextPath]m2mockupimglogopng

httphellip[ContextPath]m2mockupitemhtml

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 40: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

だからこれがオススメ構造

40

src main java resources applicationContextxml m2mockup m2static img logopng m2template indexhtml itemhtml webapp

m2mockup配下にモックアップhtmlを作る

画像やCSSはm2static配下に置いて ltmvcresources gt の設定での出力対象にする

htmlテンプレートはm2template配下に

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 41: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

これでデザイナとプログラマが仲良く仕事できる

41

プログラマとデザイナの取り決め事項 1 htmlモックアップは

srcmainresourcesm2mockup の下に作ろうぜ

2 ただしhtmlはm2templateそれ以外はm2staticの配下でたのむ

3 商品情報のdivタグはid=ldquoitemBoxrdquoにしよう

4 商品名はspanタグでid=ldquoitemNamerdquo

5 hellipその他の情報も同様に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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 42: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 43: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

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

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 44: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

ざっくりした流れ

1 JunitコードのランナーとしてSpringJUnit4ClassRunner を使えばDIコンテナが勝手にいい感じで起動してくれる

2 HttpServletRequest HttpServletResponseのモックをインスタンス化する

3 モックのrequestにテスト対象のURIやパラメータをセット

4 そのrequestオブジェクトをリクエストハンドラに渡すと疑似リクエストが発生しコントローラクラスに渡される

5 コントローラの該当メソッドが戻り値として返すModelAndViewオブジェクトにhtmlStringが入っている

6 このhtmlStringの中をMixer2Engineで再度Htmlオブジェクト化する

7 Htmlオブジェクトの中をAssertすればよい

44

45

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 45: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

45

実際のテストコードで説明します

httpsgithubcomnabedgemixer2-

sampleblobmastermixer2-fruitshop-

springmvcsrctestjavaorgmixer2samp

lewebcontrollerItemControllerTestjava

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 46: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

最後の給水

46

bull水分補給

bull時間を確認 40分くらい

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 47: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

47

Webアプリの分割開発

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 48: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

普通のWebアプリプロジェクト(maven形式)

48

Javaクラスとかこのへん

Javaクラス以外はsrcmainwebapp

静的ファイルこのへん

JSPとか

このへん

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 49: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

普通のWebアプリを分割開発するときのカベ

1 Javaクラスやその設定ファイル(propertiesxmlsql)は別プロジェクト化してjar化してWebアプリ側から依存関係をつくればいい

ndash つまりJavaライブラリは分割開発可能

2 しかしsrcmainwebapp 配下に置くようなJSP静的リソース設定ファイル類(MVCで言うとViewの周辺)はプロジェクト分割別パッケージ化が難しい

49

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 50: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

Mixer2を使うと

1 Mixer2はViewを普通のjavaコードで取扱う

2 そのテンプレートもJavaコードから見るとただのリソースファイルとして扱える

3 よって普通のJavaライブラリ同様に分割が可能

50

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 51: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

デモ

bullデモでお見せします

プロジェクト間依存関係はこんな感じ

m2flowershop-web(war)

m2flowershop-front(jar)

m2flowershop-cart(jar)

m2flowershop-resource(jar)

51

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 52: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

後日談

bull 結局当日までにサンプルのコーディングが間に合わなかったのでこのデモはやってません(^^

52

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 53: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

53

7 まとめ

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 54: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

まとめ

bull SpringMVCはシンプルで使いやすいフレームワーク

bull mixer2とSpringMVCは良いコンビ

bull ディレクトリ構造を考えたうえでSpringMVCの静的リソース出力機能と組み合わせればhtmlモックアップをjspに書き変える作業は不要

bull jspでは難しいビューに対するテストの自動化も可能

bull htmlテンプレートファイルと静的ファイル(ex画像)とJavaクラスをjarパッケージ化できるのでWebアプリの分割開発すら可能

54

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 55: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

FAQ

bull Q モックアップHTMLはクラスパス上に置かなきゃダメですか

ndash A Mixer2EngineのloadHtmlTemplateメソッドはjavaioFile String

StringBufferのいずれかでテンプレートhtmlを読めますしたがってOSのファイルシステム上でもDB上でもどこでもOKです

ndash 後日談ver1114 以降InputStreamからも読めるようになりました

bull Q WEB-INFviewmixer2viewjsp を通じて結局jspを使っているのはダサくないですか

ndash A 実はその通りです本来はコントローラのメソッドの戻り値としてHtmlオブジェクトを返すだけで済むようなViewResolverを実装するべきです誰か作って(Pull Request熱烈歓迎)

bull Q mixer2を使う場合はJSPは完全に排除しなきゃだめですか既存のtaglibも使いたいのですが

ndash A 可能ですたとえば htmlで用意したテンプレートを読み込んでその一部のタグだけを部分マーシャルしjsp上に埋め込むことも可能です

55

56

ご静聴ありがとうございました

Page 56: SpringMVCとmixer2で作るWebアプリのキホン 2013-01-24 Spring勉強会 #jsug

56

ご静聴ありがとうございました