spring-mustache-image、width = 629、height = 121

このチュートリアルでは、Spring MVC +

Mustache JSテンプレート

Webアプリケーションの例を示します。

使用される技術:

  1. Spring 4.2.4.RELEASE

  2. mustache.js

  3. JDK 1.8.0__66

  4. ジャクソン2.7

  5. Eclipse 4.3

  6. Tomcat 8

  7. Maven 3

  8. ブートストラップ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フォルダ構造。


spring-mustache-project-directory、width = 446、height = 729

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> ‘が必要です。

要約:

  1. プリミティブデータ型の場合、変換の必要はありません.


  2. java.lang.Iterable`では

    Java.from() `で変換します.

  3. `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]