[IntelliJ IDEA + EduTools] 从零开始编写一套 Java 教材(三)

目录

[IntelliJ IDEA + EduTools] 从零开始编写一套 Java 教材(零)

[IntelliJ IDEA + EduTools] 从零开始编写一套 Java 教材(一)

[IntelliJ IDEA + EduTools] 从零开始编写一套 Java 教材(二)

上期回顾

第三课 Gradle 构建脚本

第0节 build.gradle

第1节 settings.gradle


上期回顾

上一节课,我们介绍了与 EduTools 有关的4种 YAML 文件的格式。在日常的开发过程中,很难遇到需要我们人为编辑这些 YAML 文件的情况,EduTools 中的 Course Creator 工具会辅助我们进行数字教材的编写工作。

这一节课,我们将着重讲解 Gradle 项目的2个核心配置文件:build.gradle 和 settings.gradle 。


第三课 Gradle 构建脚本

Gradle 是一个以 Groovy 语言为项目构建脚本语言的自动化构建工具,支持 Java / Groovy / Scala / Kotlin 等各类 JVM 编程语言。build.gradle 与 settings.gradle 是项目的核心,它们共同管理着 Gradle 项目的一切。IntelliJ IDEA 会首先启动 Gradle ,Gradle 执行 *.gradle 构建脚本并生成各项配置,IntelliJ IDEA 自动分析这些配置,并将其与自身的设置进行同步,这正是我们在 IntelliJ IDEA 中打开 Maven / Gradle / SBT 项目时会先『加载项目结构』再『导入 IntelliJ IDEA 项目』的原因。

我们的教程项目结构本质上是一个 Gradle 多子项目结构。单一项目的 Gradle 构建脚本可能十分简单,但对于拥有四层目录分级的大型数字教程项目而言,一个正确的配置脚本至关重要。EduTools 已经为我们生成了这样的构建脚本,我们要做的只是读懂它、理解它。

 

第0节 build.gradle

// 用于构建脚本自身的配置
buildscript {
    // 远程仓库列表
    repositories {
        // 华为云 Maven 远程仓库
        maven { url "https://mirrors.huaweicloud.com/repository/maven/" }
        // 阿里云 Maven 远程仓库
        maven { url "https://maven.aliyun.com/repository/public" }
        // Maven 中央仓库
        mavenCentral()
    }
}

/**
 * 格式化 Gradle 标准输出
 *
 * @param output 字节数组输出缓冲流
 */
def printOutput(def output) {
    // 创建一个新的 Gradle 任务
    return tasks.create("printOutput") {
        // 遍历缓冲流中的每一行内容
        for (line in output.toString().readLines()) {
            // 补充前缀
            println "#educational_plugin" + line
        }
    }
}

// 子项目统一配置
subprojects {
    // 引入 Java 语言插件
    apply plugin: 'java'
    // 引入构建插件
    apply plugin: 'application'

    // 限制 Java 语法为 JDK8 及以下
    // JDK9 及更高版本的语法特性将不可使用
    sourceCompatibility = 1.8

    // 指定子项目所使用的远程仓库地址
    repositories {
        maven { url "https://mirrors.huaweicloud.com/repository/maven/" }
        maven { url "https://maven.aliyun.com/repository/public" }
        mavenCentral()
    }

    // 子项目依赖项列表
    dependencies {
        // 编译时使用的依赖项
        compile group: 'org.apache.commons', name: 'commons-math', version: '2.2'
        // 测试编译时使用的依赖项
        testCompile group: 'org.junit.jupiter', name: 'junit-jupiter', version: '5.6.2'
    }

    // 项目源文件列表
    sourceSets {
        // 主源文件目录
        main { java.srcDir 'src' }
        // 测试源文件目录
        test { java.srcDir 'test' }
    }

    // 指定项目的主类名
    mainClassName = project.hasProperty("mainClass") ?      // 当项目配置了 mainClass 属性时
                    project.getProperty("mainClass") : ""   // 获取配置值,否则留空

    // 定义 Gradle 运行时的标准输出
    def runOutput = new ByteArrayOutputStream()
    tasks.run.setStandardOutput(runOutput)
    // 指定构建过程最后执行的动作
    tasks.run.doLast { printOutput(runOutput) }
}

// 通用项目,这个子项目用于编写其他子项目所共用的类或方法
project(':util') {
    // 特定项目的依赖项
    dependencies {
        testCompile group: 'org.junit.jupiter', name: 'junit-jupiter', version: '5.6.2'
    }
}

// 配置除 util 之外的其他子项目
configure(subprojects.findAll { it.name != 'util' }) {
    // 添加 util 项目编译生成的类文件
    dependencies {
        compile project(':util').sourceSets.main.output
        testCompile project(':util').sourceSets.test.output
    }
}

 

第1节 settings.gradle

/**
 * 名称标准化(用于去除目录中的非法字符,转换为 Gradle 可接受的项目名)
 *
 * @param 任意字符串
 * @return 格式化后的字符串
 */
static String sanitizeName(String name) {
    // 将空格与各类标点符号统一替换为下划线
    return name.replaceAll("[ /\\\\:<>\"?*|()]", "_")
    // 去除名称开头和结尾多余的小数点
               .replaceAll("(^[.]+)|([.]+\$)", "")
}

// 指定根项目名
rootProject.name = 'Tutorial'

// 递归遍历根项目目录的各级子目录
rootProject.projectDir.eachDirRecurse {
    // 如果项目不是任务目录,或者目录存在 .idea/ 子目录
    if (!isTaskDir(it) || it.path.contains(".idea")) {
        // 忽略此目录
        return
    }
    // 获取当前目录相对根项目目录的路径
    def taskRelativePath = rootDir.toPath().relativize(it.toPath())

    def parts = []
    // 将相对路径中每一部分的目录名添加到数组中
    for (name in taskRelativePath) {
        parts.add(sanitizeName(name.toString()))
    }

    // 将相对路径用连字符串起来,作为项目名
    def moduleName = parts.join("-")
    // 引入项目名
    include "$moduleName"
    // 指定子项目的项目根目录
    project(":$moduleName").projectDir = it
}

/**
 * 检查一个目录是不是任务目录
 *
 * @param 目录对象
 * @return 拥有 src/ 目录的项目是任务项目,否则不是
 */
static def isTaskDir(File dir) {
    return new File(dir, "src").exists()
}

// 引入全局工具项目
include 'util'

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

️是纱雾酱哟~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值