Spring MVCのMustache JSテンプレートの例
このチュートリアルでは、Spring MVC +
Mustache JSテンプレート
Webアプリケーションの例を示します。
使用される技術:
-
Spring 4.2.4.RELEASE
-
mustache.js
-
JDK 1.8.0__66
-
ジャクソン2.7
-
Eclipse 4.3
-
Tomcat 8
-
Maven 3
-
ブートストラップ3
Springでは、ScriptTemplateConfigurerを使用してJSテンプレートライブラリのほとんど(Mustache、Handlebars、Reactなど)を統合することができます。
この公式のhttp://docs.spring.io/spring/docs/current/spring-framework-reference/html/view.html#view-script[Springスクリプトテンプレート]のドキュメントを参照してください。
P.S Spring 4.2
以降、 `ScriptTemplateConfigurer`がサポートされています
-
Note ** +この例では、組み込みJava 8 Nashorn Javascriptエンジンを使用して、サーバー側で「Mustache JS」を実行します。
isomorphic javascript
の例です。
1.プロジェクトの構成
標準のMavenフォルダ構造。
2. pom.xml
依存性といくつかの有用なプラグインを宣言するためのMaven `pom.xml`ファイル。
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4__0__0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.mkyong</groupId> <artifactId>spring-mvc-mustache</artifactId> <packaging>war</packaging> <version>1.0-SNAPSHOT</version> <name>spring mvc mustache</name> <properties> <jdk.version>1.8</jdk.version> <spring.version>4.2.4.RELEASE</spring.version> <servletapi.version>3.1.0</servletapi.version> <logback.version>1.1.3</logback.version> <jcl.slf4j.version>1.7.12</jcl.slf4j.version> <jackson.version>2.7.0</jackson.version> </properties> <dependencies> <!-- Spring and exclude commons log --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> <exclusions> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions> </dependency> <!-- Add slf4j Logging --> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>${jcl.slf4j.version}</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>${logback.version}</version> </dependency> <!-- compile only, deployed container will provide this --> <!-- no web.xml project need this to start app --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>${servletapi.version}</version> <scope>provided</scope> </dependency> <!-- JSON --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${jackson.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.3</version> <configuration> <source>${jdk.version}</source> <target>${jdk.version}</target> </configuration> </plugin> <plugin> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>9.2.11.v20150529</version> <configuration> <scanIntervalSeconds>10</scanIntervalSeconds> <webApp> <contextPath>/spring</contextPath> </webApp> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-eclipse-plugin</artifactId> <version>2.9</version> <configuration> <downloadSources>true</downloadSources> <downloadJavadocs>true</downloadJavadocs> <wtpversion>2.0</wtpversion> <wtpContextName>spring</wtpContextName> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.6</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> </plugins> </build> </project>
3. Spring + Mustache JSを統合する
MustacheスクリプトテンプレートをSpringビューテンプレートとして統合するには、
ScriptTemplateConfigurer`と
ViewResolver`の両方を設定します。コメントを見てください。
SpringWebConfig.java
package com.mkyong.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.view.script.ScriptTemplateConfigurer; import org.springframework.web.servlet.view.script.ScriptTemplateViewResolver; @EnableWebMvc @Configuration @ComponentScan({ "com.mkyong.web.controller" }) public class SpringWebConfig extends WebMvcConfigurerAdapter { @Bean public ScriptTemplateConfigurer configurer() { ScriptTemplateConfigurer configurer = new ScriptTemplateConfigurer(); //1. Nashorn jdk8 script engine. configurer.setEngineName("nashorn"); //2. Add mustache.min.js and custom render.js to Nashorn configurer.setScripts("/static/js/mustache.min.js", "/static/js/render.js"); //3. Ask Nashorn to run this function "render()" configurer.setRenderFunction("render"); return configurer; } //Define where is Mustache template, in classpath level. //If view "hello" is returned, Mustache temple will be '/static/templates/hello.html' @Bean public ViewResolver viewResolver() { ScriptTemplateViewResolver viewResolver = new ScriptTemplateViewResolver(); viewResolver.setPrefix("/static/templates/"); viewResolver.setSuffix(".html"); return viewResolver; } //add static resources like js or css @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/resources/** ** ").addResourceLocations("/resources/"); } }
4. Spring Controller + Mustacheテンプレート
4.1データをMustacheテンプレートに渡すSpringコントローラ。
HelloController.java
package com.mkyong.web.controller; import java.util.ArrayList; import java.util.List; import javax.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.ModelAndView; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.mkyong.web.model.User; @Controller public class HelloController { private static final Logger logger = LoggerFactory.getLogger(HelloController.class); private static final ObjectMapper om = new ObjectMapper(); @RequestMapping(value = "/", method = RequestMethod.GET) public ModelAndView printWelcome(HttpServletRequest request) { ModelAndView result = new ModelAndView(); result.addObject("resources", request.getContextPath() + "/resources"); result.addObject("logo", "mkyong.com"); result.addObject("title", "Spring MVC + Mustache template"); result.addObject("jumbo-title", "Spring MVC + Mustache template"); result.addObject("jumbo-desc", "Maven + Spring MVC + Mustache JS, ScriptTemplate example."); //1. Test data type result.addObject("id", 100); result.addObject("username", "mkyong"); //2. Test List result.addObject("scriptTemplates", getScriptTemplate()); //3. Test Object result.addObject("user", new User("[email protected]", 0)); //4. Test List<Object> List<User> list = new ArrayList<>(); list.add(new User("[email protected]", 1)); list.add(new User("[email protected]", 2)); list.add(new User("[email protected]", 3)); result.addObject("users__json", convertObjectToJson(list)); result.addObject("users", list); result.setViewName("hello"); return result; } private List<String> getScriptTemplate() { List<String> scriptTemplates = new ArrayList<>(); scriptTemplates.add("Handlebars"); scriptTemplates.add("Mustache"); scriptTemplates.add("React"); scriptTemplates.add("EJS"); scriptTemplates.add("ERB"); scriptTemplates.add("String templates"); return scriptTemplates; } //Jackson2 - Convert Java Object to JSON format public static String convertObjectToJson(Object obj) { String result = ""; try { result = om.writerWithDefaultPrettyPrinter().writeValueAsString(obj); } catch (JsonProcessingException e) { logger.error("Error In JSON conversion : {}", e); } return result; } }
4.2上記のSpringコントローラからのデータを表示するためのMustacheテンプレートファイル。
/static/templates/hello.html
<!DOCTYPE html> <html lang="en"> <head> <title>{{title}}</title> <link href="{{{resources}}}/core/css/bootstrap.min.css" rel="stylesheet"> <link href="{{{resources}}}/core/css/bootstrap-theme.min.css" rel="stylesheet"> <link href="{{{resources}}}/core/css/hello.css" rel="stylesheet"> </head> <body role="document"> <nav class="navbar navbar-inverse navbar-fixed-top"> <div class="container"> <div class="navbar-header"> <a class="navbar-brand" href="#">{{logo}}</a> </div> </div> </nav> <div class="container theme-showcase" role="main"> <div class="jumbotron"> <h1>{{jumbo-title}}</h1> <p>{{jumbo-desc}}</p> </div> <div class="row"> <div class="col-sm-6"> <div class="page-header"> <h1>1. Data Types</h1> </div> <p> <div> {{#id}} Hello {{username}}, id : {{.}} {{/id}} </div> </p> </div> <div class="col-sm-6"> <div class="page-header"> <h1>2. List</h1> </div> <p> <pre>{{scriptTemplates}}</pre> <ol> {{#scriptTemplates}} <li>{{.}}</li> {{/scriptTemplates}} </ol> </p> </div> </div> <div class="row"> <div class="col-sm-6"> <div class="page-header"> <h1>3. User Object</h1> </div> <p> <div> <pre>{{user}}</pre> <ol> {{#user}} <li>email- {{user.email}}</li> <li>loginFailed- {{user.loginFailed}}</li> {{/user}} </ol> </div> </p> </div> <div class="col-sm-6"> <div class="page-header"> <h1>4. List of User Objects (JSON)</h1> </div> <p> <pre>{{user__json}}</pre> {{#users__json}} <ol> <li>email- {{email}}</li> <li>loginFailed- {{loginFailed}}</li> </ol> {{/users__json}} </p> </div> </div> <div class="row"> <div class="col-sm-6"> <div class="page-header"> <h1>5. List of User Objects (RAW)</h1> </div> <p> No idea how to loop it... <pre>{{users}}</pre> {{#users}} <ol> <li>email- {{email}}</li> <li>loginFailed- {{loginFailed}}</li> </ol> {{/users}} </p> </div> <div class="col-sm-6"> <div class="page-header"> <h1></h1> </div> <p> </p> </div> </div> </div> <div class="container"> <hr> <footer> <p>© Mkyong.com 2016</p> </footer> </div> <script type="text/javascript" src="{{{resources}}}/core/js/hello.js"></script> <script type="text/javascript" src="{{{resources}}}/core/js/jquery-1.12.0.min.js"></script> <script type="text/javascript" src="{{{resources}}}/core/js/bootstrap.min.js"></script> </body> </html>
5. Javascript ‘render.js’
ビューが返されると、Springはこの関数 `render(template、model、url)`を実行します。しかし、すべてのJavaオブジェクトやデータ型がJavascriptでサポートされているわけではありません。変換が必要です。特に `List <Object> ‘が必要です。
要約:
-
プリミティブデータ型の場合、変換の必要はありません.
-
java.lang.Iterable`では
Java.from() `で変換します. -
`List <User>`ではJSON形式の文字列に変換します
JSON.parseを介してJSオブジェクトに変換します。このトリックは、任意のJavaオブジェクトのJavaScript変換で機能するはずです。
/static/js/render.js
…./
Bindings to use mustache.js with Nashorn.
//
String templates: the Mustache template content. e.g hello.html
Map model: the model in controller
String url: the templates url (since 4.2.2)
/function render(template, model, url) {
return Mustache.render(template, toJsonObject(model));
}
function toJsonObject(model) {
var o = {};
for (var k in model) {
//Convert Object String to Javascript JSON if (k.indexOf("__json") > -1) { o[k]= JSON.parse(model[k]); continue; }
//Convert Iterable like List to real JSON array if (model[k]instanceof Java.type("java.lang.Iterable")) { o[k]= Java.from(model[k]); } else { o[k]= model[k]; } } return o; }
=== 6.その他のクラス 6.1 `webInitializer`クラスを作成して、` web.xml` Webアプリケーションを作成しません。 MyWebInitializer
package com.mkyong.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import com.mkyong.config.SpringWebConfig;
public class MyWebInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
@Override protected Class<?>[]getServletConfigClasses() { return new Class[]{ SpringWebConfig.class }; }
@Override protected String[]getServletMappings() { return new String[]{ "/" }; }
@Override protected Class<?>[]getRootConfigClasses() { return null; }
}
6.2ユーザオブジェクト。 User.java
package com.mkyong.web.model;
public class User {
String email; int loginFailed;
public User(String email, int loginFailed) { this.email = email; this.loginFailed = loginFailed; }
//setters and getters }
=== 7.デモ 7.1 __http://localhost:8080/spring/__ image://wp-content/uploads/2016/01/spring-mustache-demo1.png[spring-mustache-demo1、width = 1014、height = 703] 7.2 __http://localhost:8080/spring/__ image://wp-content/uploads/2016/01/spring-mustache-demo2.png[spring-mustache-demo2、width = 999、height = 1570] === 8.このプロジェクトをどのように実行するのですか? 8.1 Githubからソースコードをクローンします。
8.2組み込みJettyコンテナを実行します。
$ mvn jetty:run
8.3訪問URL:__http://localhost:8080/spring/__ === ソースコードをダウンロードする ダウンロード:link://wp-content/uploads/2016/01/spring-mvc-mustache.zip[spring-mvc-mustache.zip](127 KB) Githubのリンク - https://github.com/mkyong/spring-mvc-mustache-js-template[spring-mvc-mustache-js-template.git] === 参考文献 . http://mustache.github.io/[Mustache - ロジックレステンプレート] . https://github.com/janl/mustache.js[Mustache - Javascript] . http://docs.spring.io/spring/docs/current/spring-framework-reference/html/view.html#view-script[Spring IO - ビューテンプレート]。 https://speakerdeck.com/sdeleuze/isomorphic-templating-with-spring-boot-nashorn-and-react[Isomorphic Spring Boot、Nashorn、Reactでのテンプレート化]。 http://winterbe.com/posts/2014/04/05/java8-nashorn-tutorial/[Java 8 ナショーンチュートリアル]。 https://github.com/sdeleuze/spring-react-isomorphic[Spring React 例]。 https://github.com/mjeanroy/springmvc-mustache[さらに別の春 口ひげソリューション]。 http://isomorphic.net/[異形JavaScript] link://tag/mustache/[mustache]link://tag/spring-mvc/[spring mvc]