3. 项目结构搭建:Maven/Gradle项目结构、模块划分、包命名规范、配置文件管理

好,咱们进入第三章。这一章我打算聊聊项目结构。你可能觉得这有什么好讲的?不就是建几个文件夹嘛。嗯,我当年也这么想,直到在一个大型微服务项目里,因为结构混乱,找配置文件找了整整一下午……从那以后,我对项目结构就特别较真。

说白了,项目结构就是代码的骨架。骨架歪了,后面长出来的肉(业务代码)肯定也歪。咱们今天就把Maven和Gradle这两种主流构建工具的项目结构、模块划分、包命名和配置文件管理,一次性说清楚。

3.1 Maven项目结构:约定优于配置

Maven最核心的思想就是“约定优于配置”。什么意思?就是它规定好了你的代码该放哪,你照着做就行,不用自己瞎折腾。我个人习惯,只要是Java后端项目,首选Maven标准结构。

一个标准的Maven项目长这样:

my-project/
├── pom.xml
├── src/
│   ├── main/
│   │   ├── java/          # 主代码
│   │   ├── resources/     # 配置文件
│   │   └── webapp/        # Web资源(可选)
│   └── test/
│       ├── java/          # 测试代码
│       └── resources/     # 测试配置文件
└── target/                # 编译输出目录(自动生成)

这里有个坑,我提醒一下。很多新手会把配置文件乱放,比如把数据库连接配置扔到src/main/java里。千万别!java目录只放.java文件,配置文件一律进resources。我曾经在一个项目里看到有人把application.yml放在java目录下,结果打包后死活找不到配置……

注意:Maven的target目录是编译产物,不要提交到版本控制。记得在.gitignore里加上target/。

3.2 Gradle项目结构:灵活但要有规矩

Gradle比Maven灵活,但灵活过头就容易乱。我见过有的团队用Gradle,每个模块的构建脚本写得五花八门,最后维护成本比Maven还高。

Gradle的标准结构其实和Maven很像:

my-project/
├── build.gradle           # 构建脚本
├── settings.gradle        # 项目设置
├── gradle.properties      # 属性配置
├── src/
│   ├── main/
│   │   ├── java/
│   │   └── resources/
│   └── test/
│       ├── java/
│       └── resources/
└── build/                 # 编译输出目录

Gradle有个好处,就是可以用Kotlin DSL写构建脚本。我个人比较推荐,因为类型安全,写起来不容易出错。不过如果你团队里都是Java老手,Groovy DSL也完全够用。

小技巧:Gradle的settings.gradle里可以配置项目名称和模块列表。我习惯把项目名和Git仓库名保持一致,这样CI/CD配置起来省事。

3.3 模块划分:别让一个项目变成“大泥球”

模块划分,说白了就是怎么切分你的代码。我见过最夸张的项目,一个模块里塞了200多个类,从数据库访问到前端渲染全在一个包里。这种项目,维护起来简直噩梦。

我的经验是,模块划分要遵循几个原则:

  • 单一职责:每个模块只做一件事。比如用户模块只管用户,订单模块只管订单。
  • 依赖方向:依赖关系要单向,不能循环依赖。我曾经在一个项目里,A模块依赖B,B又依赖A,结果编译都过不去……
  • 可独立部署:每个模块最好能独立打包和部署,这样微服务化的时候直接拆出去就行。

一个典型的多模块Maven项目结构:

my-platform/
├── pom.xml                # 父POM
├── my-platform-common/    # 公共模块
│   └── pom.xml
├── my-platform-user/      # 用户模块
│   └── pom.xml
├── my-platform-order/     # 订单模块
│   └── pom.xml
└── my-platform-gateway/   # 网关模块
    └── pom.xml

父POM里统一管理依赖版本:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.7.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
核心要点:模块划分不是越细越好。我见过一个项目分了30多个模块,结果每次改个接口都要改5个模块的代码。适度拆分,够用就行。

3.4 包命名规范:从域名到代码的映射

包命名,说白了就是给你的代码起个“身份证”。Java里包名通常用公司域名的倒序开头,比如com.example.project。这个大家应该都知道,我就不多说了。

我想重点说的是,包名内部的层次怎么设计。我的习惯是:

  • 按功能分层:controller、service、repository、model
  • 按业务模块:user、order、payment
  • 两者结合:先按业务模块,再按功能分层

举个例子:

com.example.platform
├── user
│   ├── controller
│   ├── service
│   ├── repository
│   └── model
├── order
│   ├── controller
│   ├── service
│   ├── repository
│   └── model
└── common
    ├── config
    ├── util
    └── exception

这种结构的好处是,每个业务模块自成一体,找代码特别快。我当年在一个项目里,所有代码都堆在com.example.controller、com.example.service这种平铺结构里,找用户相关的代码得翻半天……

避坑指南:包名不要用复数,比如com.example.users。Java社区惯例用单数。另外,包名里不要有下划线或大写字母,全小写。

3.5 配置文件管理:环境分离与敏感信息保护

配置文件管理,这是个大话题。我见过太多项目把数据库密码、直接写在配置文件里,然后提交到Git仓库。嗯,后果可想而知。

我的做法是:

  1. 环境分离:每个环境(开发、测试、生产)有独立的配置文件
  2. 敏感信息外部化:密码、密钥等通过环境变量或配置中心注入
  3. 配置模板化:提交到Git的是模板文件,实际值由CI/CD替换

Spring Boot项目里,我习惯这样组织配置文件:

src/main/resources/
├── application.yml              # 公共配置
├── application-dev.yml          # 开发环境
├── application-test.yml         # 测试环境
└── application-prod.yml         # 生产环境

在application.yml里指定激活哪个环境:

spring:
  profiles:
    active: dev

对于敏感信息,比如数据库密码,我建议用环境变量:

spring:
  datasource:
    url: ${DB_URL}
    username: ${DB_USER}
    password: ${DB_PASSWORD}

然后在部署时通过环境变量传入。这样就算代码泄露,密码也不会暴露。

个人经验:我习惯在项目根目录放一个.env.example文件,里面列出所有需要的环境变量和说明。这样新同事来了,照着这个文件配置就行,不用到处问。

3.6 知识结构图:项目搭建全景

下面这张图,是我对项目结构搭建的整体理解。你可以把它当作一个检查清单,每次新建项目时对照着来。

项目结构搭建 构建工具选择 Maven:约定优于配置 Gradle:灵活可定制 模块划分 单一职责原则 依赖方向单向 可独立部署 包命名规范 域名倒序开头 业务+功能分层 全小写无下划线 配置文件管理 环境分离(dev/test/prod) 敏感信息外部化(环境变量)

这张图把项目结构搭建的四个核心维度串起来了。你新建项目时,按这个顺序走一遍,基本不会出大问题。

3.7 总结

项目结构搭建,说白了就是定规矩。规矩定好了,团队协作就顺畅,代码维护就轻松。我见过太多项目,前期图省事随便建个结构,后期改得痛不欲生。

最后送你一句话:项目结构不是写出来的,是设计出来的。花点时间在设计上,后面能省十倍的时间。

本章核心要点:
  • Maven用标准结构,Gradle保持一致性
  • 模块划分遵循单一职责和单向依赖
  • 包名用域名倒序+业务+功能分层
  • 配置文件环境分离,敏感信息用环境变量