从0开始学习Java+AI知识点总结-27.web实战(Maven高级)

一、分模块设计与开发:让项目结构更清晰

1.1 为什么需要分模块?单模块开发的痛点

在小型项目中,单模块(所有代码放在一个工程)或许能满足需求,但项目规模扩大后会出现两大核心问题:

  • 维护成本高:几十甚至上百个开发人员协作时,所有人操作同一个工程,代码冲突频繁,功能迭代时牵一发而动全身(比如改一个工具类可能影响多个业务模块)。
  • 资源复用难:项目中的通用组件(如实体类、工具类、统一响应封装)无法单独抽离,其他项目想使用时,只能复制粘贴或依赖整个工程(导致冗余代码多、性能损耗大)。

1.2 分模块设计的核心思路

分模块设计的本质是 **"拆分" 与 "解耦"**:在项目设计阶段,将一个大工程按功能或结构拆分为多个独立子模块,每个模块专注于特定职责,模块间通过依赖关系协作。

例如:电商项目可拆分为 "商品模块""订单模块""购物车模块",同时抽离 "通用组件模块"(存放实体类、工具类),各业务模块只需依赖通用组件,无需重复编写代码。

1.3 3 种分模块拆分策略(附实战案例)

分模块没有固定标准,但需遵循 "高内聚、低耦合" 原则,常见有 3 种拆分策略:

|------------|-----------------------------------|--------------------|-----------------------------------------------------------------------------------------------------|
| 拆分策略 | 核心思路 | 适用场景 | 工程结构示例 |
| 按功能模块拆分 | 按业务功能划分,每个模块对应一个完整业务(如商品、订单、搜索) | 业务边界清晰的项目(如电商、CRM) | mall-common(通用组件)、mall-goods(商品)、mall-order(订单)、mall-search(搜索) |
| 按层拆分 | 按技术分层划分,每个模块对应一个技术层(如控制层、业务层、数据层) | 技术架构标准化的项目(如中台系统) | mall-common(通用)、mall-controller(控制层)、mall-service(业务层)、mall-mapper(数据层)、mall-pojo(实体类) |
| 功能 + 层混合拆分 | 先按功能拆分,再在每个功能模块内部分层 | 大型复杂项目(如多端共用的后端系统) | mall-common(通用)、mall-goods-controller(商品控制层)、mall-goods-service(商品业务层)、mall-order-controller(订单控制层) |

1.4 分模块开发实战步骤(以 "通用组件拆分" 为例)

以传统 Web 工程为例,将 "实体类" 和 "工具类" 拆分为独立模块,步骤如下:

步骤 1:拆分 "实体类模块"(xxx-pojo)
  1. 新建 Maven 模块,命名为xxx-pojo(如 tlias-pojo),用途:存放所有实体类(如 User、Order、分页结果 PageBean、统一响应 Result)。
  2. 在xxx-pojo的pom.xml中引入依赖(实体类常用依赖,如 Lombok、Spring 基础依赖):

|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <dependencies> <!-- Lombok:简化实体类get/set方法 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.34</version> </dependency> <!-- Spring基础依赖:支持@DateTimeFormat等注解 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>3.2.8</version> </dependency> </dependencies> |

  1. 将原工程中com.xxx.pojo包下的所有类复制到xxx-pojo的对应包路径下。
步骤 2:拆分 "工具类模块"(xxx-utils)
  1. 新建 Maven 模块,命名为xxx-utils,用途:存放通用工具类(如 JWT 工具、OSS 上传工具、日期工具)。
  2. 在xxx-utils的pom.xml中引入工具类依赖(如 JWT、阿里云 OSS):

|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <dependencies> <!-- JWT:生成/解析令牌 --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> <!-- 阿里云OSS:文件上传 --> <dependency> <groupId>com.aliyun.oss</groupId> <artifactId>aliyun-sdk-oss</artifactId> <version>3.17.4</version> </dependency> <!-- 依赖实体类模块:工具类可能用到实体类 --> <dependency> <groupId>com.xxx</groupId> <artifactId>xxx-pojo</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> |

  1. 将原工程中com.xxx.utils包下的工具类复制到xxx-utils的对应包路径下。
步骤 3:改造原业务模块(xxx-web-management)
  1. 删除原工程中已拆分的pojo和utils包(避免冲突)。
  2. 在原业务模块的pom.xml中引入拆分后的模块依赖:

|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <dependencies> <!-- 依赖实体类模块 --> <dependency> <groupId>com.xxx</groupId> <artifactId>xxx-pojo</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!-- 依赖工具类模块 --> <dependency> <groupId>com.xxx</groupId> <artifactId>xxx-utils</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> |

1.5 分模块开发的核心注意事项

  1. 先设计后开发:分模块需在项目启动前规划好,避免先开发完再拆分(会导致大量代码迁移和依赖调整)。
  2. 模块边界清晰:每个模块的职责单一,避免出现 "一个模块既包含商品业务,又包含订单逻辑" 的情况。
  3. 依赖不循环:禁止出现 "模块 A 依赖模块 B,模块 B 又依赖模块 A" 的循环依赖(会导致 Maven 构建失败)。

二、继承与聚合:解决依赖混乱,实现一键构建

分模块后,会出现新问题:多个模块依赖重复(如每个模块都要引入 Lombok)、版本管理麻烦(改一个依赖版本需改所有模块)、构建时需手动按依赖顺序执行(如先构建 pojo,再构建 utils,最后构建业务模块)。Maven 的 "继承" 和 "聚合" 特性可完美解决这些问题。

2.1 继承:统一管理依赖,简化配置

2.1.1 继承的核心作用
  • 简化依赖配置:将多个模块的公共依赖(如 Lombok、Spring Boot Starter)提取到 "父工程",子模块无需重复配置,自动继承父工程依赖。
  • 统一版本管理:父工程定义依赖版本,子模块直接使用,避免版本不一致导致的兼容性问题。
2.1.2 继承的实现步骤(以 Spring Boot 项目为例)

Spring Boot 项目默认继承spring-boot-starter-parent,因此我们需要创建 "自定义父工程",让自定义父工程继承 Spring Boot 父工程,再让业务模块继承自定义父工程(支持多重继承)。

步骤 1:创建自定义父工程(xxx-parent)
  1. 新建 Maven 模块,命名为xxx-parent,打包方式必须为 pom(父工程仅用于依赖管理,不写业务代码,无需 src 目录,可删除)。
  2. 在父工程的pom.xml中配置继承关系和公共依赖:

|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <!-- 继承Spring Boot官方父工程 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.8</version> <relativePath/> <!-- 从仓库查找父工程,不指定本地路径 --> </parent> <!-- 自定义父工程坐标 --> <groupId>com.xxx</groupId> <artifactId>xxx-parent</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging> <!-- 父工程打包方式必须为pom --> <!-- 1. 配置公共依赖(子模块自动继承) --> <dependencies> <!-- Lombok:所有模块通用 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.34</version> </dependency> <!-- Spring基础依赖:所有模块通用 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> </dependencies> <!-- 2. 版本锁定(非公共依赖,仅统一版本,子模块需手动引入) --> <dependencyManagement> <dependencies> <!-- JWT:仅部分模块使用,统一版本 --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> <!-- 阿里云OSS:仅工具类模块使用,统一版本 --> <dependency> <groupId>com.aliyun.oss</groupId> <artifactId>aliyun-sdk-oss</artifactId> <version>3.17.4</version> </dependency> </dependencies> </dependencyManagement> <!-- 3. 自定义属性(集中管理版本号,便于修改) --> <properties> <maven.compiler.source>17</maven.compiler.source> <!-- JDK版本 --> <maven.compiler.target>17</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <!-- 依赖版本属性(可直接引用) --> <lombok.version>1.18.34</lombok.version> <jwt.version>0.9.1</jwt.version> </properties> </project> |

步骤 2:子模块继承父工程

在每个子模块(如 xxx-pojo、xxx-utils)的pom.xml中配置继承:

|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <parent> <groupId>com.xxx</groupId> <artifactId>xxx-parent</artifactId> <version>1.0-SNAPSHOT</version> <!-- 父工程pom.xml的相对路径(若父工程与子模块平级,路径为../xxx-parent/pom.xml) --> <relativePath>../xxx-parent/pom.xml</relativePath> </parent> <!-- 子模块坐标:groupId可省略(继承父工程),仅需配置artifactId和version --> <artifactId>xxx-pojo</artifactId> <version>1.0-SNAPSHOT</version> |

步骤 3:子模块引入依赖(无需版本号)

若依赖已在父工程的dependencyManagement中锁定版本,子模块引入时无需写version:

|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <!-- 子模块xxx-utils引入JWT依赖(版本由父工程统一管理) --> <dependencies> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> </dependency> </dependencies> |

2.1.3 关键知识点: dependencyManagement vs dependencies

很多人会混淆这两个标签,核心区别如下:

|---------|-------------------------|--------------------------|
| 特性 | <dependencies> | <dependencyManagement> |
| 作用 | 直接引入依赖,子模块自动继承 | 仅统一管理依赖版本,不自动引入依赖 |
| 子模块使用方式 | 无需额外配置,直接使用 | 需手动引入依赖,无需写 version |
| 适用场景 | 所有子模块都需要的公共依赖(如 Lombok) | 部分子模块需要的依赖(如 JWT、OSS) |

2.2 聚合:一键构建所有模块,无需手动排序

2.2.1 聚合的核心作用

分模块后,模块间有依赖关系(如 xxx-web 依赖 xxx-utils,xxx-utils 依赖 xxx-pojo),手动构建时需按 "pojo → utils → web" 的顺序执行,否则会因依赖缺失失败。

聚合 可将所有模块纳入 "聚合工程",执行一次构建命令(如mvn package),Maven 会自动按依赖顺序构建所有模块,实现 "一键构建"。

2.2.2 聚合的实现步骤

通常将 "父工程" 同时作为 "聚合工程"(无需额外创建聚合工程),步骤如下:

  1. 在父工程(xxx-parent)的pom.xml中配置modules标签,指定需要聚合的子模块:

|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <!-- 聚合工程:指定子模块路径(相对路径) --> <modules> <!-- 若子模块与父工程平级,路径为../xxx-pojo --> <module>../xxx-pojo</module> <module>../xxx-utils</module> <module>../xxx-web-management</module> </modules> |

  1. 执行聚合构建:在父工程根目录执行 Maven 命令(如mvn clean package),Maven 会自动按依赖顺序构建所有子模块:
    • 先构建xxx-pojo(无依赖)
    • 再构建xxx-utils(依赖 xxx-pojo)
    • 最后构建xxx-web-management(依赖 xxx-utils 和 xxx-pojo)
2.2.3 聚合的注意事项
  • 聚合工程的打包方式必须为pom。
  • modules中模块的顺序不影响构建顺序(Maven 会自动分析依赖关系)。
  • 若需排除某个模块,只需从modules中删除该模块的配置即可。

2.3 继承与聚合的对比总结

|------|------------------------------|--------------------------------|
| 特性 | 继承(Inheritance) | 聚合(Aggregation) |
| 核心目标 | 简化依赖配置、统一版本 | 一键构建所有模块,自动排序 |
| 配置位置 | 子模块的 pom.xml 中(配置 parent 标签) | 聚合工程的 pom.xml 中(配置 modules 标签) |
| 感知关系 | 父工程无法感知哪些子模块继承了自己 | 聚合工程能感知所有被聚合的子模块 |
| 共同点 | 打包方式均为 pom,无业务代码,仅做配置管理 | |

实际开发中,父工程通常同时承担 "继承" 和 "聚合" 的角色(如 xxx-parent 既是父工程,也是聚合工程),这样既能统一管理依赖,又能一键构建所有模块。

三、私服:解决团队内部资源共享与同步

分模块开发后,模块如何在团队内部共享?比如 A 团队开发的xxx-utils模块,B 团队想使用,直接复制代码会导致版本不一致,上传到中央仓库又无权限(中央仓库仅接受开源项目)。Maven 私服可解决这一问题。

3.1 私服的核心概念与作用

3.1.1 什么是私服?

私服是架设在企业局域网内的 "私有 Maven 仓库",本质是 "中央仓库的代理"+"团队内部资源库":

  • 代理中央仓库:当本地仓库没有依赖时,先从私服下载;私服没有则自动从中央仓库下载,缓存到私服,下次其他团队成员可直接从私服获取。
  • 存储内部资源 :团队开发的模块(如xxx-utils)可上传到私服,其他团队通过依赖坐标直接引用,无需复制代码。
3.1.2 为什么需要私服?
  • 资源共享安全可控 :内部模块无需上传公网,既能保护代码隐私,又能避免因代码复制导致的版本不一致(如 A 团队更新xxx-utils后,B 团队通过依赖更新即可同步,无需手动替换代码);
  • 提升依赖下载效率:局域网内下载速度远快于外网,尤其在团队成员多、外网不稳定时,可大幅减少依赖等待时间;
  • 规避中央仓库权限限制:公网中央仓库仅允许特定机构上传资源,企业自研的私有模块无法上传,私服则支持团队自主管理上传权限。
3.1.3 依赖查找顺序

Maven 项目引入依赖时,会按以下优先级查找,直至获取依赖:

  1. 本地仓库 :优先查询开发者本地.m2/repository目录;
  2. 私服仓库:本地仓库缺失时,自动请求企业私服;
  3. 中央仓库:私服无该依赖时,由私服代理下载并缓存,供后续使用。

注:企业中通常仅需搭建 1 台私服,开发人员无需自行搭建,掌握配置和使用即可。

3.2 私服仓库分类与版本规范

3.2.1 私服仓库类型

私服默认包含 3 类仓库,各司其职:

  • RELEASE 仓库 :存储功能稳定、停止更新的 "发布版本" 模块(如xxx-utils-1.0.RELEASE.jar),用于生产环境;
  • SNAPSHOT 仓库 :存储处于开发中、需频繁迭代的 "快照版本" 模块(如xxx-utils-1.0-SNAPSHOT.jar),用于测试和开发环境;
  • Central 仓库:代理公网中央仓库,缓存第三方依赖,避免重复从外网获取。
3.2.2 项目版本规范
  • RELEASE 版本 :版本号格式为主版本号.次版本号.修订号(如 1.0.0),表示功能成熟、无重大 bug,对应上传至 RELEASE 仓库;
  • SNAPSHOT 版本 :版本号末尾加-SNAPSHOT(如 1.0.0-SNAPSHOT),表示仍在迭代,对应上传至 SNAPSHOT 仓库。

3.3 私服资源上传与下载实战

3.3.1 核心配置步骤

实现私服资源的上传与下载,需完成 3 步配置,最终执行deploy命令即可:

步骤 1:配置私服访问凭证(settings.xml)

在 Maven 安装目录的conf/settings.xml中,添加私服的用户名和密码(由管理员提供,默认常为admin/admin):

xml

复制代码
<servers>
    <!-- RELEASE仓库访问凭证 -->
    <server>
        <id>maven-releases</id>
        <username>admin</username>
        <password>admin</password>
    </server>
    <!-- SNAPSHOT仓库访问凭证 -->
    <server>
        <id>maven-snapshots</id>
        <username>admin</username>
        <password>admin</password>
    </server>
</servers>

注:id需与后续项目 pom.xml 中的仓库 ID 保持一致,否则无法匹配权限。

步骤 2:配置私服下载地址(settings.xml)

同样在settings.xml中,配置镜像和仓库权限,让 Maven 优先从私服下载依赖:

xml

复制代码
<!-- 镜像:所有依赖请求转发到私服 -->
<mirrors>
    <mirror>
        <id>maven-public</id>
        <mirrorOf>*</mirrorOf>
        <url>http://localhost:8081/repository/maven-public/</url> <!-- 私服公共仓库地址 -->
    </mirror>
</mirrors>

<!-- 允许下载RELEASE和SNAPSHOT版本 -->
<profiles>
    <profile>
        <id>allow-snapshots</id>
        <activation>
            <activeByDefault>true</activeByDefault> <!-- 默认激活 -->
        </activation>
        <repositories>
            <repository>
                <id>maven-public</id>
                <url>http://localhost:8081/repository/maven-public/</url>
                <releases><enabled>true</enabled></releases>
                <snapshots><enabled>true</enabled></snapshots>
            </repository>
        </repositories>
    </profile>
</profiles>
步骤 3:配置项目上传地址(pom.xml)

在父工程 pom.xml 中,添加distributionManagement标签,指定不同版本的上传路径:

xml

复制代码
<distributionManagement>
    <!-- RELEASE版本上传地址 -->
    <repository>
        <id>maven-releases</id> <!-- 与settings.xml中server的id一致 -->
        <url>http://localhost:8081/repository/maven-releases/</url>
    </repository>
    <!-- SNAPSHOT版本上传地址 -->
    <snapshotRepository>
        <id>maven-snapshots</id> <!-- 与settings.xml中server的id一致 -->
        <url>http://localhost:8081/repository/maven-snapshots/</url>
    </snapshotRepository>
</distributionManagement>
3.3.2 执行上传与下载
  • 资源上传 :在父工程根目录执行mvn clean deploy,Maven 会自动根据版本类型(RELEASE/SNAPSHOT)上传至对应仓库,可通过私服管理界面(如http://localhost:8081)查看;
  • 资源下载:其他项目组需使用时,直接在 pom.xml 中引入依赖坐标,Maven 会按 "本地→私服→中央仓库" 顺序自动下载。

示例:引入私服中的xxx-utils模块

xml

复制代码
<dependency>
    <groupId>com.xxx</groupId>
    <artifactId>xxx-utils</artifactId>
    <version>1.0-SNAPSHOT</version> <!-- 版本需与私服一致 -->
</dependency>

3.4 关键注意事项

  1. 地址与 ID 一致性 :确保settings.xmlpom.xml中的私服地址、仓库 ID 完全匹配,否则会出现 "权限拒绝" 或 "连接失败";
  2. 版本规范使用:禁止将 SNAPSHOT 版本上传至 RELEASE 仓库,避免影响生产环境稳定性;
  3. 企业环境适配 :真实开发中,私服部署在远程服务器,需将配置中的localhost替换为实际 IP / 域名,并确保开发环境可访问该服务器;
  4. 依赖冲突处理 :若私服存在多版本依赖,优先使用项目指定版本,或通过父工程dependencyManagement统一锁定版本。
相关推荐
振鹏Dong5 分钟前
Spring事务管理机制深度解析:从JDBC基础到Spring高级实现
java·后端·spring
信码由缰11 分钟前
Java包装类:你需要掌握的核心要点
java
wanzhong233319 分钟前
ArcGIS学习-12 实战-综合案例
学习·arcgis
小凯 ོ1 小时前
实战原型模式案例
java·后端·设计模式·原型模式
Dcs1 小时前
性能提升超100%!PostgreSQL主键选择大变革:UUIDv7能否终结v4的统治?
java
渣哥1 小时前
没有 Optional,Java 程序员每天都在和 NullPointerException 打架
java
智_永无止境1 小时前
Java集合操作:Apache Commons Collections4启示录
java·apache
悟能不能悟2 小时前
java去图片水印的方法
java·人工智能·python
diablobaal2 小时前
云计算学习100天-第32天
学习·云计算