1. 概述

本文是对 Grails 3 框架及其核心 ORM 组件 GORM 的快速入门指南,适合有一定 Java/Groovy 开发经验的后端开发者参考。

Grails 是一个基于 Groovy 语言的全栈 Web 框架,底层深度集成了一系列成熟的 Java 技术栈:

  • GORM:基于 Hibernate 实现的领域对象持久化层
  • Spring Framework:提供依赖注入(DI)和应用上下文管理
  • SiteMesh:负责页面布局与主题渲染
  • Hibernate:作为默认的 JPA 实现,处理数据库映射与操作

简单来说,Grails 就是把这些主流技术“组装”起来,并通过约定优于配置(convention over configuration)的理念,让你用更少的代码快速搭建出功能完整的 Web 应用。

⚠️ 注意:虽然 Grails 使用 Groovy 编写,但与 Java 完全兼容。你可以混合使用 Java 类和 Groovy 类,无缝接入现有项目。


2. 数据源配置

默认情况下,Grails 在开发(development)和测试(test)环境中使用 HSQLDB 内存数据库,开箱即用,无需额外配置。

但实际开发中我们通常需要切换到 MySQL、PostgreSQL 等生产级数据库。这时可以通过修改 application.yml 文件来自定义数据源。

示例:配置 MySQL 数据源

environments:
    development:
        dataSource:
            driverClassName: "com.mysql.cj.jdbc.Driver"
            url: "jdbc:mysql://localhost:3306/grails_dev"
            username: "root"
            password: "password123"
            dialect: org.hibernate.dialect.MySQL8Dialect

✅ 支持多环境配置,如 testproduction 可独立设置不同数据库。
✅ 推荐使用 com.mysql.cj.jdbc.Driver(MySQL 8+ 驱动),避免使用已废弃的 com.mysql.jdbc.Driver
⚠️ 注意 URL 端口是否正确(MySQL 默认 3306,不是 8080)。


3. 领域模型(Domain)

Grails 的一大优势是自动建表能力。只要定义好 Domain 类,框架会根据 dbCreate 策略(如 create-dropupdate)自动创建或更新数据库表结构。

定义 User 领域类

class User {
    String userName
    String password
    String email
    Integer age  // 建议使用 Integer 而非 String

    static constraints = {
        userName blank: false, unique: true
        password size: 5..10, blank: false
        email email: true, blank: true
        age min: 1, max: 150
    }

    static mapping = {
        sort "userName"
        table "users"  // 自定义表名
    }
}

关键特性说明:

  • constraints:内联定义校验规则,无需注解(annotation-free),简洁直观
  • 自动触发验证:调用 save() 时自动校验,失败返回 errors 对象
  • mapping:可指定排序、表名、索引等 ORM 映射行为

比如设置了 sort "userName" 后:

List<User> users = User.list()  // 返回结果已按 userName 升序排列

当然你也可以在查询时手动指定排序:

User.list(sort: "userName", order: "desc")

但模型层统一定义更利于维护,避免到处写重复逻辑。


4. CRUD 操作

Grails 提供了两种方式生成基础 CRUD 接口:动态脚手架(Scaffolding)和静态代码生成。

✅ 动态脚手架(Dynamic Scaffolding)

只需一行代码,运行时自动生成完整 CRUD 接口:

class UserController {
    static scaffold = true
}

框架会在运行时动态注入以下方法并暴露为 HTTP 接口:

  • index() → 列表页
  • show(id) → 查看详情
  • create() / save() → 创建
  • edit(id) / update() → 修改
  • delete(id) → 删除

✅ 适合快速原型开发
❌ 不推荐用于生产环境(缺乏灵活性)


✅ 静态脚手架(Static Scaffolding)

通过命令生成真实可编辑的控制器和视图代码:

# 仅生成视图
grails generate-views User

# 生成控制器 + 视图
grails generate-controller User

# 一键生成全部(推荐用于初学者)
grails generate-all User

生成的代码完全可控,便于定制业务逻辑,是生产项目的首选方式。


手动 CRUD 示例(GORM API 实践)

创建用户

def user = new User(
    userName: "alice",
    password: "pass123",
    email: "alice@example.com",
    age: 25
)
user.save(flush: true)  // flush: true 表示立即执行 SQL

⚠️ 若 save 失败,可通过 user.errors 查看具体校验错误

查询单条记录

// 可编辑模式(默认)
def user = User.get(1)

// 只读模式(性能更优,适合仅展示场景)
def user = User.read(1)

read() 使用 Hibernate 的 load() 语义,延迟加载且不加入一级缓存

更新记录

def user = User.get(1)
user.userName = "alice_update"
user.age = 26
user.save(flush: true)

❗ 注意:必须先 get 再修改,不能直接 new User(id:1).save()(会插入新记录)

删除记录

def user = User.get(1)
user.delete(flush: true)

✅ 支持级联删除(需在 domain 中配置 hasManybelongsTo


5. GORM 查询

GORM 提供了多种灵活的数据检索方式,远比原生 HQL 更简洁。

5.1 find:HQL 查询

支持标准 HQL 语法:

def user = User.find("from User as u where u.userName = 'alice'")

支持参数化查询(推荐):

// 位置参数
def user = User.find("from User where userName = ?", ["alice"])

// 命名参数(更清晰)
def user = User.find("from User where userName = :username", [username: "alice"])

✅ 参数化可防止 SQL 注入,强烈建议使用


5.2 findBy:动态查找器

Grails 最实用的功能之一 —— 根据属性名自动生成查询方法

def user = User.findByUserName("alice")
def user = User.findByUserNameAndAge("alice", 25)
def user = User.findByUserNameLike("ali%")
def user = User.findByAgeGreaterThanAndAgeLessThan(18, 60)
def user = User.findByUserNameNotEqual("admin")

✅ 方法名即 DSL,见名知意
✅ 支持 AndOrNotEqualIsNullBetween 等关键词
✅ 查询结果为单个对象(null 安全)

完整支持的操作符见官方文档:GORM Finders


5.3 Criteria:条件查询

适用于复杂查询场景,支持嵌套条件、分页、排序等。

def results = User.createCriteria().list {
    projections {
        property('id')
        property('userName')
    }
    like("userName", "a%")
    between("age", 18, 60)
    and {
        isNotNull("email")
        eq("active", true)
    }
    order("userName", "asc")
    maxResults(10)
    firstResult(0)
}

⚠️ 注意:闭包 {} 是 Criteria 的语法要求,不能用 ()
✅ 支持 projections 实现 select 部分子段
✅ 可组合多个条件,逻辑清晰


5.4 executeQuery / executeUpdate:原生 HQL 操作

查询(executeQuery)

def usernames = User.executeQuery(
    "SELECT u.userName FROM User u WHERE u.age > :minAge",
    [minAge: 18]
)

返回的是 List,常用于聚合查询或只取部分字段。

更新/删除(executeUpdate)

// 批量删除
def rowCount = User.executeUpdate(
    "DELETE User WHERE userName = :name",
    [name: "temp_user"]
)

// 批量更新
def updated = User.executeUpdate(
    "UPDATE User SET password = :newPass WHERE userName = :name",
    [newPass: "new123", name: "alice"]
)

✅ 支持批量操作,性能优于逐条 save/delete
⚠️ 注意:executeUpdate 不触发 beforeUpdate 等事件钩子


6. 总结

Grails 3 是一个成熟、高效的全栈框架,特别适合需要快速交付的中小型项目。其核心亮点在于:

  • 约定优于配置:减少样板代码,提升开发效率
  • GORM 强大易用:支持动态查询、Criteria、HQL 多种方式
  • 脚手架机制:快速生成 CRUD,加速原型开发
  • 无缝集成 Spring + Hibernate:企业级能力背书

虽然近年来 Spring Boot 更为主流,但在 Groovy 技术栈或遗留 Grails 项目中,掌握 GORM 和基本开发模式仍是必备技能。

📌 建议:新手可从 generate-all 入手,理解生成代码后再逐步自定义;老手则可直接手写 Controller + GORM 查询,更灵活高效。


原始标题:An Introduction to Grails 3