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 模块生效了。

相关推荐
像少年啦飞驰点、1 天前
零基础入门 Spring Boot:从“Hello World”到可上线的 Web 应用全闭环指南
java·spring boot·web开发·编程入门·后端开发
有来技术1 天前
Spring Boot 4 + Vue3 企业级多租户 SaaS:从共享 Schema 架构到商业化套餐设计
java·vue.js·spring boot·后端
东东5161 天前
xxx医患档案管理系统
java·spring boot·vue·毕业设计·智慧城市
东东5161 天前
学院个人信息管理系统 (springboot+vue)
vue.js·spring boot·后端·个人开发·毕设
qq_12498707531 天前
基于Srpingboot心晴疗愈社平台的设计与实现(源码+论文+部署+安装)
java·数据库·spring boot·spring·microsoft·毕业设计·计算机毕业设计
大爱编程♡1 天前
SpringBoot统一功能处理
java·spring boot·后端
小马爱打代码1 天前
Spring Boot:第三方 API 调用的企业级容错设计
java·spring boot·后端
东东5161 天前
xxx食堂移动预约点餐系统 (springboot+微信小程序)
spring boot·微信小程序·小程序·毕业设计·个人开发·毕设
csdn2015_1 天前
springboot task
java·spring boot·后端
czlczl200209251 天前
Spring Boot :如何高性能地在 Filter 中获取响应体(Response Body)
java·spring boot·后端