SpringBoot下配置FreeMarker配置远程模版
需求产生原因
- 要求在同一个接口中,根据不同的参数,返回不同的视图结果
- 所有的视图中的数据基本一致
- 要求页面能静态化,优化SEO
例如:A接口返回客户的信息
- 客户A在调用接口时,返回其个性化定制的页面A
- 客户B在调用这个接口时,返回其个性化主页B
实现方式 freemaker 的 TemplateLoader
freemaker的配置类freemarker.template.Configuration中提供了一个配置模版加载器的方法
setTemplateLoader,需求是要求同时能加载本地和远程的模版,但是只提供了一个模版加载器的set方法,查询文档后官方给出了建议
//远程模版加载 RemoteTemplateLoader remoteTemplateLoader = new RemoteTemplateLoader(remotePath); //本地模版加载 ClassTemplateLoader classTemplateLoader = new ClassTemplateLoader(getClass(), "/WEB-INF/pages/"); MultiTemplateLoader templateLoader = new MultiTemplateLoader(new TemplateLoader[] {classTemplateLoader,remoteTemplateLoader});
- SpringBoot配置
import freemarker.cache.ClassTemplateLoader;
import freemarker.cache.MultiTemplateLoader;
import freemarker.cache.TemplateLoader;
import freemarker.template.TemplateDirectiveModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import javax.annotation.PostConstruct;
import java.util.Map;
import java.util.Set;
/**
* Freemarker配置
* @author wpy
* @create 2017/11/8 14:51
* @project_name jcstore
*/
@Configuration
public class FreemarkerConfig {
@Autowired
private FreeMarkerConfigurer freeMarkerConfigurer;
@Autowired
private WebApplicationContext applicationContext;
// @Value("")
private String remotePath = "http://localhost:8080/static";
@PostConstruct
public void freeMarkerConfigurer() {
freemarker.template.Configuration configuration = freeMarkerConfigurer.getConfiguration();
//注册所有自定义标签
Map<String, TemplateDirectiveModel> tagsMap = applicationContext.getBeansOfType(TemplateDirectiveModel.class);
Set<Map.Entry<String, TemplateDirectiveModel>> entries = tagsMap.entrySet();
entries.forEach(entry ->
configuration.setSharedVariable(entry.getKey(), entry.getValue())
);
//远程模版加载
RemoteTemplateLoader remoteTemplateLoader = new RemoteTemplateLoader(remotePath);
//本地模版加载
ClassTemplateLoader classTemplateLoader = new ClassTemplateLoader(getClass(), "/WEB-INF/pages/");
MultiTemplateLoader templateLoader = new MultiTemplateLoader(new TemplateLoader[] {classTemplateLoader,remoteTemplateLoader});
configuration.setTemplateLoader(templateLoader);
}
}
- RemoteTemplateLoader 实现
import freemarker.cache.URLTemplateLoader;
import java.net.URL;
import java.net.URLConnection;
/**
* 自定义远程模板加载器,用来加载文件服务
*
* @author Administrator
*/
public class RemoteTemplateLoader extends URLTemplateLoader {
// 远程模板文件的存储路径(目录)
private String remotePath;
public RemoteTemplateLoader(String remotePath) {
if (remotePath == null) {
throw new IllegalArgumentException("remotePath is null");
}
this.remotePath = canonicalizePrefix(remotePath);
if (this.remotePath.indexOf('/') == 0) {
this.remotePath = this.remotePath.substring(this.remotePath
.indexOf('/') + 1);
}
}
@Override
protected URL getURL(String name) {
String fullPath = this.remotePath + name;
if ((this.remotePath.equals("/")) && (!isSchemeless(fullPath))) {
return null;
}
if (name.contains("WEB-INF/template/")) {
fullPath = fullPath.replace("WEB-INF/template/", "");
}
URL url = null;
try {
url = new URL(fullPath);
URLConnection con = url.openConnection();
long lastModified = con.getLastModified();
if (lastModified == 0) {
url = null;
}
} catch (Exception e) {
e.printStackTrace();
url = null;
}
return url;
}
private static boolean isSchemeless(String fullPath) {
int i = 0;
int ln = fullPath.length();
if ((i < ln) && (fullPath.charAt(i) == '/'))
i++;
while (i < ln) {
char c = fullPath.charAt(i);
if (c == '/')
return true;
if (c == ':')
return false;
i++;
}
return true;
}
}
- 自定义标签实现
/**
* 自定义标签示例
*
* <table style="width: 633px; height: 217px;" border="0">
<tbody>
<tr>
<td style="text-align: center;"><span style="font-size: 13px;"><strong>类型</strong></span></td>
<td style="text-align: center;"><span style="font-size: 13px;"><strong>FreeMarker接口</strong></span></td>
<td style="text-align: center;"><span style="font-size: 13px;"><strong>FreeMarker实现</strong></span></td>
</tr>
<tr>
<td style="text-align: center;"><span style="font-size: 13px;">字符串</span></td>
<td style="text-align: left;"><span style="font-size: 13px;">TemplateScalarModel</span></td>
<td style="text-align: left;"><span style="font-size: 13px;">SimpleScalar</span></td>
</tr>
<tr>
<td style="text-align: center;"><span style="font-size: 13px;">数值</span></td>
<td style="text-align: left;"><span style="font-size: 13px;">TemplateNumberModel</span></td>
<td style="text-align: left;"><span style="font-size: 13px;">SimpleNumber</span></td>
</tr>
<tr>
<td style="text-align: center;"><span style="font-size: 13px;">日期</span></td>
<td style="text-align: left;"><span style="font-size: 13px;">TemplateDateModel</span></td>
<td style="text-align: left;"><span style="font-size: 13px;">SimpleDate</span></td>
</tr>
<tr>
<td style="text-align: center;"><span style="font-size: 13px;">布尔</span></td>
<td style="text-align: left;"><span style="font-size: 13px;">TemplateBooleanModel</span></td>
<td style="text-align: left;"><span style="font-size: 13px;">TemplateBooleanModel.TRUE</span></td>
</tr>
<tr>
<td style="text-align: center;"><span style="font-size: 13px;">哈希</span></td>
<td style="text-align: left;"><span style="font-size: 13px;">TemplateHashModel</span></td>
<td style="text-align: left;"><span style="font-size: 13px;">SimpleHash</span></td>
</tr>
<tr>
<td style="text-align: center;"><span style="font-size: 13px;">序列</span></td>
<td style="text-align: left;"><span style="font-size: 13px;">TemplateSequenceModel</span></td>
<td style="text-align: left;"><span style="font-size: 13px;">SimpleSequence</span></td>
</tr>
<tr>
<td style="text-align: center;"><span style="font-size: 13px;">集合</span></td>
<td style="text-align: left;"><span style="font-size: 13px;">TemplateCollectionModel</span></td>
<td style="text-align: left;"><span style="font-size: 13px;">SimpleCollection</span></td>
</tr>
<tr>
<td style="text-align: center;"><span style="font-size: 13px;">节点</span></td>
<td><span style="font-size: 13px;">TemplateNodeModel</span></td>
<td><span style="font-size: 13px;">NodeModel</span></td>
</tr>
</tbody>
</table>
* @author wpy
* @create 2017/11/8 14:34
* @project_name jcstore
*/
@Component
public class ExampleTag implements TemplateDirectiveModel {
/**
* 标签中的参数 name
*/
private static final String NAME = "name";
/**
*
*/
private static final String AGE = "age";
/**
*
*/
private static final String SEX = "sex";
private DefaultObjectWrapper objectWrapper;
{
Version version = new Version("2.3.21");
DefaultObjectWrapperBuilder defaultObjectWrapperBuilder = new DefaultObjectWrapperBuilder(version);
objectWrapper = defaultObjectWrapperBuilder.build();
}
@Override
public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException {
TemplateScalarModel name = (TemplateScalarModel) params.get("name");
TemplateNumberModel age = (TemplateNumberModel) params.get("age");
TemplateScalarModel sex = (TemplateScalarModel) params.get("sex");
JSONObject jsonObject = new JSONObject();
jsonObject.put("name",name.getAsString() + 1);
jsonObject.put("age",age.getAsNumber().intValue() + 1);
jsonObject.put("sex",sex.getAsString().equals("男") ? "女":"男");
TemplateModel wrap = objectWrapper.wrap(jsonObject);
if(loopVars.length > 0){
loopVars[0] = wrap;
}
body.render(env.getOut());
}
}
- 模版 exampleTag.ftl
<html>
<head></head>
<body>
<h1> 自定义标签测试(我是远程模版)</h1>
<p>
<@exampleTag name = "张三" age = 18 sex = "男"; loopv>
<h1>${loopv.name}</h1>
<h1>${loopv.age}</h1>
<h1>${loopv.sex}</h1>
</@exampleTag>
</p>
</body>
</html>
- CustomTagController
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author wpy
* @create 2017/11/8 15:02
* @project_name jcstore
*/
@Controller
public class CustomTagController {
@RequestMapping("/testTags")
public String testTags(){
return "/common/exampleTag";
}
@RequestMapping("/testTagsRemote")
public String testTagsRemote(){
return "/exampleTag";
}
}
SpringBoot下配置FreeMarker配置远程模版的更多相关文章
- springboot下https证书配置
没有证书的小伙伴首先申请一个阿里云免费证书,按照我的步骤来操作 1.购买页面是这样的 按照顺序选择 神奇的一幕出现了 然后就去购买成功,我们会看到证书没有签发,我们需要去申请 填写需要绑定的域名 一般 ...
- SpringBoot下Schdule的配置与使用
我们在平常项目开发中,经常会用到周期性定时任务,这个时候使用定时任务就能很方便的实现.在SpringBoot中用得最多的就是Schedule. 一.SpringBoot集成Schedule 1.依赖配 ...
- spring-boot下mybatis的配置
问题描述:spring boot项目想添加mybatis的配置,在src/main/resources目录下新建了mybatis-config.xml文件,在application.propertie ...
- SpringBoot下,@WebFilter配置获取日志
CREATE TABLE [dbo].[SWEBSERVICELOG]( [WLG_ID] [varchar](100) NOT NULL, [WLG_SESSIONID] [varchar](100 ...
- SpringBoot下如何配置实现跨域请求?
一.什么是跨域请求? 跨域请求,就是说浏览器在执行脚本文件的ajax请求时,脚本文件所在的服务地址和请求的服务地址不一样.说白了就是ip.网络协议.端口都一样的时候,就是同一个域,否则就是跨域.这是由 ...
- SpringBoot(十三)-- 不同环境下读取不同配置
一.场景: 在开发过程中 会使用 开发的一套数据库,测试的时候 又会使用测试的数据库,生产环境中 又会切换到生产环境中.常用的方式是 注释掉一些配置,然后释放一下配置.SpringBoot提供了在不同 ...
- Yii2项目高级模版 三个模块在同一个目录下的重定向配置
最近做项目用到的,非常好用. 修改 advanced/backend/config/main.PHP 文件如下: return [ 'homeUrl' => '/admin', 'compone ...
- springboot集成freemarker 配置application.properties详解
#配置freemarker详解 #spring.freemarker.allow-request-override=false # Set whether HttpServletRequest att ...
- spring boot 配置 freemarker
1.springboot 中自带的页面渲染工具为thymeleaf 还有freemarker 这两种模板引擎 简单比较下两者不同, 1.1freemaker 优点 freemarker 不足:thym ...
随机推荐
- Redis——windows环境安装redis和redis sentinel部署
一:Redis的下载和安装 1:下载Redis Redis的官方网站Download页面,Redis提示说:Redis的正式版不支持Windows,要Windows学习Redis,请点击Learn m ...
- Spring-Boot:Spring Cloud构建微服务架构
概述: 从上一篇博客<Spring-boot:5分钟整合Dubbo构建分布式服务> 过度到Spring Cloud,我们将开始学习如何使用Spring Cloud 来搭建微服务.继续采用上 ...
- C-多个行内块布局
1 消除间隔
- 【转】 Python subprocess模块学习总结
从Python 2.4开始,Python引入subprocess模块来管理子进程,以取代一些旧模块的方法:如 os.system.os.spawn*.os.popen*.popen2.*.comman ...
- 关于Struts与Ajax整合时的异常处理
关于Struts与Ajax整合时的异常处理问题: 问题还原: 从而当有异常发出时,会将异常信息发送到页面上.如下图所示:这是一个比较经典的过程: 错误提示页面: 由于sendError()方法里 ...
- Java高新技术 Myeclipse 介绍
Java高新技术 Myeclipse 介绍 知识概述: (1)Myeclipse开发工具介绍 (2)Myeclipse常用开发步骤详解 ...
- Echarts数据可视化全解注释
全栈工程师开发手册 (作者:栾鹏) Echarts数据可视化开发代码注释全解 Echarts数据可视化开发参数配置全解 6大公共组件详解(点击进入): title详解. tooltip详解.toolb ...
- PhoneWindow,ViewRoot,Activity之间的大致关系
http://www.nowamagic.net/academy/detail/50160216 在android里,我们都知道activity.但是一个activity跟一个Window是一个什么关 ...
- 使用Gradle构建Android项目
阅读目录 Gradle是什么? 环境需求 Gradle基本结构 任务task的执行 基本的构建定制 目录配置 签名配置 代码混淆设置 依赖配置 输出不同配置的应用 生成多个渠道包(以Umeng为例) ...
- Extjs6(七)——增删查改之删除
本文基于ext-6.0.0 页面就是前面写的那个,有不清楚的可以看一下前面写页面那篇. 一.在toolbar加一个删除按钮 { text:'删除', iconCls:'x-fa fa-times', ...