需求产生原因

  • 要求在同一个接口中,根据不同的参数,返回不同的视图结果
  • 所有的视图中的数据基本一致
  • 要求页面能静态化,优化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. Redis——windows环境安装redis和redis sentinel部署

    一:Redis的下载和安装 1:下载Redis Redis的官方网站Download页面,Redis提示说:Redis的正式版不支持Windows,要Windows学习Redis,请点击Learn m ...

  2. Spring-Boot:Spring Cloud构建微服务架构

    概述: 从上一篇博客<Spring-boot:5分钟整合Dubbo构建分布式服务> 过度到Spring Cloud,我们将开始学习如何使用Spring Cloud 来搭建微服务.继续采用上 ...

  3. C-多个行内块布局

    1 消除间隔

  4. 【转】 Python subprocess模块学习总结

    从Python 2.4开始,Python引入subprocess模块来管理子进程,以取代一些旧模块的方法:如 os.system.os.spawn*.os.popen*.popen2.*.comman ...

  5. 关于Struts与Ajax整合时的异常处理

     关于Struts与Ajax整合时的异常处理问题: 问题还原: 从而当有异常发出时,会将异常信息发送到页面上.如下图所示:这是一个比较经典的过程: 错误提示页面: 由于sendError()方法里 ...

  6. Java高新技术 Myeclipse 介绍

      Java高新技术   Myeclipse 介绍 知识概述:              (1)Myeclipse开发工具介绍 (2)Myeclipse常用开发步骤详解               ...

  7. Echarts数据可视化全解注释

    全栈工程师开发手册 (作者:栾鹏) Echarts数据可视化开发代码注释全解 Echarts数据可视化开发参数配置全解 6大公共组件详解(点击进入): title详解. tooltip详解.toolb ...

  8. PhoneWindow,ViewRoot,Activity之间的大致关系

    http://www.nowamagic.net/academy/detail/50160216 在android里,我们都知道activity.但是一个activity跟一个Window是一个什么关 ...

  9. 使用Gradle构建Android项目

    阅读目录 Gradle是什么? 环境需求 Gradle基本结构 任务task的执行 基本的构建定制 目录配置 签名配置 代码混淆设置 依赖配置 输出不同配置的应用 生成多个渠道包(以Umeng为例) ...

  10. Extjs6(七)——增删查改之删除

    本文基于ext-6.0.0 页面就是前面写的那个,有不清楚的可以看一下前面写页面那篇. 一.在toolbar加一个删除按钮 { text:'删除', iconCls:'x-fa fa-times', ...