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

Post on 22-Apr-2015

4.786 Views

Category:

Technology

2 Downloads

Preview:

Click to see full reader

DESCRIPTION

 

TRANSCRIPT

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

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

プロローグ 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

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

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

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

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

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

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

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

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

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

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

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

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

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

自己紹介

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

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

目次

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

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

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

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

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

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

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

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

テンプレートエンジン

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

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

テンプレートエンジン

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

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

テンプレートエンジン

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

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

テンプレートエンジン

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

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

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

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

補足タグと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

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

補足複数要素は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

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

ちょっと一息

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

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

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

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

最大のメリット

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

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

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

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

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

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

勘所

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

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

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

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

ふつうのコントローラと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

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

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

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

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

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

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

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

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

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

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

相対パスの書き換え

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

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

相対パスの書き換え

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

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

相対パスの書き換え

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

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

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

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

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

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

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

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

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

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

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

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

ただし注意しないと

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

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

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

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

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

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

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

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

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

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

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

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

ざっくりした流れ

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

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

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

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

最後の給水

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

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

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

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

普通の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

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

普通の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

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

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

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

デモ

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

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

後日談

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

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

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

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

まとめ

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

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

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

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

56

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

top related