Velocity魔法堂系列三:模板与宿主环境通信

简介:

一、前言                          

  Velocity作为历史悠久的模板引擎不单单可以替代JSP作为Java Web的服务端网页模板引擎,而且可以作为普通文本的模板引擎来增强服务端程序文本处理能力。而且Velocity被移植到不同的平台上,如.Net的 NVelocity和js的Velocity.js,虽然各平台在使用和实现上略有差别,但大部分语法和引擎核心的实现是一致的,因此学习成本降低不少 哦。

  最好的学习资源——官网:http://velocity.apache.org/

  本系列打算采用如下结构对Velocity进行较为全面的学习,若有不妥或欠缺望大家提出,谢谢。

  1. 入门示例

  2. VTL语法详解

  3. 模板与宿主环境通信

  4. 基础配置项

  5. 深入模板引擎及调优配置

 

二、模板与宿主环境通信                   

  模板指的是使用VTL编写的Velocity模板,宿主环境指的是Java代码调用部分。而两者通信的纽带就是引擎上下文对象( VelocityContext实例 ),下面是常用的 VelocityContext实例 方法。

// 构造函数,入参为上下文的键值对集
VelocityContext(Map context)
// 添加上下文的键值对
Object put(String key, Object value)
// 从上下文获取指定键的值
Object get(String key)
// 检查上下文中是否存在指定的键值对
boolean containsKey(Object key)
// 获取所有键
Object[] getKeys()
// 移除指定键
Object remove(Object key)
// 获取上下文链中邻近的上下文对象
Context getChainedContext()

 

三、宿主环境向模板传值                    


// 1. 通过构造函数传值
HashMap<String, String> baseCtx = new HashMap<String, String>();
baseCtx.put("version", "1");
VelocityContext ctx = new VelocityContext(baseCtx);

// 2. 通过put传值
ctx.put("author", "fsjohnhuang");

注意键值对中值的数据类型为

Integer、Long等简单数据类型的装箱类型;

String类型

Object子类

Object[] 数组类型,从1.6开始Velocity将数组类型视为 java.util.List 类型看待,因此模板中可调用 size() 、 get(intindex) 和 isEmpty() 的变量方法;

java.util.Collection子类;

java.util.Map子类;

java.util.Iterator对象;

java.util.Enumeration对象。

除此之外,我们还可以将一个静态类赋予到上下文对象中,如 java.lang.Math静态类 

ctx.put("Math", java.lang.Math.class);

四、模板向宿主环境传值                      

  1.  通信示例1——通过引擎上下文对象获取变量

  模板文件frm.vm

#set($action="./submit")
<form action="$action">
  .........
</form>
  Java代码部分
VelocityContext ctx = new VelocityContext();
VelocityEngine ve = new VelocityEngine();
StringWriter sw = new StringWriter();
ve.mergeTemplate("frm.vm", ctx, sw);
String actionStr = ctx.get("action");
System.out.println(actionStr); // 显示./submit

 

  2.  通信示例2——通过副作用修改变量、属性值

  模板文件change.vm

$people.put("john", "john huang")
#set($version = $version + 1)
  Java代码部分
VelocityContext ctx = new VelocityContext();
ctx.put("version", 1);
HashMap<String, String> people = new HashMap<String,String>();
ctx.put("people", people);
VelocityEngine ve = new VelocityEngine();
StringWriter sw = new StringWriter();
ve.mergeTemplate("change.vm", ctx, sw);
System.out.println(ctx.get("version")); // 显示2
System.out.println(people.get("john")); //显示john huang

上述示例表明在模板中对引用类型实例进行操作时,操作结果将影响到该引用类型实例本身,因此必须谨慎操作。

 

五、引擎上下文链                          

  所谓引擎上下文链就是将原有的上下文对象赋予给新建的上下文对象,从而达到上下文内的键值对复用。具体代码如下:

VelocityContext ctx1 = new VelocityContext();
ctx1.put("name", "fsjohuang");
ctx1.put("version", 1);
VelocityContext ctx2 = new VelocityContext(ctx1);
ctx2.put("version", 2);

System.out.println(ctx2.get("name")); // 显示fsjohnhuang
System.out.println(ctx2.get("version")); // 显示2

    就是当前上下文对象没有该键值对时,则查询上下文链的对象有没有该键值对,有则返回,无则继续找链上的其他上下文对象,直到找到该键值对或遍历完所有链上的上下文对象。

    但VelocityContext实例除了put、get方法外,还有remove、getKeys、containsKey方法,它们的行为又是如何的呢?下面我们通过源码来了解吧!

 

六、从源码看引擎上下文                        

  从源码 public class VelocityContext extends AbstractContext implements Cloneable 得 知VelocityContext继承自AbstractContext抽象类,且实现了抽象类的internalGet、internalPut、 internalContainsKey、internalGetKeys和internalRemove方法,实际开发中常用的put、get等方法却 是由AbstractContext提供的,而put、get方法内部在调用对应的internalGet、internalPut方法外再进行了其他处 理。这是一种由子类提供具体实现,父类提供对外接口的设计方式(但与纯面向接口编程又有些区别)。

  VelocityContext类源码片段:


public class VelocityContext extends AbstractContext implements Cloneable
{
  private Map context = null;
  
  public Object internalGet( String key )
  {
      return context.get( key );
  }

  public Object internalPut( String key, Object value )
  {
      return context.put( key, value );
  }

  public  boolean internalContainsKey(Object key)
  {
      return context.containsKey( key );
  }

  public  Object[] internalGetKeys()
  {
      return context.keySet().toArray();
  }

  public  Object internalRemove(Object key)
  {
      return context.remove( key );
  }
}

从上面可知VelocityContext内置一个Map实例,而各实例方法均为对该Map实例的操作。

  AbstractContext类源码片段:


public abstract class AbstractContext extends InternalContextBase
    implements Context
{
    // 上下文对象链中邻近的上下文对象
    private   Context  innerContext = null;

    // 只将键值对存放在当前上下文对象的Map对象中
    public Object put(String key, Object value)
    {
        /*
         * don't even continue if key is null
         */
        if (key == null)
        {
            return null;
        }
        
        return internalPut(key.intern(), value);
    }

     // 从当前上下文对象的HashMap对象获取键值
     //  失败再从上下文链中寻找
     public Object get(String key)
    {
        if (key == null)
        {
            return null;
        }


        Object o = internalGet( key );

        if (o == null && innerContext != null)
        {
            o = innerContext.get( key );
        }

        return o;
    }

    // 搜索整条上下文链的对象是否包含指定键值对
    public boolean containsKey(Object key)
    {
        if (key == null)
        {
            return false;
        }

        boolean exists = internalContainsKey(key);
        if (!exists && innerContext != null)
        {
            exists = innerContext.containsKey(key);
        }
        
        return exists;
    }

    // 仅返回当前上下文对象的Map对象的键
    public Object[] getKeys()
    {
        return internalGetKeys();
    }

    // 仅移除当前上下文对象的Map对象指定的键值对
    // 上下文链上的其他对象不受影响
     public Object remove(Object key)
    {
        if (key == null)
        {
            return null;
        }

        return internalRemove(key);
    }
}

 引擎上下文链就是通过AbstractContext实现的,跟JS的原型链相同。

 

七、总结                              

   本节简单介绍了模板与宿主环境通信的两种方式,并透过源码了解了一下VelocityContext和上下文链的实现,但想继续深入上下文的实现那请自行阅读AbstractContext的父类InternalContextBase了。

目录
相关文章
|
6月前
|
JSON 小程序 JavaScript
微信小程序之项目基本结构、页面的基础及宿主环境
微信小程序之项目基本结构、页面的基础及宿主环境
145 1
|
24天前
|
JavaScript 前端开发
前端js,vue系统使用iframe嵌入第三方系统的父子系统的通信
前端js,vue系统使用iframe嵌入第三方系统的父子系统的通信
|
3月前
|
编解码 JavaScript 前端开发
JS逆向浏览器脱环境专题:事件学习和编写、DOM和BOM结构、指纹验证排查、代理自吐环境通杀环境检测、脱环境框架、脱环境插件解决
JS逆向浏览器脱环境专题:事件学习和编写、DOM和BOM结构、指纹验证排查、代理自吐环境通杀环境检测、脱环境框架、脱环境插件解决
98 1
|
3月前
|
前端开发 开发者 开发框架
JSF与Bootstrap,打造梦幻响应式网页!让你的应用跨设备,让用户爱不释手!
【8月更文挑战第31天】在现代Web应用开发中,响应式设计至关重要,以确保不同设备上的良好用户体验。本文探讨了JSF(JavaServer Faces)与Bootstrap框架的结合使用,展示了如何构建响应式网页。JSF是一个基于Java的Web应用框架,提供丰富的UI组件和表单处理功能;而Bootstrap则是一个基于HTML、CSS和JavaScript的前端框架,专注于实现响应式设计。通过结合两者的优势,开发者能够更便捷地创建自适应布局,提升Web应用体验。然而,这种组合也有其局限性,如JSF组件库较小和较高的学习成本等,因此在选择开发框架时需综合考虑具体需求和应用场景。
47 0
|
5月前
|
前端开发 JavaScript 开发者
Web技术标准是如何定义网页的?
【6月更文挑战第2天】Web技术标准是如何定义网页的?
87 2
|
6月前
|
前端开发 安全 JavaScript
Astro 2.0正式发布,现代化静态站点生成器
Astro 2.0正式发布,现代化静态站点生成器
144 0
|
JavaScript 前端开发 数据库
Unity3d(webGL)构建数字孪生小案例(包含完整的数据交互体系)附赠完整代码
Unity3d(webGL)构建数字孪生小案例(包含完整的数据交互体系)附赠完整代码,请关注公众号:拼搏的小浣熊,获取简化版的代码!
|
安全 前端开发 JavaScript
使用Gatsby构建静态网站:快速、安全和可扩展
Gatsby是一款现代化的静态网站生成器,它结合了React和GraphQL的强大功能,可以帮助开发人员快速构建高性能、安全和可扩展的静态网站。本文将介绍如何使用Gatsby创建一个简单的静态网站,并展示一些实例代码来帮助您入门。
249 0
|
数据可视化 搜索推荐
云宇宙编辑器+Web 3D可视化引擎 源代码技术源码有公司需要吗?
元宇宙展厅在线编辑器: 我们提供一键式的元宇宙空间生成工具,支持 个性化场景搭建和多媒体内容添加。普通用 户也可以在短时间内完成数字展厅的设计和 制作,让您足不出户就可以搭建属于自己的 虚拟数字展厅。 Web 3D可视化引擎: 一种浏览器端的3D引擎技术,它可以在网页中 插入和展示3D模型,及3D场景搭建,提供节点 与组件,在网页中搭建复杂的3D场景。
|
JSON 小程序 前端开发
微信小程序--》组成结构 文件作用 宿主环境
⚓经过web前端开发的学习,相信大家对于前端开发有了一定深入的了解,今天我开设了微信小程序,主要想从移动端开发方向进一步发展,而对于我来说写移动端博文的第一站就是小程序开发,希望看到我文章的朋友能对你有所帮助。
193 0
 微信小程序--》组成结构 文件作用 宿主环境