1. 概述

本文将介绍 ActiveWeb —— JavaLite 提供的全栈式 Web 框架。它为开发动态 Web 应用或 RESTful Web 服务提供了所需的一切功能。

2. 核心概念与原则

ActiveWeb 遵循约定优于配置的设计理念,这意味着:

  • 框架提供合理的默认配置
  • 无需繁琐的额外配置
  • 只需遵循预定义的命名规范(如类/方法/字段命名)

它还具备热重载能力,能自动重新编译并加载代码到运行容器(默认 Jetty)。对于依赖管理,它使用 Google Guice 作为 DI 框架(想深入了解 Guice 可参考官方文档)。

3. Maven 配置

首先添加核心依赖:

<dependency>
    <groupId>org.javalite</groupId>
    <artifactId>activeweb</artifactId>
    <version>1.15</version>
</dependency>

最新版本可在 Maven 中央仓库 查询

测试时需额外添加:

<dependency>
    <groupId>org.javalite</groupId>
    <artifactId>activeweb-testing</artifactId>
    <version>1.15</version>
    <scope>test</scope>
</dependency>

测试依赖最新版本在此

4. 应用结构

必须遵循特定的目录结构,典型 MVC 应用结构如下:

active web

关键目录说明:

  • app 包下需包含:controllersserviceconfigmodels 子包
  • ✅ 视图文件位于 WEB-INF/views,按控制器名划分子目录(如 ArticleController 对应 article/ 目录)
  • web.xml 需配置 <filter> 而非 <servlet>

示例 web.xml 配置:

<filter>
    <filter-name>dispatcher</filter-name>
    <filter-class>org.javalite.activeweb.RequestDispatcher</filter-class>
    <!-- ... -->
</filter>
<!-- 默认控制器配置 -->
<init-param>
    <param-name>root_controller</param-name>
    <param-value>home</param-value>
</init-param>

5. 控制器(Controllers)

控制器是 ActiveWeb 的核心组件,必须位于 app.controllers 包:

public class ArticleController extends AppController {
    // ...
}

5.1. 控制器 URL 映射

URL 自动按约定生成:

  • ArticleControllerhttp://host:port/contextroot/article
  • 默认执行 index() 方法:
public void index() {
    render("articles");    
}
  • 其他方法通过 URL 后缀访问:
    public void search() {
      render("search");
    }
    
    访问:http://host:port/contextroot/article/search

⚠️ 可通过 @POST/@PUT/@DELETE/@GET 注解指定 HTTP 方法,未注解默认为 GET

5.2. 控制器 URL 解析规则

URL 生成规则:

  • 单词控制器:app.controllers.ArticleController/article
  • 子包控制器:app.controllers.baeldung.ArticleController/baeldung/article
  • 多词控制器:PublishedArticleController/published_article(用下划线分隔)

5.3. 获取请求参数

通过 AppController 提供的方法获取参数:

// 获取单个参数
String keyword = param("key");  

// 获取所有参数
Map<String, String[]> criterion = params();

简单粗暴,直接用就完事了

6. 视图(Views)

ActiveWeb 使用 Apache FreeMarker 模板引擎(非 JSP),视图文件需放在:

  • WEB-INF/views/{控制器名}/ 目录下
  • ArticleController 对应 WEB-INF/views/article/

6.1. 控制器视图映射

默认规则:

  • index()/views/article/index.ftl
  • search()/views/article/search.ftl

手动指定视图

// 同目录视图
render("articles");    

// 跨目录视图
render("/common/error");

6.3. 带数据的视图

向视图传递数据:

// 方法一
view("articles", articleService.getArticles());

// 方法二(与 view() 等效)
assign("article", articleService.search(keyword));

模板中使用数据:

<@content for="title">Articles</@content>
...
<#list articles as article>
    <tr>
        <td>${article.title}</td>
        <td>${article.author}</td>
        <td>${article.words}</td>
        <td>${article.date}</td>
    </tr>
</#list>
</table>

7. 依赖管理

使用 Google Guice 管理 DI,以服务层为例:

定义服务接口

public interface ArticleService {
    List<Article> getArticles();   
    Article search(String keyword);
}

实现类

public class ArticleServiceImpl implements ArticleService {
    public List<Article> getArticles() {
        return fetchArticles(); // 实际业务逻辑
    }

    public Article search(String keyword) {
        Article ar = new Article();
        ar.set("title", "Article with "+keyword);
        ar.set("author", "dev@baeldung.com"); // mock 邮箱
        ar.set("words", "1250");
        ar.setDate("date", Instant.now());
        return ar;
    }
}

Guice 模块配置

public class ArticleServiceModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(ArticleService.class).to(ArticleServiceImpl.class)
          .asEagerSingleton();
    }
}

注册到应用上下文

public class AppBootstrap extends Bootstrap {
    public void init(AppContext context) {}

    public Injector getInjector() {
        return Guice.createInjector(new ArticleServiceModule());
    }
}

⚠️ 类名必须为 AppBootstrap 且位于 app.config

控制器注入

@Inject
private ArticleService articleService;

8. 测试

使用 JavaLite 的 JSpec 进行测试,测试类命名规则:{Controller}Spec

public class ArticleControllerSpec extends ControllerSpec {
    // ...
}

基础测试示例

@Test
public void whenReturnedArticlesThenCorrect() {
    request().get("index");
    a(responseContent())
      .shouldContain("<td>Introduction to Mule</td>");
}

带参数测试

@Test
public void givenKeywordWhenFoundArticleThenCorrect() {
    request().param("key", "Java").get("search");
    a(responseContent())
      .shouldContain("<td>Article with Java</td>");
}

支持链式调用传参,API 设计很流畅

9. 应用部署

可部署到任何 Servlet 容器(Tomcat/WildFly/Jetty),最简单的方式是使用 Maven Jetty 插件:

<plugin>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-maven-plugin</artifactId>
    <version>9.4.8.v20171121</version>
    <configuration>
        <reload>manual</reload>
        <scanIntervalSeconds>10000</scanIntervalSeconds>
    </configuration>
</plugin>

插件最新版本在此

启动命令:

mvn jetty:run

10. 总结

本文介绍了 ActiveWeb 的核心概念和约定。该框架还有更多高级特性,建议参考官方文档深入学习。

本文示例代码可在 GitHub 获取。


原始标题:Introduction to ActiveWeb | Baeldung