Apache Texen 在 Ubuntu 22.04 集成使用指南
在 Ubuntu 22.04 从零安装 JDK 17 与 Ant、下载 Texen 1.0 依赖 jar,跑通行星 HTML 与实体代码(POJO+SQL)两个生成示例,并沉淀编码与目录创建等实测注意事项。
Apache Texen 在 Ubuntu 22.04 集成使用指南
目标:在 Ubuntu 22.04 服务器上从零搭建 Apache Texen 1.0 的文本生成环境:安装 JDK 17 与 Ant、从 Maven Central 下载依赖 jar、编写控制模板与工人模板,跑通「行星 HTML 页面」与「实体代码生成(POJO + 建表 SQL)」两个完整示例,并沉淀编码、目录创建等实测坑点。全部命令与回显已在 Ubuntu 22.04.5 LTS 实测通过。
一、环境信息
本文实测环境与组件版本:
- 操作系统:Ubuntu 22.04.5 LTS(x86_64)
- JDK:OpenJDK 17.0.20.1(apt 包 openjdk-17-jdk)
- 构建工具:Apache Ant 1.10.12(apt 包 ant,包版本 1.10.12-1)
- 下载工具:GNU Wget 1.21.2
- 生成框架:Apache Texen 1.0(
org.apache.texen:texen:1.0,17159 字节) - 模板引擎:推荐组合 Velocity 1.7 + commons-collections 3.2.2 + commons-lang 2.6;对照组合 Velocity Engine 2.4.1 + commons-lang3 3.17.0 + slf4j-api 1.7.36(均含 commons-collections 3.2.2)
- 工作目录:
/root/texen-demo/
💡 技术拓展:Texen 内部固定使用 Velocity 作为渲染引擎(默认搭配 Velocity 1.7,实测环境亦如此),不提供引擎替换选项。「模板引擎」指把模板与数据上下文合并渲染成最终文本的组件,Java 生态常见对比——Velocity(
$obj/#foreach,简单直观)、FreeMarker(${obj}/<#list>,内建函数丰富)、Thymeleaf(原生 HTML 属性,Spring Boot 页面常用)、Mustache({{obj}},逻辑无关跨语言)。只想"裸用"Velocity 而不需要 Ant 驱动的多文件编排,可直接使用 Velocity Engine 本身(见《Apache Velocity 快速入门与集成示例》)。
二、前置条件
2.1 安装 JDK 17、Ant 与 wget
apt-get install -y openjdk-17-jdk ant wget
已安装状态下执行回显(实测,为三条安装命令各自回显的节选汇总,首次安装时会显示解包与配置过程):
openjdk-17-jdk is already the newest version (17.0.20.1+1-1~22.04).
ant is already the newest version (1.10.12-1).
wget is already the newest version (1.21.2-2ubuntu1.5).
0 upgraded, 0 newly installed, 0 to remove and 2 not upgraded.
版本验证(实测):
java -version && javac -version && ant -version && wget --version | head -1
openjdk version "17.0.20.1" 2026-08-18
OpenJDK Runtime Environment (build 17.0.20.1+1-1-22.04-Ubuntu)
OpenJDK 64-Bit Server VM (build 17.0.20.1+1-1-22.04-Ubuntu, mixed mode, sharing)
javac 17.0.20.1
Apache Ant(TM) version 1.10.12 compiled on January 17 1970
GNU Wget 1.21.2 built on linux-gnu.
2.2 建立工作目录
mkdir -p /root/texen-demo && cd /root/texen-demo && pwd
/root/texen-demo
三、依赖引入
Texen 不是服务,无安装包,集成方式就是把 4 个 jar 放进工程 lib 目录、在 build.xml 里声明类路径。本节先给推荐组合(Velocity 1.7 全兼容),再给对照组合(Velocity 2.4.1,仅用于兼容性评估)。
3.1 下载推荐组合的 4 个 jar
cd /root/texen-demo
mkdir -p lib
cd lib
wget https://repo1.maven.org/maven2/org/apache/texen/texen/1.0/texen-1.0.jar
wget https://repo1.maven.org/maven2/org/apache/velocity/velocity/1.7/velocity-1.7.jar
wget https://repo1.maven.org/maven2/commons-collections/commons-collections/3.2.2/commons-collections-3.2.2.jar
wget https://repo1.maven.org/maven2/commons-lang/commons-lang/2.6/commons-lang-2.6.jar
单独一条 wget 的回显(实测节选,其余三条输出格式相同):
--2026-10-16 03:23:58-- https://repo1.maven.org/maven2/org/apache/texen/texen/1.0/texen-1.0.jar
Resolving repo1.maven.org (repo1.maven.org)... 104.18.18.12, 104.18.19.12, 2606:4700::6812:120c, ...
Connecting to repo1.maven.org (repo1.maven.org)|104.18.18.12|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 17159 (17K) [application/java-archive]
Saving to: 'texen-1.0.jar'
0K .......... ...... 100% 1.35M=0.01s
2026-10-16 03:23:59 (1.35 MB/s) - 'texen-1.0.jar' saved [17159/17159]
下载完成后用 sha256 核对文件与完整性(实测值):
sha256sum /root/texen-demo/lib/*.jar
eeeae917917144a68a741d4c0dff66aa5c5c5fd85593ff217bced3fc8ca783b8 commons-collections-3.2.2.jar
50f11b09f877c294d56f24463f47d28f929cf5044f648661c0f0cfbae9a2f49c commons-lang-2.6.jar
d3ccc091d3d0efc5f18571063ff74d1f8e1b3cb519606437a7892c4026a47545 texen-1.0.jar
ec92dae810034f4b46dbb16ef4364a4013b0efb24a8c5dd67435cae46a290d8e velocity-1.7.jar
四个文件大小分别为 17159、449505、588337、284220 字节(texen、velocity、commons-collections、commons-lang)。
3.2 下载对照组合(Velocity Engine 2.4.1)
如需评估升级到 Velocity 2.x 的可行性,另备一套 jar(放在独立工程 lib 下均可):
wget https://repo1.maven.org/maven2/org/apache/velocity/velocity-engine-core/2.4.1/velocity-engine-core-2.4.1.jar
wget https://repo1.maven.org/maven2/org/apache/commons/commons-lang3/3.17.0/commons-lang3-3.17.0.jar
wget https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar
对照组合完整 jar 清单(实测):commons-collections-3.2.2.jar、commons-lang3-3.17.0.jar、slf4j-api-1.7.36.jar、texen-1.0.jar、velocity-engine-core-2.4.1.jar。
3.3 依赖矩阵实测结论
| 组合 | 结果 | 说明 |
|---|---|---|
| texen 1.0 + velocity 1.7 + commons-collections 3.2.2 + commons-lang 2.6 | 全功能可用 | 推荐组合,本文示例默认使用 |
| texen 1.0 + velocity-engine-core 2.4.1 + commons-lang3 + slf4j-api | 部分可用 | 不用 contextProperties 可跑通;$strings 仅剩 4 个 formatFileString 静态方法 |
| texen 1.0 + velocity-engine-core 2.4.1 + contextProperties 属性 | 必然失败 | 触发 NoSuchMethodError(见 5.3 节实测) |
💡 技术拓展:JVM 项目的依赖引入方式不止"手工下 jar"一种——手工 jar + Ant(wget 放入 lib、build.xml 声明路径,适合 Ant 工程与离线环境,本文采用);Maven(pom.xml 声明 org.apache.texen:texen:1.0,可经 maven-antrun 桥接);Gradle(dependencies 声明同一坐标)。apt 无 Texen 系统包。Texen 的运行入口是 Ant 任务,故本文采用手工 jar + Ant 的原生方式。
四、核心 API/配置
4.1 注册 TexenTask
每个 build.xml 需要先声明类路径并注册任务:<path id="texen.classpath"> 内用 <fileset dir="lib" includes="*.jar"/> 把 3.1 节下载的全部 jar 纳入类路径;再用 <taskdef name="texen" classname="org.apache.texen.ant.TexenTask" classpathref="texen.classpath"/> 把 TexenTask 注册为 <texen> 任务名。完整写法见 5.1 节 build.xml(可直接复制)。
4.2 <texen> 任务属性速览
四个必填属性:controlTemplate(控制模板文件名)、templatePath(模板目录,useClasspath=false 时必填)、outputDirectory(产物目录)、outputFile(报告文件名)。常用可选项:inputEncoding/outputEncoding(字符集,建议显式设为 UTF-8)、contextProperties(属性文件注入)、useClasspath(模板改由 classpath 加载)。全部 11 个属性的逐项实测行为(含缺失报错原文)见《Apache Texen 常用 CLI 命令与工具详解》。
4.3 控制模板驱动模型
控制模板里最关键的一个调用:$generator.parse("HtmlTemplate.vm", $outputFile, "planet", $planet)——第 1 参是工人模板名(相对 templatePath 或 classpath),第 2 参是输出文件名(相对 outputDirectory),第 3/4 参把"变量名=变量值"注入工人模板上下文(工人模板内用 $planet 访问)。两参数形态 $generator.parse("about.txt.vm", "about.txt") 也存在:渲染结果直接写入输出文件。控制模板自身渲染的输出不会丢弃,而是写入 outputFile 指定的报告文件;工人模板上下文继承控制模板的全部变量(实测有效)。
4.4 contextProperties 属性注入
在 build.xml 中加 contextProperties="build.properties" 后,属性文件的键值会注入模板上下文。实测三类自动转换:数字串转 Integer(maxDepth = 3)、true/false 转 Boolean(verbose = true)、键名以 file.contents 结尾时把整个文件内容作为字符串注入且键名去掉该后缀(license.file.contents = LICENSE.txt → $license,实测 license 文本出现在每个生成文件的头部)。
五、集成示例
三个示例均放在 /root/texen-demo/ 下,可独立执行;示例一、二使用推荐组合(lib 下 4 个 jar)。每个示例给出全部文件内容,逐字可复现。
5.1 示例一:行星 HTML 页面生成
目标:一个控制模板循环 3 个行星名,调用工人模板生成 3 个 HTML 页面。工程目录 /root/texen-demo/v17-html/(lib/ 放 3.1 节 4 个 jar,templates/ 放两个模板),以下为全部文件内容。
build.xml(完整文件):
<?xml version="1.0" encoding="UTF-8"?>
<project name="HtmlGenerator" default="main" basedir=".">
<description>Apache Texen 官方示例:行星 HTML 页面生成器(Velocity 1.7)</description>
<!-- Texen 运行所需 jar:texen-1.0.jar + velocity-1.7.jar + commons-collections-3.2.2.jar + commons-lang-2.6.jar -->
<path id="texen.classpath">
<fileset dir="lib" includes="*.jar"/>
</path>
<!-- 注册 TexenTask -->
<taskdef name="texen" classname="org.apache.texen.ant.TexenTask" classpathref="texen.classpath"/>
<target name="main" description="生成 Earth/Mars/Venus 三个 HTML 页面">
<echo message="+------------------------------------------+"/>
<echo message="| Generating HTML pages! |"/>
<echo message="+------------------------------------------+"/>
<texen
controlTemplate="Control.vm"
outputDirectory="output"
templatePath="templates"
outputFile="generation.report"/>
</target>
<target name="clean" description="清空 output 目录">
<delete dir="output"/>
</target>
</project>
templates/Control.vm(控制模板,完整文件):
#*
* Control.vm —— 控制模板:驱动整个生成过程。
* 遍历行星列表,逐个调用 HtmlTemplate.vm 生成 HTML 页面。
*#
#set ($Planets = ["Earth", "Mars", "Venus"])
#foreach ($planet in $Planets)
#set ($outputFile = $strings.concat([$planet, ".html"]))
$generator.parse("HtmlTemplate.vm", $outputFile, "planet", $planet)
#end
templates/HtmlTemplate.vm(工人模板,完整文件):
#*
* HtmlTemplate.vm —— 工人模板:由控制模板调用,产出单个 HTML 页面。
*#
#set ($bgcolor = "#ffffff")
<html>
<head>
<title>
Everything you wanted to know about $planet!
</title>
</head>
<body bgcolor="$bgcolor">
$planet is a great place to live!
</body>
</html>
执行生成(实测):
cd /root/texen-demo/v17-html && ant main
回显(实测节选,3 行 [echo] 横幅略):
Buildfile: /root/texen-demo/v17-html/build.xml
main:
[texen] templates
[texen] Generating to file /root/texen-demo/v17-html/output/generation.report
BUILD SUCCESSFUL
Total time: 0 seconds
核对产物(实测):
ls output/ && cat output/Earth.html
Earth.html
Mars.html
Venus.html
generation.report
<html>
<head>
<title>
Everything you wanted to know about Earth!
</title>
</head>
(后略,Mars.html/Venus.html 结构相同,仅行星名替换)
三个 HTML 已生成;generation.report 仅 4 字节(控制模板只做编排,报告为 4 个空行,实测 cat -A 确认),报告文件行为详见 6.3 节。
5.2 示例二:实体代码生成(POJO + 建表 SQL)
目标:按内置实体清单批量生成 Java POJO 与建表 SQL,并演示 contextProperties、$strings 工具与 $files.mkdir 建目录。工程目录 /root/texen-demo/v17-model-utf8/(目录名带 -utf8 后缀表示显式配置 UTF-8 编码;lib/ 放 3.1 节 4 个 jar,templates/ 放 4 个模板,根目录放 build.properties 与 LICENSE.txt)。
build.xml(完整文件):
<?xml version="1.0" encoding="UTF-8"?>
<project name="EntityGeneratorUtf8" default="main" basedir=".">
<description>Apache Texen 实体代码生成示例:POJO + 建表 SQL(Velocity 1.7,UTF-8 编码版)</description>
<path id="texen.classpath">
<fileset dir="lib" includes="*.jar"/>
</path>
<taskdef name="texen" classname="org.apache.texen.ant.TexenTask" classpathref="texen.classpath"/>
<target name="main" description="按实体模型生成 POJO、建表 SQL 与 about.txt(UTF-8 编码,logFile 记录引擎日志)">
<texen
controlTemplate="Control.vm"
outputDirectory="output"
templatePath="templates"
outputFile="generation.report"
inputEncoding="UTF-8"
outputEncoding="UTF-8"
logFile="texen.log"
contextProperties="build.properties"/>
</target>
<target name="clean" description="清空 output 目录">
<delete dir="output"/>
<delete file="texen.log"/>
</target>
</project>
⚠️ 注意:
inputEncoding/outputEncoding两个属性不能省。若去掉它们再跑同一工程,中文模板与产物会变成问号乱码(对照实测回显见 6.1 节)。logFile属性按字面含义应记录引擎日志,但实测并不产生文件(见 6.4 节)。
build.properties(完整文件):
# 实体生成器全局配置(TexenTask 的 contextProperties 指向本文件)
# 包名:模板里以 $appPkg 引用
appPkg = com.quzuo.demo
# 数字串属性:Texen 会转成 Integer 再放入上下文
maxDepth = 3
# true/false 属性:Texen 会转成 Boolean 再放入上下文
verbose = true
# file.contents 特殊用法:把 LICENSE.txt 整个文件内容作为 $license 注入上下文
license.file.contents = LICENSE.txt
LICENSE.txt(完整文件):
Copyright 2026 quzuo.net Demo. Licensed under the Apache License, Version 2.0.
本文件内容会通过 license.file.contents 属性注入模板上下文($license)。
templates/Control.vm(完整文件):
#*
* Control.vm —— 控制模板:驱动 POJO 与建表 SQL 的批量生成。
* $appPkg / $maxDepth / $verbose / $license 来自 contextProperties(build.properties)。
*#
#set ($pkgPath = $strings.getPackageAsPath($appPkg))
## Texen 不会自动创建嵌套输出目录:$files.mkdir 相对进程启动目录生效,
## 因此路径要带上 output/ 前缀(与 build.xml 的 outputDirectory 对应)
$files.mkdir("output/${pkgPath}")
$files.mkdir("output/sql")
#set ($entities = [
{"name": "user", "table": "t_user", "columns": ["id:bigint", "name:varchar", "email:varchar", "created_at:datetime"]},
{"name": "order_item", "table": "t_order_item", "columns": ["id:bigint", "user_id:bigint", "amount:decimal", "status:integer"]}
])
#foreach ($e in $entities)
#set ($className = $strings.removeAndHump($e.name))
## 生成 Java POJO 到 output/com/quzuo/demo/ 下
#set ($outputFile = "${pkgPath}${className}.java")
$generator.parse("JavaClass.vm", $outputFile, "entity", $e)
## 生成建表 SQL 到 output/sql/ 下
#set ($outputFile = "sql/${className}.sql")
$generator.parse("Sql.vm", $outputFile, "entity", $e)
#end
## 两参数形态的 $generator.parse:模板渲染结果直接写入指定文件
$generator.parse("about.txt.vm", "about.txt")
templates/JavaClass.vm(完整文件):
#*
* JavaClass.vm —— 实体 POJO 模板。
* $entity 由控制模板通过 $generator.parse 的第 3/4 参数注入。
*#
#set ($fieldTypes = {"bigint": "Long", "varchar": "String", "datetime": "LocalDateTime", "decimal": "java.math.BigDecimal", "integer": "Integer"})
$license
package $appPkg;
import java.time.LocalDateTime;
/**
* $entity.name 对应实体类,表名:$entity.table。
* 由 Apache Texen 自动生成(生成时间:$now),请勿手工修改。
*/
public class $className {
#foreach ($col in $entity.columns)
#set ($parts = $strings.split($col, ":"))
#set ($fieldName = $parts[0])
#set ($fieldType = $fieldTypes.get($parts[1]))
/** $parts[1] 类型字段 */
private $fieldType $fieldName;
#end
#foreach ($col in $entity.columns)
#set ($parts = $strings.split($col, ":"))
#set ($fieldName = $parts[0])
#set ($fieldType = $fieldTypes.get($parts[1]))
#set ($capName = $strings.capitalizeFirstLetter($fieldName))
public $fieldType get$capName() {
return $fieldName;
}
public void set$capName($fieldType $fieldName) {
this.$fieldName = $fieldName;
}
#end
}
/* 生成参数演示:maxDepth=$maxDepth(属性值数字串被转成 Integer),verbose=$verbose(属性值 true/false 被转成 Boolean) */
templates/Sql.vm(完整文件):
#*
* Sql.vm —— 建表 SQL 模板。
* 注意:#set/#if/#end 所在行行尾的换行会被 Velocity 吞掉,
* 因此每行 SQL 先拼到 $line 变量,再单独用 "$line" 引用输出。
*#
-- $entity.table 建表脚本(Apache Texen 生成于 $now)
CREATE TABLE $entity.table (
#foreach ($col in $entity.columns)
#set ($parts = $strings.split($col, ":"))
#set ($line = " $parts[0] $parts[1]")#if ($foreach.hasNext())#set ($line = "$line,")#end
$line
#end
);
templates/about.txt.vm(完整文件):
本目录由 Apache Texen 自动生成。
生成时间:$now
输出目录:$outputDirectory
包名:$appPkg
执行生成(实测):
cd /root/texen-demo/v17-model-utf8 && ant main
Buildfile: /root/texen-demo/v17-model-utf8/build.xml
main:
[texen] templates
[texen] Using contextProperties file: /root/texen-demo/v17-model-utf8/build.properties
[texen] Generating to file /root/texen-demo/v17-model-utf8/output/generation.report
BUILD SUCCESSFUL
Total time: 0 seconds
核对产物清单(实测,find output -type f | sort 输出):output/ 下共 6 个文件——about.txt、generation.report、com/quzuo/demo/ 下的 OrderItem.java 与 User.java、sql/ 下的 OrderItem.sql 与 User.sql,与 5.2 节目录设计完全对应。
再验证 logFile 属性的实际效果(实测:texen.log 并未生成,回显 ls: cannot access '/root/texen-demo/v17-model-utf8/texen.log': No such file or directory,classpath 加载方式下同样无日志文件,详见 6.4 节)。
生成物 User.java 输出节选(实测首尾,license 注入、包名、类注释均来自模板与 contextProperties):
Copyright 2026 quzuo.net Demo. Licensed under the Apache License, Version 2.0.
本文件内容会通过 license.file.contents 属性注入模板上下文($license)。
package com.quzuo.demo;
import java.time.LocalDateTime;
/**
* user 对应实体类,表名:t_user。
* 由 Apache Texen 自动生成(生成时间:Fri Oct 16 03:04:50 GMT 2026),请勿手工修改。
*/
public class User {
/** bigint 类型字段 */
private Long id;
/** varchar 类型字段 */
private String name;
(中段略)
}
/* 生成参数演示:maxDepth=3(属性值数字串被转成 Integer),verbose=true(属性值 true/false 被转成 Boolean) */
字段与 getter/setter 部分实测可见 private LocalDateTime created_at;(列名 created_at 直接成为字段名),访问器由模板循环产出。生成物 User.sql(实测全文,行格式正确):
-- t_user 建表脚本(Apache Texen 生成于 Fri Oct 16 03:04:50 GMT 2026)
CREATE TABLE t_user (
id bigint,
name varchar,
email varchar,
created_at datetime
);
生成物 about.txt 中 $now/$outputDirectory/$appPkg 均被正确替换(全文回显见 6.1 节修复后对照)。
5.3 示例三:Velocity Engine 2.4.1 兼容性对照
目标:验证 Texen 1.0 能否搭配当前活跃的 Velocity 2.4.1,给升级评估一个实测结论。把 3.2 节的 3 个 jar 换进 lib(或放独立工程 lib/),模板与 build.xml 与 5.1 完全相同,执行结果(实测输出节选,3 行 [echo] 横幅略):
Buildfile: /root/texen-demo/v241-html/build.xml
main:
[texen] templates
[texen] SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
[texen] Defaulting to no-operation (NOP) logger implementation
[texen] See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
[texen] Generating to file /root/texen-demo/v241-html/output/generation.report
BUILD SUCCESSFUL
Total time: 0 seconds
看似成功,产物却异常(实测):3 个 HTML 文件没有生成,output/ 下只剩报告:
ls output/
generation.report
根因:Velocity 2.4.1 删除了 org.apache.velocity.util.StringUtils 的大多数实例方法,控制模板里的 $strings.concat([$planet, ".html"]) 失效导致输出文件名变成空串,$generator.parse 两参形态把内容全部并入报告(generation.report 达 470 字节,实测可见 Earth/Mars/Venus 三个 HTML 的完整内容依次相连)。
更严重的兼容问题:在 2.4.1 下使用 contextProperties 属性会直接崩溃(实测):
BUILD FAILED
/root/texen-demo/v241-ctxprops/build.xml:19: java.lang.NoSuchMethodError: 'java.lang.String[] org.apache.velocity.util.StringUtils.split(java.lang.String, java.lang.String)'
at org.apache.texen.ant.TexenTask.setContextProperties(TexenTask.java:305)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
兼容改造后的可行写法(实测通过):控制模板不用 $strings,改用 VTL 原生拼接或 String 方法,且不使用 contextProperties 属性。执行回显(实测节选;原文中另有 3 行 SLF4J NOP 提示,属 2.4.1 无绑定器的正常输出,此处略去):
Buildfile: /root/texen-demo/v241-model/build.xml
main:
[texen] templates
[texen] Generating to file /root/texen-demo/v241-model/output/generation.report
BUILD SUCCESSFUL
Total time: 0 seconds
⚠️ 注意:2.4.1 下即使跑通,产物细节也有差异——建表 SQL 的行间会出现空行(Velocity 2.x 换行处理与 1.7 不同,实测 User.sql 每个列定义之间多一个空行,SQL 本身仍有效)。结论:Texen 1.0 建议固定搭配 Velocity 1.7 使用。
六、注意事项(全部来自实测,可直接对照处理)
6.1 中文乱码:三处来源与修复
乱码来源一:未设置 inputEncoding/outputEncoding。同一套模板与 build.xml 去掉两个编码属性后再跑(实测对照工程,产物 about.txt):
???????????? Apache Texen ???????????????
???????????????Fri Oct 16 03:03:01 GMT 2026
???????????????/root/texen-demo/v17-model/output
?????????com.quzuo.demo
把 inputEncoding="UTF-8" outputEncoding="UTF-8" 加回 build.xml 再跑(实测,即 5.2 工程的产物):
本目录由 Apache Texen 自动生成。
生成时间:Fri Oct 16 03:04:50 GMT 2026
输出目录:/root/texen-demo/v17-model-utf8/output
包名:com.quzuo.demo
乱码来源二:运行环境的 LANG 为空时,JVM 默认编码是 ASCII(file.encoding=ANSI_X3.4-1968),contextProperties 的 file.contents 读文件会注入乱码。实测 license 行字节对照:
=== LANG 为空时 license 行字节(EF BF BD 重复,即 U+FFFD 替换符)===
0000000 357 277 275 357 277 275 357 277 275 357 277 275 357 277 275 357
=== LANG=C.UTF-8 时 license 行 ===
本文件内容会通过 license.file.contents 属性注入模板上下文($license)。
修复方法(实测有效):执行 ant 前 export LANG=C.UTF-8。乱码来源三(ant 控制台回显自身乱码,-projecthelp 中文 description 变问号)同由 LANG 为空引起,此修复同样有效。
6.2 嵌套输出目录不会自动创建
Texen 只保证 outputDirectory 本身存在,模板若直接向 output/com/quzuo/demo/User.java 写文件会失败(实测,模板去掉 $files.mkdir 后复现):非 debug 模式报 Exception thrown by 'generator.parse'. For more information consult the velocity log, or invoke ant with the -debug flag.;加 -debug 可见根因 Caused by: java.io.FileNotFoundException: /root/texen-demo/v17-mkdir-repro/output/com/quzuo/demo/User.java (No such file or directory),出栈在 org.apache.texen.Generator.getWriter(完整实测栈见《Apache Texen 常用 CLI 命令与工具详解》4.4)。
解决方案(5.2 节 Control.vm 已采用):生成前先在控制模板里建目录:
$files.mkdir("output/${pkgPath}")
$files.mkdir("output/sql")
💡 说明:$files.mkdir 的路径相对 ant 进程的启动目录(执行 ant 命令所在目录)解析,不带
output/前缀时会建到工程根目录下,导致目录建了但产物路径仍对不上。其内部实现是 mkdirs(),多级目录一次可建。
6.3 控制模板渲染结果会写入报告文件
outputFile 指定的 generation.report 不是空占位:控制模板自身渲染的所有输出都会写进去。实测两种表现——控制模板只做编排时报告近乎为空(5.1 节 report 仅 4 字节);控制模板渲染失效时工人内容也会并入报告(5.3 节 v241-html 的 report 达 470 字节,含三个 HTML 全文);工人模板若用两参数 $generator.parse("X.vm") 形态调用(不给输出文件名),其渲染内容同样全部并入报告。编排型控制模板务必保证 #set/#foreach 行首行尾干净,避免杂质写进报告。
6.4 logFile 属性无实际效果
logFile="texen.log"(5.2 工程配置)执行后并未产生日志文件(实测回显见 5.2 节末尾);classpath 加载方式(logFile="texen-cp.log")同样无日志文件产生(实测见《Apache Texen 常用 CLI 命令与工具详解》4.11)。需要排障信息时用 ant -debug,不要依赖 logFile。
6.5 Velocity 1.7 的换行吞噬
VTL 中 #set/#if/#end 所在行行尾的换行会被 Velocity 1.7 吞掉。模板里直接书写多行 SQL 时,列定义会挤在一行。5.2 节 Sql.vm 的写法(每行先拼到 $line 变量、再单独一行输出 $line)是实测可用的规避模式;该问题在 Velocity 2.4.1 下方向相反(多出空行,见 5.3 节)。
七、参考链接
- Texen 官方文档(1.0):https://velocity.apache.org/texen/1.0/
- Maven Central 下载目录:https://repo1.maven.org/maven2/org/apache/texen/texen/1.0/
- Velocity 1.7 下载目录:https://repo1.maven.org/maven2/org/apache/velocity/velocity/1.7/
- Velocity Engine 2.4.1 下载目录:https://repo1.maven.org/maven2/org/apache/velocity/velocity-engine-core/2.4.1/
- Apache Velocity 官网:https://velocity.apache.org/
- 本文配套文档:《Apache Texen 介绍与选型指南》(选型与架构)、《Apache Texen 常用 CLI 命令与工具详解》(属性逐项实测)