文档站点
Skip to content

目录结构(对比 Laravel) ​

Laravel 用 app/Http/Controllers、routes/、resources/views/ 等目录按「职责」切分;Spring Boot 只用 Maven 标准目录 + 自建包(package)。最大的心智差异是:Laravel 按「文件类型」组织,Java 按「业务模块」组织。

Maven 标准目录 ​

一个 Spring Boot 项目(Maven 构建)的物理目录是固定的:

demo/
├── pom.xml
├── mvnw
└── src/
    ├── main/
    │   ├── java/          ← Java 源码(全部 .java 都在这里)
    │   │   └── com/example/demo/
    │   └── resources/     ← 非代码资源:配置文件、静态资源、模板
    │       ├── application.yml
    │       ├── static/    ← 相当于 Laravel 的 public/(CSS、JS、图片)
    │       └── templates/ ← 模板文件(Thymeleaf 等)
    └── test/
        └── java/          ← 测试代码,与 main 对应

关键点:

  • 所有 Java 代码都在 src/main/java 下,没有 app/、routes/、config/ 这些顶层目录的区分
  • src/main/resources 相当于「杂项资源区」:application.yml(配置)、static/(静态文件)、templates/(服务端模板)
  • 没有 routes/web.php —— 路由用注解直接写在控制器上

包(package)才是模块化的单元 ​

com/example/demo 这种层层嵌套的目录,对应 Java 的包(package)。包名的规范写法是「域名倒序」:com.example.demo。

包有两个作用,和 PHP 的命名空间对应:

PHPJava
命名空间 App\Models\User包 + 类 com.example.demo.domain.User
use App\Models\User;import com.example.demo.domain.User;
namespace App\Models;package com.example.demo.domain;

注意区分

PHP 的命名空间只是「逻辑名」,不强制对应目录;但 Java 的包名必须对应目录。com.example.demo.domain.User 这个类,就必须放在 src/main/java/com/example/demo/domain/User.java。

一个真实的 Spring Boot 包结构(对比 Laravel) ​

假设做一个「文章」功能,Laravel 的项目会这样组织:

app/
├── Http/Controllers/PostController.php
├── Models/Post.php
├── Services/PostService.php
├── Http/Requests/StorePostRequest.php
└── Http/Resources/PostResource.php

Spring Boot 的常见做法是按业务模块建包,每个模块内部再分角色:

com/example/blog/
├── BlogApplication.java        ← 入口
├── config/                     ← 本模块的配置类
├── post/
│   ├── Post.java               ← 实体(对应 Model)
│   ├── PostController.java     ← 控制器
│   ├── PostService.java        ← 业务逻辑
│   ├── PostRepository.java     ← 数据访问接口(对应 Repository/DAO)
│   ├── PostDto.java            ← 请求/响应数据传输对象(对应 FormRequest / Resource)
│   └── PostNotFoundException.java  ← 模块内自定义异常
└── common/                     ← 跨模块的通用代码
    ├── ApiResponse.java
    └── GlobalExceptionHandler.java

两种组织方式的对比:

维度Laravel(按类型)Spring Boot(按模块)
找「帖子的控制器」去 app/Http/Controllers/ 找 PostController去 post/ 包找 PostController
加一个新功能「评论」在 5 个顶层目录各加一个文件新建一个 comment/ 包,5 个类放一起
模块间边界靠命名空间约定靠包结构 + 访问修饰符(public/package-private)硬约束

为什么这样设计?

Java 的包不光是「分类」,还控制可见性:不加 public 的类只在同包可见。模块内的类对外隐藏,模块间的依赖只能走 public 接口 —— 编译器强制你遵守边界,这比 PHP 的「约定」更硬。 更深入的原因和做法,见专题文章 模块化:包结构与模块划分。

入口类、实体、配置文件的准确位置 ​

概念位置
程序入口 XxxApplicationsrc/main/java/<包>/ 的最外层
实体 / 控制器 / 服务各自模块包内
application.ymlsrc/main/resources/
静态资源(CSS/JS)src/main/resources/static/
测试代码src/test/java/(包结构与 main 镜像对应)

入口类的位置很讲究

@SpringBootApplication 入口类必须放在所有包的最外层,因为 Spring Boot 默认扫描「入口类所在包及其子包」。把它放错位置会导致扫描不到任何组件,启动即报错。这也是很多新手第一个坑。

与 Go 的模块化对比(顺带一提) ​

如果你也写过 Go:Go 用 module + package,一个目录就是一个包,跨包访问靠 go mod 导入 —— 这其实和 Java 的「包 = 目录 = 模块」几乎是同一套思想,只是 Java 多了「访问修饰符」这道硬约束。

面向 PHP / Laravel 开发者的 Spring Boot 中文文档