在本教程中,我们将向您展示Spring MVC + Mustache JS模板 Web应用程序示例。
使用的技术:
- Spring4.2.4。发布
- mustache.js
- JDK 1.8.0_66
- 杰克逊2.7
- Eclipse 4.3
- 雄猫8
- Maven 3
- 引导程序3
注意
该解决方案仍然有效,但建议使用此简单的Spring Boot + JMustache解决方案。
在Spring,我们可以使用ScriptTemplateConfigurer
集成大多数JS模板库,例如Mustache,Handlebars或React。 请参阅此官方Spring脚本模板文档。
从Spring 4.2开始就支持PS ScriptTemplateConfigurer
注意
本示例将使用内置的Java 8 Nashorn Javascript引擎在服务器端运行“ Mustache JS”。 一个同构的javascript示例。
1.项目结构
标准的Maven文件夹结构。
2. pom.xml
一个Maven 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
。 参见评论以进行自我解释。
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.弹簧控制器+小胡子模板
4.1一个将数据传递到Mustache模板的Spring控制器。
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("abc@gmail.com", 0));
//4. Test List<Object>
List<User> list = new ArrayList<>();
list.add(new User("aaa@gmail.com", 1));
list.add(new User("bbb@yahoo.com", 2));
list.add(new User("ccc@hotmail.com", 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一个Mustache模板文件,用于显示来自上述Spring控制器的数据。
<!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语言支持所有Java对象或数据类型,因此需要转换,尤其是List<Object>
。
总结:
- 对于原始数据类型,无需进行转换。
- 对于
java.lang.Iterable
,将其与Java.from()
转换。 - 对于
List<User>
,使用Jackson
将其转换为JSON格式的字符串,然后通过JSON.parse
将其转换为JS对象。 此技巧应可在任何Java对象JavaScript转换中使用。
/**
* 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));
}
// Some Java objects may not support in JS directly, need conversion.
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应用程序。
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用户对象。
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 /
7.2 http:// localhost:8080 / spring /
8.如何运行该项目?
8.1从Github克隆源代码。
$ git clone https://github.com/mkyong/spring-mvc-mustache-js-template
8.2运行嵌入式Jetty容器。
$ mvn jetty:run
8.3访问URL: http:// localhost:8080 / spring /
下载源代码
下载– spring-mvc-mustache.zip (127 KB)
Github链接– spring-mvc-mustache-js-template.git
参考文献
- 小胡子–无逻辑模板
- 小胡子– Javascript
- Spring IO –查看模板
- 使用Spring Boot,Nashorn和React的同构模板
- Java 8 Nashorn教程
- Spring React示例
- Spring小胡子的另一个解决方案
- 同构JavaScript
翻译自: https://mkyong.com/spring-mvc/spring-mvc-mustache-js-template-example/