【前端转全栈java速通课】 项目实战④-1 Spring Boot 创建项目-定义接口-请求参数处理-分层规范-依赖注入

1. 什么是 Spring Boot

Spring Boot 是 Spring 家族中用于简化 Spring 应用搭建与开发的框架。它基于「约定优于配置」的理念,通过自动配置(Auto-Configuration)和起步依赖(Starter)大幅减少繁琐的 XML 配置,让开发者可以快速创建独立运行的、生产级别的 Spring 应用。

1.1 Spring Boot 的核心特性

  • 自动配置:根据项目引入的依赖自动装配 Bean,无需手动编写大量配置。
  • 起步依赖(Starter) :将常用功能打包成统一的依赖,如 spring-boot-starter-web,一条依赖即可引入 Web 开发所需组件。
  • 内嵌服务器 :默认内嵌 Tomcat、Jetty 或 Undertow,无需单独部署 WAR 包,java -jar 即可运行。
  • 生产就绪:提供健康检查、指标监控等 Actuator 能力,方便运维。
  • 无代码生成与 XML :无需生成样板代码,也无需繁琐的 XML 配置。

1.2 Spring Boot 与 Spring 的关系

Spring Boot 并不是替代 Spring 的新框架,而是建立在 Spring 之上、简化 Spring 使用的工具。它依然使用 Spring 的 IOC 容器和 AOP 等核心能力,只是把「如何配置」这件事变得更简单。

2. 环境准备

在创建项目之前,需要先准备好以下环境:

工具 版本要求 说明
JDK 8 及以上(推荐 17) Spring Boot 3.x 要求 JDK 17+
Maven 3.6+ 或使用 Maven Wrapper 项目构建与依赖管理
IDE IntelliJ IDEA / Eclipse / VS Code 开发工具,推荐 IDEA

提示:Spring Boot 2.7.x 支持 JDK 8,Spring Boot 3.x 最低要求 JDK 17。建议新项目直接使用 Spring Boot 3.x + JDK 17。

3. 创建 Spring Boot 项目

创建 Spring Boot 项目有多种方式,下面介绍最常用的三种。

3.1 方式一:使用 Spring Initializr 网页创建

  1. 打开 Spring Initializr。
  2. 选择构建工具(Maven/Gradle)、语言(Java/Kotlin/Groovy)和 Spring Boot 版本。
  3. 填写项目坐标(Group、Artifact、Name 等)。
  4. 添加依赖,例如 Spring Web。
  5. 点击 Generate 下载项目压缩包,解压后用 IDE 打开即可。

3.2 方式二:使用 IDEA 内置创建

  1. 打开 IntelliJ IDEA,选择 New Project。
  2. 左侧选择 Spring Initializr。
  3. 填写项目信息,选择 Spring Boot 版本和依赖。
  4. 点击 Finish,IDEA 会自动下载依赖并创建项目结构。

3.3 方式三:使用 Maven 命令行创建

bash 复制代码
mvn archetype:generate -DgroupId=com.example \
  -DartifactId=demo \
  -DarchetypeArtifactId=maven-archetype-quickstart \
  -DinteractiveMode=false

创建完成后,手动在 pom.xml 中加入 Spring Boot 父工程和依赖。

4. 项目结构解析

一个标准的 Spring Boot 项目结构如下:

text 复制代码
demo
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com/example/demo
│   │   │       ├── DemoApplication.java   # 启动类
│   │   │       └── controller
│   │   │           └── HelloController.java
│   │   └── resources
│   │       ├── application.properties     # 配置文件
│   │       ├── static                     # 静态资源
│   │       └── templates                  # 模板文件
│   └── test
│       └── java/com/example/demo
│           └── DemoApplicationTests.java
└── pom.xml

4.1 启动类

@SpringBootApplication 是核心注解,它组合了 @Configuration、@EnableAutoConfiguration 和 @ComponentScan 三个注解的功能。

4.2 常用注解详解

除了 @SpringBootApplication,Spring Boot 开发中还会频繁使用以下注解:

注解 作用 使用位置
@RestController 组合了 @Controller 和 @ResponseBody,直接返回 JSON 数据 类上
@GetMapping / @PostMapping 映射 HTTP GET / POST 请求到处理方法 方法上
@RequestMapping 通用请求映射,可指定 method、path 类或方法上
@Autowired 按类型自动注入依赖 Bean 字段、构造器、Setter
@Service 标记业务层组件,交给 Spring 容器管理 类上
@Repository 标记数据访问层组件(DAO) 类上
@Configuration 声明该类为配置类,可定义 @Bean 类上
@Bean 在配置类中声明一个 Bean 实例 方法上
@Value 注入配置文件中的属性值 字段、方法参数
@PathVariable 获取 URL 路径中的参数 方法参数
@RequestParam 获取请求参数(Query String 或表单) 方法参数
@RequestBody 将请求体 JSON 反序列化为对象 方法参数
4.2.1 常用注解示例
java 复制代码
package com.example.demo.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import com.example.demo.service.UserService;

@RestController
@RequestMapping("/api/users")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/{id}")
    public String getUser(@PathVariable Long id) {
        return userService.getUserById(id);
    }

    @PostMapping
    public String createUser(@RequestBody String userJson) {
        return "created: " + userJson;
    }
}

提示:@RestController 中的方法默认将返回值直接写入 HTTP 响应体(JSON),无需再添加 @ResponseBody。

java 复制代码
package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

@SpringBootApplication 是核心注解,它组合了 @Configuration、@EnableAutoConfiguration 和 @ComponentScan 三个注解的功能。

4.3 编写第一个接口

java 复制代码
package com.example.demo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello, Spring Boot!";
    }
}

4.4 处理请求参数

在实际开发中,接口往往需要接收客户端传来的参数。Spring Boot 提供了多种注解来获取不同类型的请求参数,下面结合示例逐一说明。

4.4.1 使用 @RequestParam 获取查询参数

@RequestParam 用于获取 URL 中的查询参数(Query String)或表单参数,适合 GET 请求。

java 复制代码
package com.example.demo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ParamController {

    @GetMapping("/greet")
    public String greet(@RequestParam String name,
                        @RequestParam(defaultValue = "18") int age) {
        return "Hello, " + name + "! Your age is " + age;
    }
}

访问 http://localhost:8080/greet?name=Tom&age=20,返回 Hello, Tom! Your age is 20。其中 defaultValue 表示参数缺省时的默认值。

4.4.2 使用 @PathVariable 获取路径参数

@PathVariable 用于获取 URL 路径中的参数,适合 RESTful 风格的接口。

java 复制代码
package com.example.demo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @GetMapping("/user/{id}")
    public String getUser(@PathVariable Long id) {
        return "User id: " + id;
    }
}

访问 http://localhost:8080/user/1001,返回 User id: 1001。

4.4.3 使用 @RequestBody 接收 JSON 请求体

@RequestBody 用于将请求体中的 JSON 数据反序列化为 Java 对象,适合 POST 请求。

java 复制代码
package com.example.demo.controller;

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @PostMapping("/user")
    public String createUser(@RequestBody User user) {
        return "Created user: " + user.getName();
    }
}

对应的实体类:

java 复制代码
package com.example.demo.entity;

public class User {

    private Long id;
    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

请求时在 Body 中发送 JSON:

json 复制代码
{
  "id": 1,
  "name": "Tom"
}

返回 Created user: Tom。

提示:使用 @RequestBody 时,请求头需设置 Content-Type: application/json,且实体类需要提供无参构造和 getter/setter 方法。

5. 运行项目

在 IDEA 中直接运行 DemoApplication 的 main 方法,或在项目根目录执行:

bash 复制代码
mvn spring-boot:run

启动成功后,控制台会输出类似以下日志:

text 复制代码
Tomcat started on port(s): 8080 (http)
Started DemoApplication in 2.5 seconds

浏览器访问 http://localhost:8080/hello,即可看到返回的 Hello, Spring Boot!。

6. 常用配置

Spring Boot 的配置文件默认为 src/main/resources/application.properties,也可以使用 application.yml。

properties 复制代码
# 服务端口
server.port=8081

# 应用名称
spring.application.name=demo

7. 总结

本文介绍了 Spring Boot 的核心概念、环境准备以及三种创建项目的方式,并演示了如何编写和运行第一个接口。Spring Boot 通过自动配置和起步依赖,让 Spring 应用的开发变得简单高效,非常适合快速搭建微服务和个人项目。

下一步可以尝试引入 spring-boot-starter-data-jpa 连接数据库,或使用 spring-boot-starter-security 添加安全认证,逐步深入 Spring Boot 生态。

8. 常见问题与排查

在实际开发中,初学者经常会遇到一些典型问题,这里整理几个常见场景及解决办法。

8.1 端口被占用

启动时报错 Port 8080 was already in use,说明 8080 端口已被其他程序占用。解决办法:

  • 关闭占用端口的进程;
  • 或在 application.properties 中修改端口:
properties 复制代码
server.port=8081

8.2 依赖下载缓慢或失败

Maven 默认从中央仓库下载依赖,国内网络可能较慢。可在 settings.xml 中配置阿里云镜像:

xml 复制代码
<mirror>
    <id>aliyunmaven</id>
    <mirrorOf>central</mirrorOf>
    <url>https://maven.aliyun.com/repository/public</url>
</mirror>

8.3 接口返回 404

  • 检查控制器是否被 @RestController 或 @Controller 标注;
  • 确认启动类所在包是否覆盖了控制器所在的包(@ComponentScan 默认扫描启动类所在包及其子包);
  • 确认请求路径与 @GetMapping / @RequestMapping 中的路径是否一致。

8.4 中文乱码

在 application.properties 中设置编码:

properties 复制代码
server.servlet.encoding.charset=UTF-8
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true

9. 结语

本文从零开始介绍了 Spring Boot 的入门知识,包括核心概念、环境准备、项目创建、项目结构、常用注解、请求参数处理、运行与配置,以及常见问题排查。希望这些内容能帮助你顺利迈出 Spring Boot 开发的第一步。

Spring Boot 生态非常庞大,后续还可以继续学习数据访问(JPA/MyBatis)、安全认证(Security)、消息队列、微服务治理(Spring Cloud)等内容。保持动手实践,多写多调试,你会越来越熟练。

感谢阅读,祝你编码愉快!

10. 项目分层规范

在实际项目中,为了让代码结构清晰、职责分明、便于维护和扩展,通常会按照分层架构来组织代码。下面介绍 Spring Boot 项目中最常见的分层方式。

10.1 常见的分层结构

一个典型的 Spring Boot 项目通常分为以下几层:

层次 包名 职责
Controller 层(控制层) controller 接收 HTTP 请求,校验参数,调用 Service 层,返回响应
Service 层(业务层) service 处理核心业务逻辑,事务管理,调用 Mapper/Repository 层
Mapper/Repository 层(数据访问层) mapper / repository 与数据库交互,执行 SQL 或 JPA 操作
Entity 层(实体层) entity / domain 对应数据库表结构的实体类
DTO 层(数据传输层) dto 用于接口入参和出参的数据封装,避免直接暴露实体
Config 层(配置层) config 存放配置类,如 @Configuration、@Bean 定义
Common/Util 层(通用层) common / util 存放通用工具类、常量、统一返回结果等

10.2 分层后的目录示例

text 复制代码
demo
├── src/main/java/com/example/demo
│   ├── DemoApplication.java
│   ├── controller
│   │   └── UserController.java
│   ├── service
│   │   ├── UserService.java
│   │   └── impl
│   │       └── UserServiceImpl.java
│   ├── mapper
│   │   └── UserMapper.java
│   ├── entity
│   │   └── User.java
│   ├── dto
│   │   ├── UserRequest.java
│   │   └── UserResponse.java
│   ├── config
│   │   └── WebConfig.java
│   └── common
│       ├── Result.java
│       └── GlobalExceptionHandler.java
└── src/main/resources
    └── application.properties

10.3 各层之间的调用关系

调用方向是自上而下的,即 Controller 调用 Service,Service 调用 Mapper,各层之间通过接口或类解耦:

text 复制代码
Controller 层  →  Service 层  →  Mapper/Repository 层  →  数据库

提示:Service 层建议先定义接口,再提供实现类(如 UserService 与 UserServiceImpl),便于后续扩展和单元测试。

10.4 分层的好处

  • 职责清晰:每一层只关注自己的职责,代码可读性更强。
  • 易于维护:修改某一层时,尽量不影响其他层。
  • 便于测试:可以针对 Service 层单独编写单元测试,无需启动 Web 容器。
  • 利于团队协作:不同成员可以并行开发不同层次,减少冲突。

11. 结语补充

项目分层是 Spring Boot 工程化开发的重要基础。掌握分层思想后,再结合前面介绍的注解、请求参数处理等内容,你就能搭建出一个结构清晰、易于扩展的完整项目。后续学习数据访问、安全认证时,分层结构会帮助你更好地组织代码。

12. 实战示例:根据 id 查询用户(分层 + Lombok)

下面结合前面介绍的分层规范,演示一个完整的「根据 id 查询用户」接口。为了让代码更简洁,这里引入 Lombok 来消除繁琐的 getter/setter 样板代码。

12.1 引入 Lombok 依赖

在 pom.xml 中加入 Lombok 依赖(Spring Boot 3.x 无需指定版本,由父工程统一管理):

xml 复制代码
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

提示:使用 IDEA 时,需在 Settings → Plugins 中安装 Lombok 插件,并在 Settings → Build → Compiler → Annotation Processors 勾选 Enable annotation processing ,否则 IDE 无法识别 @Data 等注解。

12.2 Entity 层(实体类)

使用 @Data 自动生成 getter/setter、toString 等方法:

java 复制代码
package com.example.demo.entity;

import lombok.Data;

@Data
public class User {

    private Long id;
    private String name;
    private Integer age;
}

12.3 Mapper 层(数据访问层)

这里用 @Repository 标记,并模拟从内存中查询数据:

java 复制代码
package com.example.demo.mapper;

import com.example.demo.entity.User;
import org.springframework.stereotype.Repository;

@Repository
public class UserMapper {

    public User findById(Long id) {
        // 模拟数据库查询
        User user = new User();
        user.setId(id);
        user.setName("Tom");
        user.setAge(20);
        return user;
    }
}

12.4 Service 层(业务层)

先定义接口,再提供实现类:

java 复制代码
package com.example.demo.service;

import com.example.demo.entity.User;

public interface UserService {

    User getUserById(Long id);
}
java 复制代码
package com.example.demo.service.impl;

import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public User getUserById(Long id) {
        return userMapper.findById(id);
    }
}

12.5 Controller 层(控制层)

使用 @PathVariable 接收路径参数,调用 Service 层返回结果:

java 复制代码
package com.example.demo.controller;

import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/user/{id}")
    public User getUser(@PathVariable Long id) {
        return userService.getUserById(id);
    }
}

12.6 测试接口

启动项目后,浏览器访问 http://localhost:8080/user/1001,返回 JSON:

json 复制代码
{
  "id": 1001,
  "name": "Tom",
  "age": 20
}

12.7 小结

通过这个示例可以看到,结合分层架构与 Lombok,代码结构清晰、职责分明,且大幅减少了样板代码。后续接入真实数据库(如 MyBatis、JPA)时,只需替换 Mapper 层的实现即可,其余层次无需改动。

13. 依赖注入体系

依赖注入(Dependency Injection,简称 DI)是 Spring 框架的核心机制之一。它让对象之间的依赖关系由容器在运行时自动装配,而不是在代码中手动 new 出来,从而降低耦合、提升可测试性和可维护性。

13.1 什么是依赖注入

简单来说,依赖注入就是「把对象需要的依赖,由外部容器注入进来,而不是自己创建」。例如 UserServiceImpl 需要用到 UserMapper,它并不自己 new UserMapper(),而是通过注解让 Spring 容器把 UserMapper 的实例注入进来。

java 复制代码
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;  // 由 Spring 容器注入,而非手动 new

    @Override
    public User getUserById(Long id) {
        return userMapper.findById(id);
    }
}

13.2 依赖注入的三种方式

Spring 支持三种常见的依赖注入方式,各有适用场景。

13.2.1 字段注入(Field Injection)

直接在字段上使用 @Autowired,写法最简洁,也是初学者最常用的方式:

java 复制代码
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;
}

优点:代码简洁。缺点:依赖关系隐藏在字段中,不利于单元测试和发现循环依赖。适合快速开发,但工程化项目中建议少用。

13.2.2 构造器注入(Constructor Injection)

通过构造方法传入依赖,Spring 会自动匹配参数并注入:

java 复制代码
@Service
public class UserServiceImpl implements UserService {

    private final UserMapper userMapper;

    @Autowired
    public UserServiceImpl(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    @Override
    public User getUserById(Long id) {
        return userMapper.findById(id);
    }
}

优点:依赖关系明确、不可变,便于测试,是官方推荐的方式。Spring Boot 3.x 中,类只有一个构造器时可以省略 @Autowired。

13.2.3 Setter 注入(Setter Injection)

通过 Setter 方法注入依赖:

java 复制代码
@Service
public class UserServiceImpl implements UserService {

    private UserMapper userMapper;

    @Autowired
    public void setUserMapper(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    @Override
    public User getUserById(Long id) {
        return userMapper.findById(id);
    }
}

适用场景:依赖可选或需要在运行时动态更换时使用,实际开发中较少用到。

13.3 注入的匹配规则

Spring 容器在注入时,会按照以下顺序查找合适的 Bean:

  1. 按类型匹配:优先根据字段或参数的类型查找容器中对应的 Bean。
  2. 按名称匹配 :如果同类型存在多个 Bean,再根据字段名或参数名(@Qualifier 指定的名称)进一步区分。
  3. @Primary 优先 :当同类型有多个 Bean 时,标注了 @Primary 的 Bean 会被优先注入。
java 复制代码
@Configuration
public class DataSourceConfig {

    @Bean
    @Primary
    public DataSource primaryDataSource() {
        return new HikariDataSource();
    }

    @Bean
    public DataSource backupDataSource() {
        return new HikariDataSource();
    }
}

当同类型存在多个 Bean 时,也可以使用 @Qualifier 指定要注入的 Bean 名称:

java 复制代码
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    @Qualifier("backupDataSource")
    private DataSource dataSource;
}

13.4 依赖注入与分层架构的结合

结合前面介绍的分层规范,依赖注入贯穿了 Controller → Service → Mapper 的整个调用链:

text 复制代码
Controller 层  --注入-->  Service 层  --注入-->  Mapper/Repository 层

每一层都通过接口或类声明依赖,由 Spring 容器统一装配,各层之间无需关心对方如何创建,真正做到「面向接口编程、依赖倒置」。

13.5 小结

依赖注入是 Spring 的核心能力,它让对象之间的协作关系由容器统一管理。掌握字段注入、构造器注入和 Setter 注入的区别,理解按类型、按名称、@Primary、@Qualifier 的匹配规则,是深入使用 Spring Boot 的必备基础。工程化项目中推荐优先使用构造器注入,让依赖关系更清晰、更易测试。

相关推荐
上下求索,莫负韶华1 小时前
Spring全家桶
java·后端·spring
涛涛ing1 小时前
当AI能写原生代码:Shopify用12周把React Native应用迁回了Swift和Kotlin
前端
JudithHuang1 小时前
React 数据请求:TanStack Query
前端·react.js·前端框架
w_zero_one1 小时前
链表(2)
java·数据结构·链表
程序员-Benothing1 小时前
Shell脚本入门教程:Shebang、变量、注释与执行方式
前端·chrome
白杨尚青1 小时前
C++入门篇(十一):string(中)——容量与增删改查:一篇吃透所有常用接口(万字详解)
java·开发语言·c++
java_nnnn2 小时前
JavaEE进阶-JavaScript初识
开发语言·前端·javascript·java-ee·ecmascript
SimonKing2 小时前
SSE、WebSocket 连接丢 Redis 里?那可踩大坑了!
java·后端·程序员
倔强的石头1062 小时前
【Linux指南】动静态库系列(九):动态库如何进入进程地址空间:从磁盘 .so 到共享内存映射
java·linux·服务器