Apache Turbine 快速入门与集成示例

以 Apache Turbine 7.0 完整工程讲解快速入门:archetype 生成、pom 与 web.xml 配置、自建 Screen 页面、Pipeline 与 Intake 实操、Security 登录体系与堆验证。

Apache TurbineApache Turbine2026/10/12

Apache Turbine 快速入门与集成示例

本文以 Apache Turbine 7.0 为例,演示从零创建完整工程、自建页面到核心概念实操的全过程,环境为 OpenJDK 17 + jakarta.servlet 6.1.0 + Maven 3.9.9 + MariaDB,全部回显来自真实服务器实测。

一、快速入门总览

步骤内容命令/文件
1生成工程骨架mvn archetype:generate
2初始化数据库systemctl/mysql + mvn integration-test
3启动应用mvn jetty:run
4验证默认页与登录curl
5自建 Screen 页面HelloTurbine.java + HelloTurbine.vm
6理解 Pipeline/Intake/Security配置文件与代码走读

前置:JDK 17、Maven ≥ 3.9.6、MariaDB 已安装并启动(安装步骤见本专栏安装指南两篇)。

二、创建完整工程

2.1 生成工程

cd /root
mvn archetype:generate \
  -DarchetypeGroupId=org.apache.turbine \
  -DarchetypeArtifactId=turbine-webapp \
  -DarchetypeVersion=7.0 \
  -DgroupId=com.example \
  -DartifactId=turbine-demo \
  -Dversion=1.0.0 \
  -Dpackage=com.example \
  -DinteractiveMode=false

实测回显(尾部):

[INFO] Project created from Archetype in dir: /root/turbine-demo
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

2.2 pom.xml 全文

archetype 生成的 pom.xml 如下(省略许可证头注释,其余为实测文件原文,属性 turbine.core 即 Turbine 版本):

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <parent>
        <groupId>org.apache.turbine</groupId>
        <artifactId>turbine-parent</artifactId>
        <version>14</version>
        <relativePath/>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>turbine-demo</artifactId>
    <version>1.0.0</version>
    <packaging>war</packaging>
    <name>My Turbine Web Application</name>
    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <resource>
                <targetPath>../torque/schema</targetPath>
                <filtering>true</filtering>
                <directory>src/main/torque-schema</directory>
                <includes><include>*.xml</include></includes>
            </resource>
        </resources>
        <testSourceDirectory>src/test/java</testSourceDirectory>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>${maven.surefire.version}</version>
                <configuration>
                    <skipTests>${skipTests}</skipTests>
                    <reuseForks>false</reuseForks>
                    <forkCount>1</forkCount>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${maven.compile.source}</source>
                    <target>${maven.compile.target}</target>
                    <encoding>${project.build.sourceEncoding}</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.torque</groupId>
                <artifactId>torque-maven-plugin</artifactId>
                <version>${torque.version}</version>
                <configuration/>
                <executions>
                    <execution>
                        <id>torque-om</id>
                        <phase>generate-sources</phase>
                        <goals><goal>generate</goal></goals>
                        <configuration>
                            <packaging>classpath</packaging>
                            <configPackage>org.apache.torque.templates.om</configPackage>
                            <sourceDir>${project.basedir}/src/main/torque-schema</sourceDir>
                            <options>
                                <torque.database>auto</torque.database>
                                <torque.om.package>com.example.om</torque.om.package>
                            </options>
                            <outputDirMap>
                                <modifiable>${project.build.sourceDirectory}</modifiable>
                            </outputDirMap>
                        </configuration>
                    </execution>
                    <execution>
                        <id>torque-sql-mysql</id>
                        <phase>generate-sources</phase>
                        <goals><goal>generate</goal></goals>
                        <configuration>
                            <packaging>classpath</packaging>
                            <configPackage>org.apache.torque.templates.sql</configPackage>
                            <sourceDir>${project.basedir}/src/main/torque-schema</sourceDir>
                            <defaultOutputDir>${project.build.directory}/generated-sql/torque/mysql</defaultOutputDir>
                            <defaultOutputDirUsage>none</defaultOutputDirUsage>
                            <options><torque.database>mysql</torque.database></options>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.4.0</version>
                <configuration>
                    <webResources>
                        <resource>
                            <directory>${project.basedir}/src/main/webapp/WEB-INF</directory>
                            <filtering>true</filtering>
                            <targetPath>WEB-INF</targetPath>
                            <includes><include>jetty-ee10-env.xml</include></includes>
                        </resource>
                        <resource>
                            <directory>${project.basedir}/src/main/webapp/META-INF</directory>
                            <filtering>true</filtering>
                            <targetPath>META-INF</targetPath>
                            <includes><include>context.xml</include></includes>
                        </resource>
                    </webResources>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>sql-maven-plugin</artifactId>
                <version>1.5</version>
                <configuration>
                    <driver>com.mysql.cj.jdbc.Driver</driver>
                    <url>${turbine_database_url}${turbine_database_name}?useSSL=false</url>
                    <username>db_user</username>
                    <password>db_password</password>
                    <onError>continue</onError>
                    <autocommit>true</autocommit>
                    <orderFile>descending</orderFile>
                </configuration>
                <executions>
                    <execution>
                        <id>create-db</id>
                        <phase>pre-integration-test</phase>
                        <goals><goal>execute</goal></goals>
                        <configuration>
                            <skip>false</skip>
                            <orderFile>ascending</orderFile>
                            <fileset>
                                <basedir>${project.build.directory}/generated-sql/torque/mysql</basedir>
                                <includes><include>*.sql</include></includes>
                            </fileset>
                        </configuration>
                    </execution>
                    <execution>
                        <id>create-data</id>
                        <phase>pre-integration-test</phase>
                        <goals><goal>execute</goal></goals>
                        <configuration>
                            <skip>false</skip>
                            <orderFile>ascending</orderFile>
                            <srcFiles>
                                <srcFile>${project.basedir}/src/main/data/sample-mysql-data/_application-data.sql</srcFile>
                                <srcFile>${project.basedir}/src/main/data/sample-mysql-data/_turbine-security-data.sql</srcFile>
                            </srcFiles>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.eclipse.jetty.ee10</groupId>
                <artifactId>jetty-ee10-maven-plugin</artifactId>
                <version>12.0.22</version>
                <configuration>
                    <scanIntervalSeconds>10</scanIntervalSeconds>
                    <httpConnector>
                        <port>8081</port>
                        <idleTimeout>60000</idleTimeout>
                    </httpConnector>
                    <webApp>
                        <jettyEnvXml>${project.build.directory}/${project.build.finalName}/WEB-INF/jetty-ee10-env.xml</jettyEnvXml>
                    </webApp>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-jakarta-web</artifactId>
            <version>${log4j2.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>${log4j2.version}</version>
        </dependency>
        <dependency>
            <groupId>jakarta.servlet</groupId>
            <artifactId>jakarta.servlet-api</artifactId>
            <version>6.1.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.torque</groupId>
            <artifactId>torque-runtime</artifactId>
            <version>${torque.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.turbine</groupId>
            <artifactId>turbine</artifactId>
            <version>${turbine.core}</version>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.commons</groupId>
                    <artifactId>commons-email</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.fulcrum</groupId>
            <artifactId>fulcrum-yaafi</artifactId>
            <version>${fulcrum.yaafi}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.fulcrum</groupId>
            <artifactId>fulcrum-intake</artifactId>
            <version>${fulcrum.intake}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.fulcrum</groupId>
            <artifactId>fulcrum-cache</artifactId>
            <version>${fulcrum.cache}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.fulcrum</groupId>
            <artifactId>fulcrum-security-memory</artifactId>
            <version>${fulcrum.security}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.fulcrum</groupId>
            <artifactId>fulcrum-security-torque</artifactId>
            <version>${fulcrum.security}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.fulcrum</groupId>
            <artifactId>fulcrum-security-api</artifactId>
            <version>${fulcrum.security}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.fulcrum</groupId>
            <artifactId>fulcrum-json-jackson2</artifactId>
            <version>${fulcrum.json}</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <properties>
        <maven.compile.source>17</maven.compile.source>
        <maven.compile.target>17</maven.compile.target>
        <maven.surefire.version>3.5.3</maven.surefire.version>
        <project.build.sourceEncoding>utf-8</project.build.sourceEncoding>
        <log4j2.version>2.25.1</log4j2.version>
        <mysql.version>8.3.0</mysql.version>
        <fulcrum.intake>4.0.0</fulcrum.intake>
        <fulcrum.parser>4.0.0</fulcrum.parser>
        <fulcrum.security>4.0.0</fulcrum.security>
        <fulcrum.yaafi>2.0.1</fulcrum.yaafi>
        <fulcrum.json>2.0.1</fulcrum.json>
        <fulcrum.cache>2.0.1</fulcrum.cache>
        <torque.version>7.0</torque.version>
        <turbine.core>7.0</turbine.core>
        <skipTests>true</skipTests>
        <turbine_database_url>jdbc:mysql://localhost:3306/</turbine_database_url>
        <turbine_database_name>turbine</turbine_database_name>
    </properties>
    <profiles>
        <profile>
            <id>mysql</id>
            <activation><activeByDefault>true</activeByDefault></activation>
            <properties>
                <driverClassName>com.mysql.cj.jdbc.Driver</driverClassName>
                <turbine_database_url>jdbc:mysql://localhost:3306/</turbine_database_url>
            </properties>
            <dependencies>
                <dependency>
                    <groupId>com.mysql</groupId>
                    <artifactId>mysql-connector-j</artifactId>
                    <version>${mysql.version}</version>
                    <scope>runtime</scope>
                </dependency>
            </dependencies>
        </profile>
    </profiles>
</project>

2.3 web.xml 全文

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                             http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1" metadata-complete="true">
    <servlet>
        <description>My Turbine Web Application</description>
        <servlet-name>Turbine</servlet-name>
        <servlet-class>org.apache.turbine.Turbine</servlet-class>
        <init-param>
            <param-name>applicationRoot</param-name>
            <param-value>webContext</param-value>
        </init-param>
        <init-param>
            <param-name>properties</param-name>
            <param-value>WEB-INF/conf/TurbineResources.properties</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Turbine</servlet-name>
        <url-pattern>/app/*</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>60</session-timeout>
        <cookie-config><max-age>3600</max-age></cookie-config>
    </session-config>
    <welcome-file-list>
        <welcome-file>app</welcome-file>
    </welcome-file-list>
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>templates</web-resource-name>
            <url-pattern>/templates/*</url-pattern>
        </web-resource-collection>
        <web-resource-collection>
            <web-resource-name>logs</web-resource-name>
            <url-pattern>/logs/*</url-pattern>
        </web-resource-collection>
        <auth-constraint />
    </security-constraint>
</web-app>

2.4 TurbineResources.properties 关键配置

实测工程中最核心的 8 项(完整解析见《Apache Turbine 配置参数详解》):

pipeline.default.descriptor = WEB-INF/conf/turbine-classic-pipeline.xml
module.packages=com.example.modules,com.example.flux.modules,org.apache.turbine.modules
template.homepage=Index.vm
template.login=Login.vm
template.error=Error.vm
action.login=LoginUserIntake
action.logout=LogoutUser
services.TemplateService.classname=org.apache.turbine.services.template.TurbineTemplateService

三、运行与验证

3.1 初始化数据库并启动

mysql -u root -e "CREATE DATABASE turbine CHARACTER SET utf8mb4;"
mysql -u root -e "CREATE USER 'db_user'@'localhost' IDENTIFIED BY 'db_password';"
mysql -u root -e "GRANT ALL PRIVILEGES ON turbine.* TO 'db_user'@'localhost';"
cd /root/turbine-demo
mvn integration-test
MAVEN_OPTS='-Xms256m -Xmx512m' nohup mvn jetty:run > /root/jetty.log 2>&1 &

启动就绪日志:

[INFO] Started ServerConnector@39124055{HTTP/1.1, (http/1.1)}{0.0.0.0:8081}
[INFO] Started oejs.Server@377d66f{STARTING}[12.0.22,sto=0] @56049ms

3.2 验证默认页与登录

curl -s http://localhost:8081/app | grep -oE '<title>[^<]*</title>'
<title>Sample Apache Turbine Application</title>

演示账号 admin / q1w2e3r4(种子数据改法见安装指南):

curl -s -c /tmp/ck.txt -d 'username=admin&password=q1w2e3r4' http://localhost:8081/app/action/LoginUser -o /dev/null -w '%{http_code}\n'
curl -s -b /tmp/ck.txt http://localhost:8081/app/template/Index.vm | grep -c Logout

实测依次返回 200 与 1(登录成功后导航栏出现 Flux 管理菜单与 Logout 链接)。

四、自建 Screen 与 Template 页面

4.1 Screen 类

新建 src/main/java/com/example/modules/screens/HelloTurbine.java(包名必须在 module.packages 列出的包下):

package com.example.modules.screens;

import java.util.Date;
import org.apache.turbine.modules.screens.VelocityScreen;
import org.apache.turbine.pipeline.PipelineData;
import org.apache.turbine.util.RunData;
import org.apache.velocity.context.Context;

public class HelloTurbine extends VelocityScreen
{
    @Override
    protected void doBuildTemplate(PipelineData data, Context context) throws Exception
    {
        RunData rundata = data.getRunData();
        context.put("visitor", rundata.getUser().getName());
        context.put("now", new Date().toString());
    }
}

注意:Turbine 7.0 的回调签名是 PipelineData(6.0 引入),不是老版本的 RunData;经 data.getRunData() 取回 RunData 后再取当前用户。

4.2 Velocity 模板

新建 src/main/webapp/templates/app/screens/HelloTurbine.vm(与 Screen 同名,模板服务按名字匹配):

<h2>Hello Turbine!</h2>
<p>当前登录用户:$visitor</p>
<p>服务器时间:$now</p>

4.3 编译并验证

mvn compile
MAVEN_OPTS='-Xms256m -Xmx512m' nohup mvn jetty:run > /root/jetty.log 2>&1 &
curl -s http://localhost:8081/app/template/HelloTurbine.vm | grep -E 'Hello Turbine|anon|服务器时间'

实测回显:

<h2>Hello Turbine!</h2>
<p>当前登录用户:anon</p>
<p>服务器时间:Mon Oct 12 12:18:15 GMT 2026</p>

未登录时 Turbine 自动以匿名用户 anon 渲染;登录后访问则显示登录名。

五、核心概念实操

5.1 Pipeline 与 Valve

Pipeline 是 Turbine 处理请求的责任链。实测工程的 WEB-INF/conf/turbine-classic-pipeline.xml 按序声明了 10 个 Valve:SetEncoding → DetermineAction → DetermineTarget → SessionTimeout → Login → SessionValidation → ACLCreation → ExecutePage → CleanUp → DetermineRedirectRequested。一个请求进入 /app/* 后依次穿过这些 Valve:先确定要执行的 Action,再确定目标模板,校验会话与登录,构建 ACL,最后由 ExecutePageValve 渲染页面。自定义横切逻辑(如审计、限流)实现 org.apache.turbine.pipeline.Valve 接口后插入该文件即可。

5.2 Screen / Action / Navigation

  • Screen 负责生成页面主体(第四章的 HelloTurbine 即最简 Screen),渲染顺序为 Screen 输出嵌入 Layout(Default.vm),Layout 中的导航片段来自 templates/app/navigations/Menu.vm。
  • Action 处理业务动作、不直接输出页面。实测工程 modules/actions/LoginUser.java 继承 org.apache.turbine.modules.actions.LoginUser,在 doPerform 中取 username 参数、拒绝匿名登录、调用安全服务认证后写入会话;表单提交的 eventSubmit_doPerform 按钮值触发事件方法(action.eventsubmit.needsvalue=false 时无需特定值)。
  • URL 规律:/app/template/<名字>.vm 走 Screen+模板渲染,/app/action/<动作名> 触发 Action 后重定向回模板。

5.3 Intake 表单校验

Intake 把表单校验规则集中到 WEB-INF/conf/intake.xml。实测 Login 组定义:

<group name="Login" key="login">
    <field name="Username" key="u" type="String">
        <rule name="required" value="true">username_required_msg</rule>
        <rule name="minLength" value="4">username_min_length_msg</rule>
    </field>
    <field name="Password" key="p" type="String">
        <rule name="required" value="true">password_msg</rule>
    </field>
</group>

模板用 $loginGroup.Username.Key 渲染输入框,实测页面上生成的控件名为 login_0u(组键_序号_字段键)。用 curl 携带这些参数提交即可完成 Intake 校验流程的登录:

curl -s -c /tmp/ik.txt -d 'login_0u=admin&login_0p=q1w2e3r4&eventSubmit_doPerform=1' \
  http://localhost:8081/app/action/LoginUserIntake/template/Login.vm -o /dev/null -w '%{http_code}\n'

实测回显:

200

5.4 Fulcrum Security 用户体系

Turbine 7.0 的用户/角色/权限由 Fulcrum Security 组件提供,数据落库为 TURBINE_USER、TURBINE_ROLE、TURBINE_GROUP、TURBINE_PERMISSION 及三张关联表(实测建表清单见第三章)。要点:

  • 用户模型:TurbineUserImpl,经 services.SecurityService.wrapper.class 包装为应用用户对象。
  • 认证:security.getAuthenticatedUser(username, password),匿名用户固定为 anon(种子数据中存在)。
  • 授权:登录后 ACL 由 DefaultACLCreationValve 构建,Flux 管理界面提供 user/role/group/permission 增删改查(实测以 admin 登录后导航栏出现 User List / User Roles / Add User 菜单)。
  • 密码:演示数据明文存储,生产启用 componentConfiguration.xml 中 <authenticator> 的加密算法。

六、JVM 堆验证

以 256–512MB 堆启动后,用 JDK 自带工具核对:

jps -v | grep -v Jps

实测回显:

7746 Launcher -Xms256m -Xmx512m -Dclassworlds.conf=/opt/maven/bin/m2.conf -Dmaven.home=/opt/maven -Dlibrary.jansi.path=/opt/maven/lib/jansi-native -Dmaven.multiModuleProjectDirectory=/root/turbine-demo
ps -ef | grep '[j]ava' | grep -oE '\-Xm[sx][0-9a-z]+'
-Xms256m
-Xmx512m

部署到独立 Tomcat 时改为在 /opt/tomcat/bin/setenv.sh 写 CATALINA_OPTS="-Xms256m -Xmx512m",验证目标进程名变为 Bootstrap。

七、常见问题

**Q1:**自建 Screen 访问报错或显示默认页? 三查:包名是否在 module.packages 中;类名与模板名是否一致;mvn compile 后是否重启了 mvn jetty:run(jetty:run 使用 target/classes 中的类)。

**Q2:**覆写 doBuildTemplate 编译报错 "method does not override"? Turbine 7.0 签名为 doBuildTemplate(PipelineData, Context),老教程中的 doBuildTemplate(RunData, Context) 已不适用(实测踩坑)。

**Q3:**模板中文乱码? 确认 input.encoding=UTF-8、services.VelocityService.default_encoding=UTF-8 与模板文件本身均为 UTF-8(实测工程默认即 UTF-8,无需修改)。

**Q4:**登录后菜单没出现 Flux 管理入口? 种子数据中 admin 需绑定角色与权限(TURBINE_USER_GROUP_ROLE 关联表);确认执行了 mvn integration-test 完整灌数,且用 admin 而非 user/anon 登录。

**Q5:**mvn integration-test 报数据库连接失败? 检查 MariaDB 已启动、turbine 库已创建、db_user 授权与 pom/sql-maven-plugin、jetty-ee10-env.xml 中的账号一致。

八、参考链接

  1. Turbine 7.0 官方文档:https://turbine.apache.org/turbine/turbine-7-0/
  2. Turbine 7.0 快速上手:https://turbine.apache.org/turbine/turbine-7-0/getting-started.html
  3. Turbine 7.0 Howto 文档:https://turbine.apache.org/turbine/turbine-7-0/howto/index.html
  4. Turbine 7.0 API 文档:https://turbine.apache.org/turbine/turbine-7-0/apidocs/index.html
  5. Maven Central 上的 turbine 7.0:https://central.sonatype.com/artifact/org.apache.turbine/turbine/7.0
  6. 官方代码仓库(turbine-core):https://github.com/apache/turbine-core
  7. 官方 archetype 仓库:https://github.com/apache/turbine-archetypes
  8. Fulcrum 组件列表:https://turbine.apache.org/fulcrum/