乐途乐途
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
  • 学习路径
  • 第1章 介绍与核心概念

    • Maven是什么
    • 约定优于配置
  • 第2章 安装与配置

    • 安装与验证
    • settings.xml
    • 本地仓库与镜像
  • 第3章 POM与项目坐标

    • POM
    • GAV坐标
    • packaging
  • 第4章 标准目录布局

    • 标准目录布局
  • 第5章 依赖机制

    • dependencies
    • scope
    • 依赖传递
    • 依赖冲突与调解
    • exclusions
    • optional
    • dependencyManagement
  • 第6章 仓库

    • 仓库体系
    • 本地仓库
    • 远程仓库与镜像
    • 私服
  • 第7章 构建生命周期

    • 生命周期概述
    • clean 生命周期
    • default 生命周期
    • site 生命周期
    • 生命周期与插件绑定
  • 第8章 插件

    • 插件概述
    • maven-compiler-plugin
    • maven-surefire-plugin
    • maven-war-plugin
  • 第9章 继承与聚合

    • parent继承
    • 聚合
    • BOM
    • properties
  • 第10章 属性与资源过滤

    • 资源过滤
    • Profile
  • 第11章 常用命令

    • mvn compile
    • mvn test
    • mvn package
    • mvn clean
    • mvn install
    • mvn dependency:tree
  • 第12章 常见问题与最佳实践

    • 依赖冲突排查
    • 最佳实践

标准目录布局

本章承接"约定优于配置",将抽象的哲学落地为具体的目录结构。理解 Maven 的标准目录布局,是正确放置代码、资源、测试和构建产物的先决条件,也是团队协作时"无需解释"的默契基础。


核心机制

Maven 为项目定义了一套默认的目录结构,使得任何熟悉 Maven 的开发者都能立即知道去哪里找源代码、测试、资源和构建输出。

这句话的潜台词是:目录结构本身就是一种"接口"。当你说"这是一个 Maven 项目",就等于承诺了"源代码在 src/main/java,测试在 src/test/java,构建产物在 target/"。任何懂 Maven 的人不需要阅读你的 README 就能定位一切。

标准目录结构全貌

Maven 的目录约定不是随意制定的,它反映了 Java 项目从开发到交付的完整生命周期:

my-project/
├── pom.xml                          # 项目核心配置
├── src/
│   ├── main/
│   │   ├── java/                    # 主源代码(.java 文件)
│   │   ├── resources/               # 主资源文件(配置文件、静态资源)
│   │   ├── filters/                 # 资源过滤配置文件
│   │   ├── webapp/                  # Web 项目专属(WEB-INF、静态页面)
│   │   └── assembly/                # 装配描述符(高级)
│   ├── test/
│   │   ├── java/                    # 测试源代码
│   │   ├── resources/               # 测试资源文件
│   │   └── filters/                 # 测试资源过滤配置
│   └── site/                        # 项目文档站点源文件
├── target/                          # 构建输出目录(自动生成)
│   ├── classes/                     # 编译后的主类文件
│   ├── test-classes/                # 编译后的测试类文件
│   ├── surefire-reports/            # 测试报告
│   ├── my-project-1.0.0.jar         # 打包产物
│   └── generated-sources/           # 插件生成的源代码
└── .mvn/                            # Maven 包装器配置(可选)

目录用途对照表

目录路径存放内容生命周期阶段是否参与打包
src/main/java主业务逻辑源代码compile是
src/main/resources主配置文件(Spring、MyBatis、日志配置等)process-resources是
src/main/webappWeb 应用静态资源(HTML、JS、WEB-INF)package是(WAR)
src/test/java单元测试、集成测试代码test-compile否
src/test/resources测试专用配置(如 H2 内存数据库配置)process-test-resources否
target/classes编译后的 .class 文件和复制后的资源compile中间产物
target/test-classes编译后的测试类test-compile中间产物
target/surefire-reports测试执行报告(XML/HTML)test否
target/*.jar / *.war最终打包产物package最终交付物

约定优于配置的体现

Maven 的目录约定直接决定了生命周期的默认行为:

  1. mvn compile 默认编译 src/main/java → 输出到 target/classes
  2. mvn test-compile 默认编译 src/test/java → 输出到 target/test-classes
  3. mvn test 默认运行 target/test-classes 中的 JUnit 测试
  4. mvn package 默认将 target/classes 和 src/main/resources 打入 JAR/WAR

你不需要在 pom.xml 里写"编译哪个目录",因为 Maven 已经知道。

与 Ant 时代自定义目录的对比

维度Ant 时代(自定义目录)Maven 时代(标准目录)
目录命名各项目不同:source/、code/、java/统一:src/main/java
构建脚本每个 build.xml 都要声明源码路径pom.xml 无需声明
新成员上手需要阅读文档或询问"代码放哪"一眼就知道
工具兼容性IDE、CI 工具需要单独配置路径开箱即用
插件兼容性自定义路径导致插件找不到文件标准路径,插件默认生效

生活类比:图书馆的图书分类法

想象你走进一座图书馆:

  • Ant 时代的图书馆:每座图书馆都有自己的分类法。A 馆把小说放在一楼,B 馆把小说放在三楼;A 馆用"作者名"排序,B 馆用"出版年份"排序。你每去一座新馆,都要先花半小时学习它的规则。
  • Maven 时代的图书馆:全球统一——文学类在 A 区,科技类在 B 区,期刊在 C 区,每区内部按"中图法"编号排列。你只需学习一次,到了任何城市的图书馆都能直接找到书。

Maven 的标准目录就是这套"全球统一的图书分类法"。


图示

上图展示了 Maven 目录结构的数据流向:源代码层的内容经过编译、测试、打包三个阶段,最终流向构建输出层的产物。这个流向是固定的、可预期的,不需要任何额外配置。


完整示例

场景

飞翔科技正在开发一个员工管理系统 employee-system。CTO 大翔要求项目必须严格遵循 Maven 标准目录,方便后续微服务拆分。架构师白歌负责搭建项目骨架,后端小崔负责业务代码,前端黄俪负责页面资源,运维李眉负责部署脚本。

操作前:混乱的目录实验

白歌先做了一个"反例实验",故意打破约定,让小崔体验后果:

employee-system-bad/
├── pom.xml
├── code/                          # ❌ 自定义:不叫 src,叫 code
│   ├── src/                       # 主代码
│   │   └── com/feixiang/...
│   ├── config/                    # ❌ 自定义:不叫 resources,叫 config
│   │   └── application.yml
│   └── test/                      # ❌ 自定义:测试和主代码混在一起
│       └── com/feixiang/...
├── web/                           # ❌ 自定义:静态资源放在 web/
│   └── index.html
└── output/                        # ❌ 自定义:构建输出叫 output

对应的 pom.xml 被迫写满自定义路径:

<build>
    <sourceDirectory>code/src</sourceDirectory>
    <testSourceDirectory>code/test</testSourceDirectory>
    <resources>
        <resource>
            <directory>code/config</directory>
        </resource>
    </resources>
    <directory>output</directory>
</build>

后果:

  • 小崔从其他 Maven 项目转过来,找不到 src/main/java,一脸茫然
  • 黄俪的 HTML 文件放在 web/,mvn package 时没有被自动打入 WAR,需要额外配置
  • 李眉写 Jenkins 脚本时,发现构建产物不在 target/,而是散落在 output/,脚本失效
  • maven-javadoc-plugin 默认去 src/main/java 找代码,找不到,构建报错

操作后:标准目录布局

白歌重新创建标准结构:

employee-system/
├── pom.xml
├── src/
│   ├── main/
│   │   ├── java/                  # ✅ 小崔的业务代码
│   │   │   └── com/feixiang/employee/
│   │   │       ├── controller/
│   │   │       ├── service/
│   │   │       └── dao/
│   │   ├── resources/             # ✅ 配置文件
│   │   │   ├── application.yml
│   │   │   └── logback.xml
│   │   └── webapp/                # ✅ 黄俪的前端页面(Web 项目)
│   │       ├── WEB-INF/
│   │       └── index.html
│   └── test/
│       ├── java/                  # ✅ 单元测试
│       │   └── com/feixiang/employee/
│       │       └── EmployeeServiceTest.java
│       └── resources/             # ✅ 测试专用配置
│           └── application-test.yml
└── target/                        # ✅ 自动生成,李眉的部署脚本直接取这里
    ├── classes/
    ├── test-classes/
    ├── surefire-reports/
    └── employee-system-1.0.0.war

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>

    <groupId>com.feixiang</groupId>
    <artifactId>employee-system</artifactId>
    <version>1.0.0</version>
    <packaging>war</packaging>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.7.0</version>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.8.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

变化分析:

  • 小崔入职第一天,看到 src/main/java 就知道业务代码在哪,看到 src/test/java 就知道测试在哪
  • 黄俪的 webapp/ 内容被 maven-war-plugin 自动打包进 WAR,无需额外配置
  • 李眉的 Jenkins 脚本直接取 target/employee-system-1.0.0.war,脚本通用于所有 Maven 项目
  • mvn javadoc:javadoc 自动找到 src/main/java,生成 API 文档

易错点与常见问题

误区一:target/ 目录应该提交到版本控制

错误认知:"target/ 里有构建产物,我应该把它提交到 Git,方便同事直接下载。"

纠正:target/ 是纯生成目录,里面的内容全部由 Maven 从 src/ 和 pom.xml 推导生成。提交它会导致:

  • 仓库体积膨胀(JAR 文件通常几十 MB)
  • 合并冲突频发(.class 文件是二进制,Git 无法智能合并)
  • 不同环境产物混杂(Windows 和 Linux 编译的 .class 可能有差异)

正确做法:在 .gitignore 中写入 target/。

误区二:src/main/resources 和 src/test/resources 可以混用

错误认知:"我把所有配置文件放在 src/main/resources,测试时也能读到,省事。"

纠正:src/test/resources 中的文件只在测试时可见,且会覆盖 src/main/resources 中的同名文件。这是隔离测试环境的关键机制。例如:

  • src/main/resources/application.yml 配置生产数据库 MySQL
  • src/test/resources/application.yml 配置内存数据库 H2

如果混用,测试可能意外连接生产数据库,导致数据污染。

误区三:标准目录只适用于简单项目

错误认知:"我的项目有 50 个模块,标准目录不够用,必须自定义。"

纠正:Maven 的多模块项目(Multi-Module Project)正是通过每个模块内部遵循标准目录来实现统一的。父项目只负责聚合,子模块各自拥有完整的 src/main/java、src/test/java 和 target/。50 个模块意味着 50 套标准目录,而不是 50 套自定义目录。这是 Maven 管理大型代码库的核心能力。


小结

Maven 的标准目录布局是"约定优于配置"最直接的体现。它将源代码、资源、测试、构建产物固定在可预期的位置,使得任何熟悉 Maven 的开发者都能零成本上手新项目。与 Ant 时代的自定义目录相比,标准目录带来了团队协作效率、工具链兼容性和插件开箱即用的三重收益。

本章与全局的关系:本章回答了"代码应该放在哪里"。下一章"依赖机制"将回答"项目需要什么外部库、如何声明它们"——这是 pom.xml 最核心的功能之一。