Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Mixer2 で作るカスタムテンプレートエンジン #渋谷java

4,501 views

Published on

第八回 #渋谷java の通常 LT 「Mixer2 で作るカスタムテンプレートエンジン」のスライドです。

Published in: Technology
  • Be the first to comment

Mixer2 で作るカスタムテンプレートエンジン #渋谷java

  1. 1. Mixer2 で作る カスタムテンプレートエンジン 第八回#渋谷java Jun Futagawa (@jfut) Mixer2 で作るカスタムテンプレートエンジン, September 20, 2014 1
  2. 2. 自己紹介  Jun Futagawa  有限会社インテグシステム  Twitter: @jfut  好きなこと: Linux サーバー・ネットワーク構築  今好きなフレームワーク: Cubby, S2JDBC, Mixer2 Mixer2 で作るカスタムテンプレートエンジン, September 20, 2014 2
  3. 3. 今日のお話  Mixer2 で作るカスタムテンプレートエンジン  素材: Mixer2 テンプレートエンジン  http://mixer2.org/  作者: @nabedge さん  テンプレートファイルはHTML ファイル  HTML の構造をマッピングしたJava のクラスインスタンスに変換  HTML タグに対応する個別のJava クラス型を持つ  Java の世界でタグや値の合成操作  テンプレート記述言語を覚えなくて良い new Html(); new Body(); new Div(); new P() Html Head Body Div P Mixer2 で作るカスタムテンプレートエンジン, September 20, 2014 3
  4. 4. Mixer2: 利用例  HTML ファイルをMixer2 でインスタンス化、値を書き換えて出力 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> ... <head /> 省略... <body> <article> <section> <h1>headline</h1> <p id="HERE.msg">here comes hello message</p> <span class="DEBUG">dummy span</span> <p class="DEBUG">dummy p</p> </section> </article> </body> <html> Mixer2Engine m2e = new Mixer2Engine(); Html html = m2e.loadHtmlTemplate(new File("hello.html")); H1 h1 = html.getDescendants(H1.class).get(0); h1.unsetContent(); h1.getContent().add("New Headline"); P p = html.getById("HERE.msg"); p.setId("msg"); p.unsetContent(); p.getContent().add("Hello World!"); // or html.removeDescendants("DEBUG"); List<AbstractJaxb> debugTagList = html.getDescendants("DEBUG"); for (AbstractJaxb abstractJaxb : debugTagList) { html.remove(abstractJaxb); } // タグで取得 // コンテンツ削除 // コンテンツ追加 // id 属性で取得 // id 属性の値を設定 // コンテンツ削除 // コンテンツ追加 // ↓class 属性で取得 // タグごと削除 hello.html 特別な記法のないHTML Java コードの例 ... 省略... <article> 出力: m2e.saveToString(html); <section> <h1>New Headline</h1> <p id="msg">Hello World!</p> </section> </article> ... 省略... DOM 操作ではないため 判りやすい (ちょっと冗長ではある) * AbstractJaxb はMixer2 が持つHTML タグ用クラスのスーパークラス Mixer2 で作るカスタムテンプレートエンジン, September 20, 2014 4
  5. 5. カスタムテンプレートエンジン  なぜ?  Mixer2 はビューのHTML を全部Java で操作できる  でも、汎用部分を毎回Java で操作するのはさすがに手間  レイアウト・共通部品埋め込み  単なるリクエスト・セッションの値の出力  そこで  共通処理の記述はテンプレートファイルへ  <div id="機能名1">dummy div</div>  <p class="機能名2">dummy p</p>  Mixer2 でインスタンス化したhtml から機能名で該当タグを検索  AbstractJaxb tag = html.getById("機能名1");  List<AbstractJaxb> tagList = html.getDescendants("機能名2");  機能名に応じた処理を実行するヘルパークラスでタグや値を操作  ヘルパークラス群= カスタムテンプレートエンジン Mixer2 で作るカスタムテンプレートエンジン, September 20, 2014 5
  6. 6. Class ヘルパークラスの実装イメージ  テンプレートファイル <article> <section> <h1>headline</h1> <p id=" HERE.msg">here comes hello message</p> <span class="M_FUNC">dummy span</span> <p class=" M_FUNC ">dummy p</p> </section> </article>  ヘルパークラス実装 String name = "M_FUNC"; ... public <T extends AbstractJaxb> T replace(String path, String templatePath, T parent, HttpServletRequest request) { List<AbstractJaxb> abstractJaxbList = parent.getDescendants(name); for (AbstractJaxb abstractJaxb : abstractJaxbList) { ... 機能に応じたインタスタンス操作... } return parent; } Mixer2 で作るカスタムテンプレートエンジン, September 20, 2014 6
  7. 7. ヘルパークラスのオプション値  機能によってはオプション値が必要  例: 値や条件式の指定  オプション値はHTML5 のdata-* 属性を利用すると便利  独自タグなし(独自data-* 属性は使う)  Class ヘルパーM_OUT 用のHTML テンプレート記述例:  .html: <span class="M_OUT" data-value="${ sessionScope.name }">dummy.name</span>  値の出力記述方法の比較  JSTL 例:  .jsp: <c:out value="${sessionScope.username }" />  Thymeleaf の例  .html: <span th:text="${ session.username }">dummy.name</span>  Mayaa 例:  .html: <span id="name">dummy.name</span>  .mayaa: <m:writem:id="name" value="${ session.username }" /> Mixer2 で作るカスタムテンプレートエンジン, September 20, 2014 7
  8. 8. テンプレートエンジン実行例  Mixer2 を使用したView の処理時にまとめて実行  例: SpringWeb MVC: View クラス内  コントローラから対応するView 内で実行 1. View に対応するテンプレートファイルからHtml インスタンス化(Mixer2) 2. 事前処理ヘルパークラス群(カスタム) 3. ページ固有のView 処理(Mixer2) 4. 事後処理ヘルパークラス群(カスタム) 処理イメージ Html html = m2e.loadHtmlTemplate(new File(templatePath)); /** 事前処理用共通ヘルパー群を適用します。*/ html = FunctionsHelper.getDefaultPreInstance().replaceAll(path, templatePath, html); ...ページ固有のレンダリング処理をMixer2 のインスタンス操作で適用します。... /** 事後処理用共通ヘルパー群を適用します。*/ html = FunctionsHelper.getDefaultPostInstance().replaceAll(path, templatePath, html); ヘルパークラス群は事前に Map へ登録しておく Mixer2 で作るカスタムテンプレートエンジン, September 20, 2014 8
  9. 9. デモ実装  エンジン実装例: Spring Web MVC 依存  https://github.com/jfut/integ-web-spring-webmvc-mixer2  機能  M_ACTIVE_PATH 表示パスと同じ時にclass 属性へactive を追加  M_APP_NAME pom.xml の<name /> の値を出力  M_DEBUG デバッグモード時にデバッグ欄を作成して表示  M_DELETE レンダリング時に削除  M_EXPORT レイアウト機能  M_IF EL 式によるタグの表示・削除  M_IF_DEBUG バッグモード時のみ表示  M_INCLUDE 別のテンプレートファイルを埋め込む  M_LINK リンクアドレスの相対パスを解決  M_MESSAGE リソースファイルの値を出力  M_OUT リクエスト情報の値を出力、EL 式サポート  M_REQUEST_DEBUG リクエスト情報の値をすべて出力  M_VERSION pom.xml の<version /> の値を出力  利用例: Mixer2 のSpring Boot デモを修正  https://github.com/jfut/mixer2-sample/tree/custom-template Mixer2 で作るカスタムテンプレートエンジン, September 20, 2014 9
  10. 10. デモ実装利用例 <span class="badge M_IF M_OUT" data-test="${ 0 != sessionScope.cart.getReadOnlyItemList().size() }" data-value="${ sessionScope.cart.totalAmount }"> dummy.10</span></a></li> <li class="M_ACTIVE_PATH" data-path="/"> <a class="M_LINK" data-href="../../" href="../../index.html"> ホーム</a></li> コンテンツファイル: /index.html (ここが起点) <div id="M_EXPORT" data-src="/component/layout/layout.html"> レイアウトファイル: /component/layout/layout.html <div id="M_EXPORT"></div> レイアウトファイル: /component/layout/layout.html <div class="M_INCLUDE" data-src="/component/layout/footer.html"> レイアウトファイル: /component/layout/layout.html <div class="M_INCLUDE" data-src="/component/layout/header.html"> z <a class="M_LINK" data-href="../../cart/view" href="../../cart.html">view cart</a> レイアウトファイル: /component/layout/layout.html <div class="M_INCLUDE" data-src="/component/layout/sidebar.html"> <span class="M_APP_NAME">dummy.appName</span> Version <span class="M_VERSION">x.y.z</span> <div class="M_REQUEST_DEBUG">dummy.M_REQUEST_DEBUG</div> Mixer2 で作るカスタムテンプレートエンジン, September 20, 2014 10
  11. 11. まとめ  Mixer2  HTML タグをすべてJava で操作可能  テンプレート記述言語を覚えなくて良い  レンダリング済みHTML のテストもJava で書ける= テスト簡単  参考: @nabedge さんのスライドたくさん: http://www.slideshare.net/nabedge  - さらばJSP - JAXBとテンプレートエンジンMixer2 など  Mixer2 の上にカスタムテンプレートエンジンが簡単に作れる  汎用部分の記述をテンプレートファイル側へ  独自のテンプレート記述言語(機能名、data-*属性)を覚えるデメリットはある  Mixer2 のインスタンス操作だけ、DOM 操作ツライがない Mixer2 で作るカスタムテンプレートエンジン, September 20, 2014 11
  12. 12. Thank You for Your Attention! Mixer2 で作るカスタムテンプレートエンジン, September 20, 2014 12
  13. 13. Mixer2 + テスト  Spring MVC 連携時のテスト @Test public void showItem_exists() throws Exception { // Mock とRequestMappingHandlerAdapter を使用してリクエストを再現し、ModelAndView を取得 ... 省略... request.setMethod("GET"); request.setRequestURI("/item/10001"); Object handler = handlerMapping.getHandler(request).getHandler(); ModelAndView modelAndView = handlerAdapter.handle(request, response, handler); // ViewName をテスト String viewName = modelAndView.getViewName(); assertThat(viewName, is("item")); // ビューをレンダリング // レンダリング時にビュークラスでテンプレートHTML ファイルをMixer2 でインスタンス化し、タグの書き換え、レスポンスに書き出す AbstractMixer2XhtmlView view = (AbstractMixer2XhtmlView)mixer2XhtmlViewResolver.resolveViewName(viewName, Locale.getDefault()); view.render(modelAndView.getModelMap(), request, response); // レンダリングに使用したhtml インスタンスをダイレクトにテスト Html renderedHtml = view.getRenderedHtml(); // or view.getHtml(); H1 itemNameH1 = renderedHtml.getById("itemName"); // テンプレート: <h1 id="itenName">dummy.header</h1> assertThat(itemNameH1.getContent().get(0).toString(), is("Apple")); // レンダリング後: <h1 id="itemName">Apple</h1> Mixer2 で作るカスタムテンプレートエンジン, September 20, 2014 13 } * https://github.com/jfut/mixer2-sample/blob/custom-template/mixer2-fruitshop-springboot

×