springmvcとmixer2で作るwebアプリのキホン 2013-01-24 spring勉強会 #jsug
Post on 22-Apr-2015
4.786 Views
Preview:
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