需求产生原因

  • 要求在同一个接口中,根据不同的参数,返回不同的视图结果
  • 所有的视图中的数据基本一致
  • 要求页面能静态化,优化SEO

例如:A接口返回客户的信息

  1. 客户A在调用接口时,返回其个性化定制的页面A
  2. 客户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配置远程模版的更多相关文章

  1. springboot下https证书配置

    没有证书的小伙伴首先申请一个阿里云免费证书,按照我的步骤来操作 1.购买页面是这样的 按照顺序选择 神奇的一幕出现了 然后就去购买成功,我们会看到证书没有签发,我们需要去申请 填写需要绑定的域名 一般 ...

  2. SpringBoot下Schdule的配置与使用

    我们在平常项目开发中,经常会用到周期性定时任务,这个时候使用定时任务就能很方便的实现.在SpringBoot中用得最多的就是Schedule. 一.SpringBoot集成Schedule 1.依赖配 ...

  3. spring-boot下mybatis的配置

    问题描述:spring boot项目想添加mybatis的配置,在src/main/resources目录下新建了mybatis-config.xml文件,在application.propertie ...

  4. SpringBoot下,@WebFilter配置获取日志

    CREATE TABLE [dbo].[SWEBSERVICELOG]( [WLG_ID] [varchar](100) NOT NULL, [WLG_SESSIONID] [varchar](100 ...

  5. SpringBoot下如何配置实现跨域请求?

    一.什么是跨域请求? 跨域请求,就是说浏览器在执行脚本文件的ajax请求时,脚本文件所在的服务地址和请求的服务地址不一样.说白了就是ip.网络协议.端口都一样的时候,就是同一个域,否则就是跨域.这是由 ...

  6. SpringBoot(十三)-- 不同环境下读取不同配置

    一.场景: 在开发过程中 会使用 开发的一套数据库,测试的时候 又会使用测试的数据库,生产环境中 又会切换到生产环境中.常用的方式是 注释掉一些配置,然后释放一下配置.SpringBoot提供了在不同 ...

  7. Yii2项目高级模版 三个模块在同一个目录下的重定向配置

    最近做项目用到的,非常好用. 修改 advanced/backend/config/main.PHP 文件如下: return [ 'homeUrl' => '/admin', 'compone ...

  8. springboot集成freemarker 配置application.properties详解

    #配置freemarker详解 #spring.freemarker.allow-request-override=false # Set whether HttpServletRequest att ...

  9. spring boot 配置 freemarker

    1.springboot 中自带的页面渲染工具为thymeleaf 还有freemarker 这两种模板引擎 简单比较下两者不同, 1.1freemaker 优点 freemarker 不足:thym ...

随机推荐

  1. 【JVM命令系列】javap

    命令基本概述 javap是JDK自带的反汇编器,可以查看java编译器为我们生成的字节码.通过它,可以对照源代码和字节码,从而了解很多编译器内部的工作.可以在命令行窗口先用javap -help看下j ...

  2. 在asp.net web api 2 使用 Serilog 记录日志

    Serilog是.net里面非常不错的记录日志的库,另外一个我认为比较好的Log库是NLog. 在我个人的asp.net web api 2 基础框架(Github地址)里,我原来使用的是NLog,但 ...

  3. spring boot系列01--快速构建spring boot项目

    最近的项目用spring boot 框架 借此学习了一下 这里做一下总结记录 非常便利的一个框架 它的优缺点我就不在这背书了 想了解的可以自行度娘谷歌 说一下要写什么吧 其实还真不是很清楚,只是想记录 ...

  4. 天上掉Pizza

    天上掉Pizza 时间限制: 3 Sec  内存限制: 128 MB提交: 73  解决: 48[提交][状态][讨论版] 题目描述 明明喜欢Pizza,但总是缺钱.有一天,他在报纸上阅读,他最喜爱的 ...

  5. Island Perimeter

    You are given a map in form of a two-dimensional integer grid where 1 represents land and 0 represen ...

  6. Angular JS中的路由

      前  言            本章节将为大家介绍 AngularJS 路由.AngularJS 路由允许我们通过不同的 URL 访问不同的内容.通过 AngularJS 可以实现多视图的单页We ...

  7. java web jsp原理图 ,静态包含,动态包含,out与response.getWrite()

    jsp原理图 ,静态包含,动态包含,out与response.getWrite() 

  8. Spring事务管理配置示例

    (一).Spring事务特性 1.事务隔离级别 隔离级别是指若干个并发的事务之间的隔离程度. ISOLATION_DEFAULT:默认值,使用数据库的默认隔离级别,就是ISOLATION_READ_C ...

  9. C#微信公众号/订阅号开发 接口源码

    using System; using System.Web; using System.IO; using System.Text; using System.Web.Security; using ...

  10. wpf C# 数据库 c/s 个人信息管理 wpf局域网通信

    系统功能基本要求 wpf局域网通信 WPF跨线程访问线程安全的数据如解决该类型的CollectionView不支持从调度程序线程以外的线程对其SourceCollection 读取信息null 读取发 ...