Введение
Velocity Бесплатный шаблонизатор Java с долгой историей. Официальный сайт:velocity.apache.org/
Velocity — это механизм шаблонов на основе Java, простой, но мощный инструмент разработки, который позволяет легко создавать и отображать документы для форматирования и отображения данных.
*.vm : файлы шаблонов скорости
VTL: язык шаблонов скорости
При использовании механизма шаблонов Velocity необходимо сосредоточиться на двух аспектах:Шаблон скоростиа такжеВызов кода Java.
Шаблон скорости отVTLа такжеобъект контекста движкасоставляют;
Вызывающая часть Java-кода отвечает заДвигатель начальной скорости,Создайте объект контекста движка,Загрузить шаблон скоростиа такжеНачать рендеринг шаблона.
Связь между шаблоном Velocity и вызывающей частью кода Java:объект контекста движка.
Velocity был перенесен на разные платформы, такие как NVelocity из .Net и Velocity.js из js. Хотя каждая платформа имеет небольшие различия в использовании и реализации, большая часть синтаксиса и реализация ядра движка одинаковы, поэтому стоимость обучения уменьшается О много.
Требования к версии
Для Velocity2.1 или выше требуется jdk1.8 или выше
Velocity2.2 зависимости maven
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.apache.velocity.tools</groupId>
<artifactId>velocity-tools-generic</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>org.apache.velocity.tools</groupId>
<artifactId>velocity-tools-view</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>org.apache.velocity.tools</groupId>
<artifactId>velocity-tools-view-jsp</artifactId>
<version>3.0</version>
</dependency>
Официальный адрес загрузки всех остальных версий:archive.apache.org/Day 3/VELO Times…
Для Velocity1.7 требуется jdk1.4 или выше. Адрес официального сайта:velocity.apache.org/engine/1.7/
1.7 адрес документа API:tool.OSCHINA.net/API doc S/API…
Быстрый старт
Example2.java
import java.io.StringWriter;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.VelocityContext;
public class Example2
{
public static void main( String args[] )
{
/* 首先,初始化运行时引擎,使用默认的配置 */
Velocity.init();
/* 创建Context对象,然后把数据放进去 */
VelocityContext context = new VelocityContext();
context.put("name", "Velocity");
context.put("project", "Jakarta");
/* 渲染模板 */
StringWriter w = new StringWriter();
Velocity.mergeTemplate("testtemplate.vm", context, w );
System.out.println(" template : " + w );
/* 渲染字符串 */
String s = "We are using $project $name to render this.";
w = new StringWriter();
Velocity.evaluate( context, w, "mystring", s );
System.out.println(" string : " + w );
}
}
testtemplate.vm
Hi! This $name from the $project project.
Суммировать
В первую очередь нужно еще создать контекст и поместить нужные данные.
затем объединить содержимое
Кодирование Java для Velocity
Следующее воспроизводится из:блог woowowoo.cn on.com/FS Джон паникует…Толстяк Джон
Шаблоны взаимодействуют с хост-средой
Шаблон относится к шаблону Velocity, написанному на VTL, а среда хоста относится к вызывающей части кода 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");
Обратите внимание, что тип данных значения в паре ключ-значение
Целое, длинноеТипы в штучной упаковке для простых типов данных, таких как
Тип строки;
Подкласс объекта;
Тип массива Object[], поскольку Velocity 1.6 обрабатывает типы массивов как типы java.util.List, поэтому в шаблоне можно вызывать переменные методы size() , get(intindex) и isEmpty();
подкласс java.util.Collection;
подкласс java.util.Map;
объект java.util.Iterator;
java.util. Объект перечисления.
Кроме того, мы также можем назначить статический класс объекту контекста, например статический класс 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 context1 = new VelocityContext();
context1.put("name","Velocity");
context1.put("project", "Jakarta");
context1.put("duplicate", "I am in context1");
VelocityContext context2 = new VelocityContext( context1 );
context2.put("lang", "Java" );
context2.put("duplicate", "I am in context2");
template.merge( context2, writer );
Так называемая цепочка контекста механизма предназначена для назначения исходного объекта контекста вновь созданному объекту контекста, чтобы добиться повторного использования пар ключ-значение в контексте. Конкретный код выглядит следующим образом:
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
То есть, когда текущий объект контекста не имеет пары ключ-значение, запрашивается, имеет ли объект цепочки контекста пару ключ-значение, и возвращается, если есть, и продолжает поиск других объектов контекста в цепочке до тех пор, пока найдена пара ключ-значение или пройдены все цепочки в объекте контекста.
Но помимо методов put и get экземпляры VelocityContext также имеют методы remove, getKeys, containsKey, как они себя ведут? Давайте посмотрим на исходный код ниже!
Часть кода Java, задействованная на официальном сайте
пользовательские свойства
/opt/templates
...
import java.util.Properties;
...
public static void main( String args[] )
{
/* 首先,我们还是初始化运行时引擎 */
Properties p = new Properties();
p.setProperty("file.resource.loader.path", "/opt/templates");
Velocity.init( p );
...
Хотя Velocity позволяет создавать собственные классы контейнеров для удовлетворения конкретных потребностей и технологий (например, контейнер с прямым доступом к серверу LDAP), базовый класс реализации под названием VelocityContext был предоставлен вам как часть дистрибутива.
VelocityContext подходит для всех общих нужд, поэтому мы настоятельно рекомендуем вам использовать VelocityContext в качестве контейнера. Только в особых случаях и для расширенных приложений вам необходимо расширять или создавать собственную реализацию контейнера.
поддержка объектов обхода for и foreach()
Velocity поддерживает несколько типов коллекций с помощью оператора foreach() в VTL:
Object []
Массив простых объектов Если класс предоставляет интерфейс итератора, Velocity автоматически перенесет ваш массив
Теперь Velocity позволяет разработчикам шаблонов рассматривать массивы как связанные списки фиксированной длины (это было в Velocity 1.6).
java.util.Collection
Velocity возвращает итератор для использования в цикле через метод iterator().
java.util.Map
Velocity возвращает интерфейс Collection через метод values() интерфейса, для которого вызывается метод iterator() для извлечения итератора для цикла.
java.util.Iterator
В настоящее время поддерживается только временно, итераторы не могут быть сброшены
Если неинициализированный итератор помещен в контейнер и используется в нескольких операторах foreach(), если первый foreach() завершится ошибкой, все последующие будут заблокированы, поскольку итератор не будет перезапущен.
java.util.Enumeration
то же, что java.util.Iterator
Для Iterator и Enumeration рекомендуется помещать их в контейнер только в крайнем случае, а также следует максимально позволить Velocity найти подходящий и повторно используемый интерфейс итерации.
Vector v = new Vector();
v.addElement("Hello");
v.addElement("There");
context.put("words", v.iterator() );//不推荐
context.put("words", v );
Поддержка статических классов
context.put("Math", Math.class);
Таким образом, вы можете вызвать любой общедоступный статический метод в java.lang.Math со ссылкой $Math в шаблоне.
Такой класс, как java.lang.Math, не предоставляет общедоступных конструкторов, но содержит полезные статические методы.
Сервлет использует скорость
Настройте скорость в web.xml
speed.apache.org/tools/… но даже…
<!-- Define Velocity template handler -->
<servlet>
<servlet-name>velocity</servlet-name>
<servlet-class>
org.apache.velocity.tools.view.VelocityViewServlet
</servlet-class>
<!--
Unless you plan to put your tools.xml and velocity.properties
under different folders or give them different names, then these
two init-params are unnecessary. The
VelocityViewServlet will automatically look for these files in
the following locations.
-->
<init-param>
<param-name>org.apache.velocity.toolbox</param-name>
<param-value>/WEB-INF/tools.xml</param-value>
</init-param>
<init-param>
<param-name>org.apache.velocity.properties</param-name>
<param-value>/WEB-INF/velocity.properties</param-value>
</init-param>
</servlet>
<!-- Map *.vm files to Velocity -->
<servlet-mapping>
<servlet-name>velocity</servlet-name>
<url-pattern>*.vm</url-pattern>
</servlet-mapping>
tools.xml подобен определению набора инструментов со многими инструментами, такими как «гаечный ключ».
Конкретный пример: попросите нашего друга Джона взять наш «гаечный ключ» из настоящего ящика с инструментами. Джону просто нужно знать, какой ключ нам нужен. Ему не нужно знать, что делает ключ или что мы собираемся делать.
Velocity Toolbox работает так же, как и в приведенном выше примере, нам нужно только указать необходимые инструменты, а затем Velocity Engine может использовать любые общедоступные методы, определенные в Toolbox Tool.xml в шаблоне vm, для обработки остальных.
PipeWrench.java
public class PipeWrench {
public String getSize() {
return "Large Pipe Wrench!";
}
}
tools.xml
<?xml version="1.0"?>
<tools>
<toolbox scope="application">
<tool key="wrench" class="PipeWrench"/>
</toolbox>
</tools>
В шаблоне .vm вы можете использовать:
$wrench.size
.
Шаблон виртуальной машины
Официальное руководство по ВТЛ:
скорость.apache.org/engine/2.2/…
VTL: язык шаблонов скорости
Следующее воспроизводится из:блог woowowoo.cn on.com/FS Джон паникует…Толстяк Джон
Примечания
1. Строковые комментарии
## 行注释内容
2. Блокировать комментарии
#*块注释内容1块注释内容2*#
3. Примечания к документации
#**文档注释内容1文档注释内容2*#
Ни комментарии блока, ни комментарии документа не выводятся в окончательный результат, но вызывают появление окончательного результата.пустая строка. Это не так со строчными комментариями.
прямой вывод
То есть контент, который не будет анализироваться движком.
#[[直接输出的内容1直接输出的内容2]]#
Цитировать
Оператор ссылки должен работать со свойствами в объекте контекста механизма.
С точки зрения грамматики она делится на обычную грамматику ($property) и обычную грамматику (${property}).
В приведенных выше двух способах записи в обычном режиме, когда в объекте контекста движка нет соответствующего свойства, окончательный результат будет напрямую выводить $property или ${property}, если нет, его нужно переписать как $!property и $!{свойство} .
1. Переменные (то есть свойства объекта контекста движка)
$变量名, 常规写法,若上下文中没有对应的变量,则输入字符串"$变量名"
${变量名}, 常规写法,若上下文中没有对应的变量,则输入字符串"${变量名}"
$!变量名, 常规写法,若上下文中没有对应的变量,则输入空字符串""
$!{变量名}, 常规写法,若上下文中没有对应的变量,则输入空字符串""
Состоит из букв, знаков подчеркивания (_), дефисов (-), цифр и начинается с буквы.
Целое, длинноеТипы в штучной упаковке для простых типов данных, таких как
Тип строки;
Подкласс объекта;
Тип массива Object[], поскольку Velocity 1.6 обрабатывает типы массивов как типы java.util.List, поэтому в шаблоне можно вызывать переменные методы size() , get(int index) и isEmpty() ;
подкласс java.util.Collection;
подкласс java.util.Map;
объект java.util.Iterator;
java.util. Объект перечисления.
2. Свойства (то есть свойства свойств объекта контекста движка)
$变量名.属性, 常规写法
${变量名.属性}, 正规写法
$!变量名.属性, 常规写法
$!{变量名.属性}, 正规写法
Правила поиска атрибутов:
В Velocity используется очень гибкий способ поиска свойств переменных:
// Если есть ссылка на $var.prop, Velocity преобразует реквизит, а затем попытается вызвать объект $var // Порядок морфинга и попытки следующий
$var.getprop()
$var.getProp()
$var.get("prop")
$var.isProp()
// Для $var.Prop тогда следующее
$var.getProp()
$var.getprop()
$var.get("Prop")
$var.isProp()
Поэтому при получении значения ключа объекта java.util.Map его можно сократить до $map.key , и Velocity автоматически преобразует его в $map.get("key") для поиска!
3. Метод (то есть метод свойств объекта контекста движка)
$变量名.方法([入参1[, 入参2]*]?), 常规写法
${变量名.方法([入参1[, 入参2]*]?)}, 正规写法
$!变量名.方法([入参1[, 入参2]*]?), 常规写法
$!{变量名.方法([入参1[, 入参2]*]?)}, 正规写法
Славный метод на самом деле является операцией вызова метода, фокусвозвращаемое значение,Входа такжепобочный эффектСитуация следующая:
Возвращаемое значение метода будет выведено в конечном результате
тип входных данных
$变量 或 $属性,数据类型参考第一小节;
范围操作符(如:[1..2]或[$arg1..$arg2]),将作为java.util.ArrayList处理
字典字面量(如:{a:"a",b:"b"}),将作为java.util.Map处理
数字字面量(如:1),将自动装箱或拆箱匹配方法定义中的int或Integer入参
побочный эффект
// 若操作如java.util.Map.put方法,则会修改Java代码部分中的Map对象键值对
$map.put("key", "new value")
инструкция
Директивы в основном используются для определения повторно используемых модулей, введения внешних ресурсов и управления потоком процессов. Инструкции начинаются с символа #.
#set: добавить свойства в объект контекста движка или изменить существующие свойства
Формат: #set($variable = value) , конкретный пример выглядит следующим образом:
#set($var1 = $other)
#set($var1.prop1 = $other)
#set($var = 1)
#set($var = true)
#set($var = [1,2])
#set($var = {a:"a", b:"b"})
#set($var = [1..3])
#set($var = [$arg1..$arg2])
#set($var = $var1.method())
#set($var = $arg1 + 1)
#set($var = "hello")
#set($var = "hello $var1") // 双引号可实现字符串拼接(coffeescript也是这样哦!),假设$var1为fsjohnhuang,则$var为hello fsjohnhuang
#set($var = 'hello $var1') // 单引号将不解析其中引用,假设$var1为fsjohnhuang,则$var为hello $var1
Области действия, очевидно, являются глобальными.
#if: условное суждение
Формат:
#if(判断条件)
.........
#elseif(判断条件)
.........
#else
.........
#end
Узнайте об условиях суждения на примерах:
#if($name) //$name不为false、null和undefined则视为true
$name
#elseif($job == "net") // ==和!=两边的变量将调用其toString(),并对比两者的返回值
Net工程师
#elseif($age <= 16) // 支持<=,>=,>,<逻辑运算符
未成年劳工
#elseif(!$married) // 支持!逻辑运算符
未婚
#elseif($age >= 35 && !$married) // 支持&&,||关系运算符
大龄未婚青年
#end
#форич: цикл
Формат:
#foreach($item in $items)
..........
#end
Областью видимости $item является тело цикла #foreach.
Типы данных $items: массивы Object[], [1..2], [1,2,3,4], {a:"a",b:"b"} и с общедоступным Iterator iterator() объект метода следующим образом:
java.util.Collection子类,Velocity会调用其iterator方法获取Iterator对象
java.util.Map子类,Velocity会调用value()获取Collection对象,然后调用调用其iterator方法获取Iterator对象
java.util.Iterator对象,直接将该Iterator对象添加到上下文对象中时,由于Iterator对象为只进不退的操作方式,因此无法被多个#foreach指令遍历
java.util.Enumeration对象,直接将该Enumeration对象添加到上下文对象中时,由于Iterator对象为只进不退的操作方式,因此无法被多个#foreach指令遍历
Встроенное свойство $foreach.count используется для указания номера текущего цикла, начиная с 0. Максимальное количество циклов может быть ограничено директивой элемента конфигурации foreach.maxloops, значение по умолчанию равно -1 (неограниченно).
Пример. Разница между использованием вектора и итератора:
шаблон:
#macro(show)
#foreach($letter in $letters)
$letter
#end
#end
#show()
Java-код:
Vector<String> v = new Vector<String>();
v.add("a");
v.add("b");
VelocityContext ctx = new VelocityContext();
ctx.put("letters",v);
Template t = Velocity.getTemplate("模板路径");
StringWriter sw = new StringWriter();
t.merge(ctx,sw);
System.out.println(sw.toString());
// 结果
// a
// b
// a
// b
ctx.put("letters",v.iterator());
// 结果
// a
//
#break: выйти из цикла
#foreach($item in $items)
#if($item == "over")
#break;
#end
$item
#end
#stop: прервать операцию парсинга шаблона
#set($cmd="stop")
$cmd
#if($cmd == "stop")
#stop
#end
$cmd // 该语句将不执行
#include импорт внешних ресурсов
(Импортированные ресурсы не анализируются движком)
Формат: #include(ресурс[другойресурс]*)
ресурс, другой ресурс может бытьстрока в одинарных или двойных кавычках, так же может быть$переменная, содержимое — это путь к внешнему ресурсу. Обратите внимание, что если это относительный путь, в качестве системы отсчета используется путь загрузки загрузчика файлов, настроенный движком, а не путь к текущему файлу шаблона.
#parseПредставьте внешние ресурсы
(Импортированные ресурсы будут проанализированы движком)
Формат: #parse(ресурс)
ресурс может бытьстрока в одинарных или двойных кавычках, так же может быть$переменная, содержимое — это путь к внешнему ресурсу. Обратите внимание, что если это относительный путь, в качестве системы отсчета используется путь загрузки загрузчика файлов, настроенный движком, а не путь к текущему файлу шаблона.
Поскольку директива #parse может вызвать проблему бесконечного рекурсивного введения, максимальное количество рекурсивных представлений может быть ограничено элементом конфигурации directive.parse.max.depth, а значение по умолчанию равно 10.
#macro: определить повторно используемый модуль (с параметрами)
Формат определения:
#macro(宏名 [$arg[ $arg]*]?)
.....
#end
Формат вызова:
#宏名([$arg[ $arg]]?)
Пример 1 -Когда определение и вызов находятся в том же файле шаблона, нет необходимости следовать правилу определить-перед использованием:
#log("What a happy day")
#macro(log $msg)
log message: $msg
#end
Пример 2 -При определении и вызове различных файлов шаблонов вам необходимо следовать правилам сначала определить, а затем использовать:
## 模板文件macro.vm#macro(log $msg)
log message: $msg
#end
## 模板文件main.vm
#parse("macro.vm")
#log("What a happy day")
Анализ принципа: Движок Velocity создаст синтаксическое дерево на основе шаблона и буферизует его перед выполнением.Поэтому, когда определение макроса и вызов находятся в одном файле шаблона, когда макрос вызывается, он был распознан и инициализирован движком (аналог хоста в js).
Если определение и вызов расположены в разных файлах шаблона, поскольку #parse выполняется, когда движок анализирует файл шаблона для импорта внешних ресурсов и инициализации в нем определений макросов, необходимо соблюдать правила определения перед использованием.
Мы можем настроить глобальную библиотеку макросов следующим образом:
Properties props = new Properties();
// velocimacro.library的值为模板文件的路径,多个路径时用逗号分隔
// velocimacro.library的默认值为VM_global_library.vm
props.setProperty("velocimacro.library", "global_macro1.vm,global_macro2.vm");
VelocityEngine ve = new VelocityEngine(props);
Кроме того, у #macro есть еще один способ передачи параметров — $!bodyContent
#macro(say)
$!bodyContent
#end
#@say()Hello World#end
// 结果为Hello World
#define: определить повторно используемый модуль (без параметров)
#define($log)
hello log!
#end
$log
Его можно рассматривать как слабую версию #macro, вообще не используемую, просто разбираюсь.
#evaluate: динамическая оценка
Пример:
#set($name = "over")
#evalute("#if($name=='over')over#{else}not over#end") // 输出over
Вообще не надо, просто пойми.
Побеги
Экранирование $ и # с помощью \ заставляет синтаксический анализатор не анализировать их.
#set($test='hello')
$test ## 结果:hello
\$test ## 结果:$test
\\$test ## 结果:\hello
\\\$test ## 结果:\$test
$!test ## 结果:hello
$\!test ## 结果:$!test
$\\!test ## 结果:$\!test
$\\\!test ## 结果:$\\!test
Практика шаблонов
Содержание цитируется из:блог woowowoo.cn on.com/FS Джон паникует…толстый мальчик
Результатом примера является создание такой HTML-формы:
<form action="./submit">
<div>
<label for="title">标题:</label>
<input type="text" id="title" name="title"/>
</div>
<div>
<label for="brief">摘要:</label>
<input type="text" id="brief" name="brief"/>
</div>
<div>
<label for="sex">性别:</label>
<select id="sex" name="sex">
<option value="0">男</option>
<option value="1">女</option>
</select>
</div>
<div>
<label for="job">职业:</label>
<select id="job" name="job">
<option value="0">Java工程师</option>
<option value="1">Net工程师</option>
</select>
</div>
</form>
Внедрение зависимостей — speed-1.7-dep.jar
Файл шаблона frm.vm
##表单模板
##@author fsjohnhuang
##@version 1.0
## 引入外部模板文件
#parse('macro.vm')
## 主逻辑
<form action="$action">
#foreach($input in $inputs)
#input($input.title $input.id)
#end
#foreach($select in $selects)
#select($select.title $select.id $select.items)
#end
</form>
Файл шаблона macro.vm
## 生成input表单元素区域的宏
#macro(input $title $id)
<div>
<label for="$id">$title</label>
<input type="text" id="$id" name="$id"/>
</div>
#end
## 生成select表单元素区域的宏
#macro(select $title $id $items)
<div>
<label for="$id">$title</label>
<select id="$id" name="$id">
## VTL指令紧贴左侧才能确保结果的排版正常(不会有多余空格)
#foreach($key in $items.keySet())
<option value="$key">$items.get($key)</option>
#end
</select>
</div>
#end
Java-код
public static void main(String[] args) {
// 初始化模板引擎
Properties props = new Properties();
props.put("file.resource.loader.path", ".\\vm");
VelocityEngine ve = new VelocityEngine(props);
// 配置引擎上下文对象
VelocityContext ctx = new VelocityContext();
ctx.put("action", "./submit");
ArrayList<HashMap<String, String>> inputs = new ArrayList<HashMap<String,String>>();
HashMap<String, String> input1 = new HashMap<String, String>();
input1.put("id", "title");
input1.put("title", "标题:");
inputs.add(input1);
HashMap<String, String> input2 = new HashMap<String, String>();
input2.put("id", "brief");
input2.put("title", "摘要:");
inputs.add(input2);
ctx.put("inputs", inputs);
ArrayList<HashMap<String, Object>> selects = new ArrayList<HashMap<String,Object>>();
HashMap<String, Object> select1 = new HashMap<String, Object>();
selects.add(select1);
select1.put("id", "sex");
select1.put("title", "性别:");
HashMap<Integer, String> kv1 = new HashMap<Integer, String>();
kv1.put(0, "男");
kv1.put(1, "女");
select1.put("items", kv1);
HashMap<String, Object> select2 = new HashMap<String, Object>();
selects.add(select2);
select2.put("id", "job");
select2.put("title", "职业:");
HashMap<Integer, String> kv2 = new HashMap<Integer, String>();
kv2.put(0, "Java工程师");
kv2.put(1, "Net工程师");
select2.put("items", kv2);
ctx.put("selects", selects);
// 加载模板文件
Template t = ve.getTemplate("test.vm");
StringWriter sw = new StringWriter();
// 渲染模板
t.merge(ctx, sw);
System.out.print(sw.toString());
}
Справочная статья
Оригинальный адрес руководства по разработке:
speed.apache.org/engine/… в канун…
Оригинальный адрес руководства пользователя:
speed.apache.org/engine/… в канун…
Адрес руководства по разработке китайского перевода:
Толстяк Джон отлично веб-адрес:
блог woowowoo.cn on.com/FS Джон паникует…