Gradle 高级篇之构建多模块项目的方法

基于 IDEA 创建 Gradle 多模块项目。

  • IDEA 版本:2023.3.4
  • SpringBoot 版本:3.5.3
  • Gradle 版本:gradle-8.12.1
  • JDK 版本:jdk-21.0.7

1. 创建父项目

1.1. 新建项目

文件 -> 新建 -> 项目

输入项目名称:gradle-multi-module-demo。

点击下一步,创建父项目,这里什么都没选。

点击创建,就建好了一个 SpringBoot 项目。

1.2. 修改项目

我们是要创建多模块项目,所以作为父项目,有些内容是可以删除的。下图中选中的内容可以删除。

项目目录下仅保留了:.gradle \ .idea \ .gitattributes \ .gitignore \ setting.gradle

删除后的项目结构:

2. 创建子模块

2.1. 创建模块

选中父项目 -> 新建 -> 模块

输入模块名称:demo-core。(这里模块名称最好是一个单词,多个单词的话注意修改软件包名称,多个单词间加点号)

点击下一步,作为示例项目,我仅选择了 lombok 和 spring web。

点击创建,就建好了一个 SpringBoot 模块。

2.2. 修改模块

创建好子模块后,需要在右上角的 Gradle 下删除最外层的子模块目录。

然后将子模块包含到父项目下:

刷新后,在右上角的 Gradle 下的父项目下能看到这个子模块了。

删除子模块的settings.gradle文件。

使用同样的方法再创建一个子模块demo-mgmt

因为我选的依赖一样,所以这两个子模块的 build.gradle 内容一样:

gradle 复制代码
plugins {
    id 'java'
    id 'org.springframework.boot' version '3.5.3'
    id 'io.spring.dependency-management' version '1.1.7'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(21)
    }
}

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

tasks.named('test') {
    useJUnitPlatform()
}

3. 提取公共配置到父项目

现在发现两个子模块的 build.gradle 内容基本一样,所以可以把这些相同的配置提到父项目的 build.gradle 文件中,前面把这个文件删除了,这里可以选一个子模块的该文件复制出来。

修改方法:

  1. plugins下添加一个subprojects,将下面内容都复制到里面。
  2. 添加一个apply,将plugins中的插件进行应用。
  3. 修改dependencies中的内容,仅保留子模块们共用的依赖。

修改完的 build.gradle 内容:

gradle 复制代码
plugins {
    id 'java'
    id 'org.springframework.boot' version '3.5.3'
    id 'io.spring.dependency-management' version '1.1.7'
}

subprojects {
    apply {
        plugin('java')
        plugin('org.springframework.boot')
        plugin('io.spring.dependency-management')
    }

    group = 'com.example'
    version = '0.0.1-SNAPSHOT'

    java {
        toolchain {
            languageVersion = JavaLanguageVersion.of(21)
        }
    }

    configurations {
        compileOnly {
            extendsFrom annotationProcessor
        }
    }

    repositories {
        mavenCentral()
    }

    dependencies {
        implementation 'org.springframework.boot:spring-boot-starter-web'
        compileOnly 'org.projectlombok:lombok'
        annotationProcessor 'org.projectlombok:lombok'
        testImplementation 'org.springframework.boot:spring-boot-starter-test'
        testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
    }

    tasks.named('test') {
        useJUnitPlatform()
    }
}

子模块的 build.gradle 文件内容修改,排除共用的依赖,仅保留单独的依赖(分别加了两个不同的依赖)。

两个子模块的 build.gradle 文件内容如下:

gradle 复制代码
dependencies {
    implementation("com.alibaba.fastjson2:fastjson2:2.0.57")
}
gradle 复制代码
dependencies {
    implementation 'cn.hutool:hutool-all:5.8.38'
}

4. 创建公共子模块

上面内容是对公共配置抽取,现在需要搭建一个公共代码子模块:

创建完毕后,参考 2.2,同样的修改方式

接下来修改 common 模块的 build.gradle 文件:

gradle 复制代码
plugins {
    id 'java-library'
}

接下来修改父项目的 build.gradle 文件,添加一个判断引入,表示非 common 模块都引入 common 模块:

gradle 复制代码
if (project.name != 'demo-common'){
    dependencies {
        implementation project(':demo-common')
    }
}

修改完的父项目的 build.gradle 文件内容:

gradle 复制代码
plugins {
    id 'java'
    id 'org.springframework.boot' version '3.5.3'
    id 'io.spring.dependency-management' version '1.1.7'
}

subprojects {
    apply {
        plugin('java')
        plugin('org.springframework.boot')
        plugin('io.spring.dependency-management')
    }

    group = 'com.example'
    version = '0.0.1-SNAPSHOT'

    java {
        toolchain {
            languageVersion = JavaLanguageVersion.of(21)
        }
    }

    configurations {
        compileOnly {
            extendsFrom annotationProcessor
        }
    }

    repositories {
        mavenCentral()
    }

    dependencies {
        implementation 'org.springframework.boot:spring-boot-starter-web'
        compileOnly 'org.projectlombok:lombok'
        annotationProcessor 'org.projectlombok:lombok'
        testImplementation 'org.springframework.boot:spring-boot-starter-test'
        testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
    }

    if (project.name != 'demo-common'){
        dependencies {
            implementation project(':demo-common')
        }
    }

    tasks.named('test') {
        useJUnitPlatform()
    }
}

实际上,可以在需要依赖 common 的模块中直接添加依赖即可,能更灵活一些。

5. 测试公共子模块

首先在 common 模块配置一个全局异常拦截类:

java 复制代码
package com.example.democommon.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ProblemDetail;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * @author wangbo
 * @since 2025/7/13
 */
@Slf4j
@RestControllerAdvice
public class GlobalControllerAdvice {
    @ExceptionHandler
    public ProblemDetail exceptionHandler(Exception e){
        log.info("==============");
        log.atError().setMessage(e::getMessage).setCause(e).log();
        return ProblemDetail.forStatusAndDetail(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage());
    }
}

在 mgmt 模块导入该类:

Java 复制代码
package com.example.demomgmt;

import com.example.democommon.config.GlobalControllerAdvice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;

@Import({GlobalControllerAdvice.class})
@SpringBootApplication
public class DemoMgmtApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoMgmtApplication.class, args);
    }

}

在 demo-mgmt 模块中创建一个 Controller 类,写上一个异常方法,启动项目,看异常是否会被拦截。

java 复制代码
package com.example.demomgmt.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author wangbo
 * @since 2025/7/13
 */
@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {

    @GetMapping("/a")
    public String test1(){
        log.info("aaaaa");
        return "aaaaa";
    }

    @GetMapping("/b")
    public String test2(){
        log.info("bbbbb");
        int i = 1 / 0;
        return "bbbbb";
    }
}

测试会被拦截,证明 common 模块中的全局异常拦截对 mgmt 模块生效了。

相关推荐
fanruitian1 小时前
Springboot aop面向切面编程
java·spring boot·spring
中国lanwp2 小时前
Spring Boot 中使用 Lombok 进行依赖注入的示例
java·spring boot·后端
张先shen7 小时前
Spring Boot集成Redis:从配置到实战的完整指南
spring boot·redis·后端
Q_Q5110082857 小时前
python的婚纱影楼管理系统
开发语言·spring boot·python·django·flask·node.js·php
congvee10 小时前
springboot 学习第1期 - 创建工程
spring boot
风流 少年11 小时前
Cursor创建Spring Boot项目
java·spring boot·后端
毕设源码_钟学姐11 小时前
计算机毕业设计springboot宿舍管理信息系统 基于Spring Boot的高校宿舍管理平台设计与实现 Spring Boot框架下的宿舍管理系统开发
spring boot·后端·课程设计
军军君0111 小时前
基于Springboot+UniApp+Ai实现模拟面试小工具二:后端项目搭建
前端·javascript·spring boot·spring·微信小程序·前端框架·集成学习
全栈凯哥12 小时前
16.Spring Boot 国际化完全指南
java·spring boot·后端