1、前言
使用Freemarker做模板构建页面是比较简单的,但在某些复杂的场景下需要在js中使用spring 中的model对象是个问题。
但是js不认识java对象。需要用Freemarker自定义函数去解决这个问题
2、项目构建
构建web应用
3.1、添加fastJson依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.57</version>
</dependency>
整个pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.whwe</groupId>
<artifactId>web-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>web-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.57</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3.2、配置webMvc
package com.whwe.webdemo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;
/**
* @ClassName WebMvcConfig
* @Description TODO
* @Author yueyiming
* @Date 2019/4/19 9:32
*/
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
/**
* Override this method to add resource handlers for serving static resources.
*
* @param registry
* @see ResourceHandlerRegistry
*/
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/js/**").addResourceLocations("classpath:/js/");
registry.addResourceHandler("/statics/**").addResourceLocations("classpath:/statics/");
super.addResourceHandlers(registry);
}
/**
* Override this method to configure cross origin requests processing.
*
* @param registry
* @see CorsRegistry
* @since 4.2
*/
@Override
protected void addCorsMappings(CorsRegistry registry) {
super.addCorsMappings(registry);
}
/**
* Override this method to add Spring MVC interceptors for
* pre- and post-processing of controller invocation.
*
* @param registry
* @see InterceptorRegistry
*/
@Override
protected void addInterceptors(InterceptorRegistry registry) {
super.addInterceptors(registry);
}
}
3.3、自定义java对象转成json的方法
package com.whwe.webdemo.json;
import com.alibaba.fastjson.JSON;
/**
* @ClassName MyJson
* @Description TODO
* @Author yueyiming
* @Date 2019/4/19 14:12
*/
public class MyJson {
public static String toJson(Object src) {
String json = JSON.toJSONString(src);
return json;
}
}
3.4、配置Freemarker的配置
FreeMarker内部使用的变量的类型都实现了freemarker.template.TemplateModel接口。
我们需要把我们刚才的自定义类包装成TemplateModel的子类TemplateHashModel
package com.whwe.webdemo.json;
import freemarker.ext.beans.BeansWrapper;
import freemarker.ext.beans.BeansWrapperBuilder;
import freemarker.template.*;
import lombok.extern.log4j.Log4j2;
import java.util.HashMap;
import java.util.Map;
@Log4j2
public class FreemarkerStaticModels extends HashMap<String, Object> {
public FreemarkerStaticModels(Map<String, String> classMap) {
for (String key : classMap.keySet()) {
put(key, getModel(classMap.get(key)));
}
}
private TemplateHashModel getModel(String packageName) {
BeansWrapper wrapper = new BeansWrapperBuilder(Configuration.VERSION_2_3_28).build();
TemplateHashModel fileStatics=null;
try {
fileStatics = (TemplateHashModel) wrapper.getStaticModels().get(packageName);
return fileStatics;
} catch (TemplateModelException e) {
log.error(e.toString());
}
return fileStatics;
}
}
自定义视图解析,配置freemarker的配置
package com.whwe.webdemo.config;
import com.whwe.webdemo.json.FreemarkerStaticModels;
import freemarker.template.TemplateException;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ui.freemarker.FreeMarkerConfigurationFactory;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import org.springframework.web.servlet.view.freemarker.FreeMarkerView;
import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;
import java.io.IOException;
import java.util.HashMap;
import java.util.Properties;
@Configuration
public class FreeMarkerConfig {
@Bean
public ViewResolver viewResolverFtl() {
FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();
resolver.setCache(false);
resolver.setViewClass(FreeMarkerView.class);
resolver.setRequestContextAttribute("re");
resolver.setExposeRequestAttributes(true);
resolver.setExposeSessionAttributes(true);
resolver.setSuffix(".ftl");
resolver.setContentType("text/html;charset=UTF-8");
resolver.setOrder(0);
//添加自定义解析器
resolver.setAttributesMap(new FreemarkerStaticModels(new HashMap<String, String>() {{
put("Json", "com.whwe.webdemo.json.MyJson");
}}));
return resolver;
}
@Bean
public FreeMarkerConfigurer freemarkerConfig() throws IOException, TemplateException {
FreeMarkerConfigurationFactory factory = new FreeMarkerConfigurationFactory();
factory.setTemplateLoaderPath("classpath:/view/");
factory.setDefaultEncoding("UTF-8");
factory.setPreferFileSystemAccess(false);
FreeMarkerConfigurer result = new FreeMarkerConfigurer();
freemarker.template.Configuration configuration = factory.createConfiguration();
configuration.setClassicCompatible(true);
result.setConfiguration(configuration);
Properties settings = new Properties();
settings.put("template_update_delay", "0");
settings.put("default_encoding", "UTF-8");
settings.put("number_format", "0.######");
settings.put("classic_compatible", true);
settings.put("template_exception_handler", "ignore");
result.setFreemarkerSettings(settings);
return result;
}
}
3.5、添加测试页面
index.ftl
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>欢迎</title>
</head>
<#assign base=request.contextPath />
<script src="${base}/js/jquery-3.4.0.min.js" type="text/javascript" ></script>
<body>
<div>
<h1>欢迎!</h1>
</div>
<script>
var user=${Json.toJson(user)};
console.log(user)
</script>
</body>
</html>
测试
新建测试controller
package com.whwe.webdemo.controller;
import com.whwe.webdemo.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @ClassName WebController
* @Description TODO
* @Author yueyiming
* @Date 2019/4/19 10:12
*/
@Controller
public class WebController {
@RequestMapping(value = "test")
public String test(Model model) {
User user=new User();
user.setAge(11);
user.setName("zhangsan");
model.addAttribute("user",user);
return "index";
}
}
package com.whwe.webdemo.bean;
import lombok.Data;
/**
* @ClassName User
* @Description TODO
* @Author yueyiming
* @Date 2019/4/19 14:31
*/
@Data
public class User {
private String name;
private int age;
}