当前位置: 首页 > news >正文

从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-pojopom.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-utilspom.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. 删除原工程中已拆分的pojoutils包(避免冲突)。
  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统一锁定版本。
http://www.dtcms.com/a/355438.html

相关文章:

  • Python Imaging Library (PIL) 全面指南:PIL基础入门-图像滤波与处理技术
  • python自动化测试工具selenium使用指南
  • AS32S601抗辐照MCU在商业卫星EDFA系统中的应用研究
  • 基于 Selenium 和 BeautifulSoup 的动态网页爬虫:一次对百度地图 POI 数据的深度模块化剖析
  • 033 日志
  • 硬件三人行--运算基础篇
  • 怎样将Word转成高质量的DITA
  • 【涂鸦T5】1. 环境搭建和demo
  • 量化策略布林带解读
  • Java Spring(1)- Spring基础
  • AI提升SEO关键词效果新策略
  • PostgreSQL【应用 04】加解密扩展 pgcrypto 使用实例(加密、导出、导入、解密流程说明)
  • 信息技术发展
  • Flink Redis广播方案
  • 深度学习④【经典卷积神经网络演进:从LeNet到ResNet(重要意义)的架构革命】
  • Uniapp中自定义导航栏
  • 使用qianjkun uniapp 主应用 集成 vue微应用
  • Android 使用MediaMuxer+MediaCodec编码MP4视频
  • 把 AI 塞进「智能手环」——基于心率变异的零样本压力监测手环
  • sqlserver: count(*)
  • TCP和HTTP的keep-alive的区别
  • 嵌入式第四十天(TCP并发服务端(IO多路复用))
  • 【Python 入门】(1)Python 语言基础(语法特点)
  • OSI模型和TCP/IP模型区别是什么
  • JAVA全栈Redis篇————Redis常用数据类型概述
  • 如何快速copy复制一个网站,或是将网站本地静态化访问
  • 电力电子中的变压器原理、作用、选型与测量指南-超简单解读
  • 雷达传感器和红外传感器的区别
  • MCP tutorials
  • HOOPS Communicator 2025.6.0更新发布:WebViewer UI全面进化,BIM支持再升级