ElIauk

Spring Boot 项目创建与目录结构

用 Initializr 起步 2022 年新建 Spring Boot 项目,最省事的方式是打开 start.spring.io:构建工具选 Maven,语言 Java,Spring Boot 选 2.7.x,JDK 选 8、11 或 17(Spring Boot 3.0 要求 JDK 17,学习

评论
Spring Boot 项目创建与目录结构

用 Initializr 起步

2022 年新建 Spring Boot 项目,最省事的方式是打开 start.spring.io:构建工具选 Maven,语言 Java,Spring Boot 选 2.7.x,JDK 选 8、11 或 17(Spring Boot 3.0 要求 JDK 17,学习阶段建议直接上 17)。依赖勾选 Spring Web,需要数据库再加 MySQL Driver 和 MyBatis Framework,然后生成压缩包解压导入 IDEA。

不推荐从空 Maven 项目手写依赖,版本、插件、目录都要自己配,新手很容易在第一步就卡住。Initializr 生成的项目是可以直接运行的。

pom.xml 里有什么

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.0</version>
    <relativePath/>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

关键点有两个:parent 负责统一管理依赖版本,所以 starter-web 不需要写 version;spring-boot-maven-plugin 负责把项目打成可执行的 fat jar,少了它,java -jar 会提示“没有主清单属性”。

spring-boot-starter-web 会带进 Spring MVC、Jackson 和内嵌 Tomcat,一个依赖就把 Web 开发需要的东西凑齐了。starter 的本质是“依赖集合”,看到不用怕,展开依赖树就知道它引了什么。

依赖不写版本,是因为父 POM 的 dependencyManagement 已经管好了。手动再写一个版本,等于绕过统一管理,很容易和 Spring 的版本对不上。要升级就整体升级 Spring Boot,不要单点改某个 starter。

spring-boot-maven-plugin 除了打 fat jar,还提供 spring-boot:run 命令,开发时可以不打包直接启动。CI 里一般用 package,本地调试用 run。

第一次打开项目时等 Maven 依赖下载完再运行,右下角的进度条没结束就点运行,容易看到一堆“找不到类”的红字。

目录结构与分层

路径 作用
src/main/java 业务代码
src/main/resources/application.yml 主配置文件
src/main/resources/static 静态资源,如 css、js
src/main/resources/templates 模板文件,如 Thymeleaf
src/test/java 测试代码
target 编译产物,不要提交到 Git

包结构上,小项目按职责分就够了:

com.example.demo
├── DemoApplication.java      # 启动类,放在最外层
├── controller                # 接收请求、参数校验
├── service                   # 业务逻辑
│   └── impl
├── mapper                    # 数据库访问
├── entity                    # 数据库映射对象
├── dto                       # 接口出入参
└── config                    # 配置类

业务复杂之后可以再按模块拆包,但一开始不要为了“架构感”拆出十几个空包。分层的目的在于明确职责,并非为了让目录看起来更高级。

resources 目录下还会遇到 application-dev.yml、logback-spring.xml、mapper 等文件,它们最终都会被打进 classpath。放错层级(比如在 resources 下又建了一层 src)是新手常见问题,表现是打包后运行时找不到配置。

启动类为什么必须放最外层

@SpringBootApplication 是一个组合注解,里面包含 @ComponentScan,默认只扫描启动类所在包及其子包。启动类放在 com.example.demo 下,com.example.demo.controller 才会被扫到;如果把它放到 com.example.demo.web 里,同级或上级的 Service、Controller 都不会被注册,表现就是接口 404、注入报“找不到 Bean”。

这也是很多人从教程复制代码后跑不起来的常见原因:包名和教程不一样,但启动类位置照抄了。

常见坑

1. Controller 没被扫描到

除了包位置,还要确认类上加了 @RestController 或 @Controller。只写 @RequestMapping 不加控制器注解,Spring 不会把它当 Bean。

2. 端口被占用

启动日志里出现 Port 8080 was already in use,要么改 server.port=8081,要么找到占用进程杀掉。Windows 用 netstat -ano | findstr 8080,Linux 用 ss -lntp | grep 8080。

3. 配置文件放错位置

application.yml 必须放在 src/main/resources 根目录,名字也要对。config/application.yml 在 classpath 下也能识别,但新手阶段统一放根目录最不容易出错。

4. 自己乱写依赖版本

父 POM 已经管好了 Spring 相关依赖的版本,再手动指定一个不兼容的版本,很容易出现 NoSuchMethodError。要升级就整体升级 Spring Boot 版本,不要单点改某个 starter。

5. 打包后启动找不到主类

多模块项目里,spring-boot-maven-plugin 要配在真正可启动的模块上,并确认 mainClass 指向正确。单模块项目一般不用配,插件会自动找带 main 方法的类。

排查步骤

  1. mvn clean package 确认能成功打出 jar;
  2. java -jar target/demo-0.0.1-SNAPSHOT.jar 启动,观察 banner 和端口;
  3. 访问 http://localhost:8080,确认没有 404 或连接拒绝;
  4. 加 --debug 启动,查看自动配置报告里哪些配置生效、哪些没生效;
  5. 接口 404 时先看启动日志有没有 Mapped "{[/xxx]}",没有就是没扫描到。

参考

评论

推荐阅读

订阅邮件

订阅更新,及时收到最新文章。

作者