60分钟,我用Spring Boot搭了个能跑的后端

YAML别缩进
2026-04-17 22:36
阅读 715

上周五晚上十一点半,我正戴着耳机听着Lo-fi beats敲代码,突然产品经理在钉钉上@我:“新需求,下周三上线,后端接口明天给一版?” 我差点把咖啡喷在键盘上。作为一个创业公司的全栈开发(说白了就是“啥都干”),我已经习惯了这种节奏——前端改个UI、后端加个接口、运维查个日志、甚至偶尔还要帮测试写个自动化脚本。但这次真有点急。

不过还好,这次我决定用 Spring Boot 快速搭个原型。毕竟最近正在刷 LeetCode 准备跳槽,顺手复习下 Java 生态也挺好。更重要的是,我一直觉得:代码不仅要能跑,还得让人看得懂、改得动。今天这篇技术分享,就带你用不到一小时的时间,从零搞一个能跑、可扩展、带点 Fine-tuning 的 Spring Boot 应用。


起手式:别再手写 Maven 了!

首先,打开 start.spring.io(或者直接在 IDEA 里新建 Spring Initializr 项目)。我选了这些依赖:

  • Spring Web(必须的)
  • Spring Data JPA(懒人 ORM,比 MyBatis 上手快)
  • H2 Database(内存数据库,开发阶段不用装 MySQL)
  • Spring Boot DevTools(热部署,救命神器)

项目结构生成后,pom.xml 自动配好依赖,连版本都不用操心——这就是 Spring Boot 的魅力:约定优于配置。以前手写 XML 配置的日子,真的回不去了。

<!-- 别问我为啥不写具体版本号,Spring Boot parent 已经帮你管好了 -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.2.0</version>
</parent>

写个实体类,顺便聊聊数据库设计

假设我们要做一个简单的用户管理 API。先定义 User 实体:

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, unique = true)
    private String email;

    @Column(nullable = false)
    private String name;

    // getter/setter 省略(Lombok 大法好!)
}

这里有几个小细节:

  • 用了 @Table(name = "users") 明确表名,避免 Hibernate 自动生成复数形式踩坑。
  • email 加了 unique = true,防止重复注册——这种约束一定要在数据库层做,别只靠业务代码判断。
  • 主键用自增 ID,虽然分布式系统里可能不够用,但对 MVP(最小可行产品)完全够了。

Repository + Service + Controller,经典三层走起

Spring Data JPA 让 DAO 层几乎不用写代码:

public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByEmail(String email);
}

Service 层简单封装逻辑(虽然现在只有 CRUD):

@Service
@Transactional
public class UserService {
    @Autowired
    private UserRepository userRepository;

    public User createUser(User user) {
        if (userRepository.findByEmail(user.getEmail()).isPresent()) {
            throw new IllegalArgumentException("Email already exists");
        }
        return userRepository.save(user);
    }
}

Controller 层暴露 REST 接口:

@RestController
@RequestMapping("/api/users")
public class UserController {
    @Autowired
    private UserService userService;

    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody User user) {
        try {
            User saved = userService.createUser(user);
            return ResponseEntity.status(HttpStatus.CREATED).body(saved);
        } catch (IllegalArgumentException e) {
            return ResponseEntity.badRequest().build();
        }
    }
}

看到没?异常处理很粗糙,但 MVP 阶段先跑起来再说。等后面有时间再统一用 @ControllerAdvice 做全局异常处理。


配置文件:别只用 application.properties

默认的 application.properties 没问题,但我习惯拆成多环境配置:

src/main/resources/
├── application.yml
├── application-dev.yml
└── application-prod.yml

application.yml 放通用配置:

spring:
  profiles:
    active: dev

application-dev.yml 开发环境:

spring:
  datasource:
    url: jdbc:h2:mem:testdb
    driver-class-name: org.h2.Driver
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: create-drop

而生产环境(application-prod.yml)会用真正的 MySQL,并关闭 show-sql,设置 ddl-auto: validate —— 线上绝对不能自动改表结构!


Fine-tuning:不只是调参,更是工程思维

很多人以为 Fine-tuning 就是改几个 JVM 参数,其实不止。在 Spring Boot 里,Fine-tuning 体现在:

  1. 连接池配置(HikariCP 默认集成)
  2. 线程池大小
  3. 日志级别
  4. 健康检查端点

比如,我在 application-prod.yml 里加了这些:

spring:
  datasource:
    hikari:
      maximum-pool-size: 20
      connection-timeout: 30000

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics

这样运维就能通过 /actuator/health 查服务状态,监控系统也能采集指标。别等到线上挂了才想起要可观测性。


踩过的坑:那些让我想砸电脑的瞬间

  1. JPA LazyInitializationException
    在 Controller 里直接返回 Entity,结果 Jackson 序列化时访问了未加载的关联字段。解决方案:要么用 DTO,要么加 @JsonIgnore,或者开启 spring.jpa.open-in-view=true(但后者有性能隐患,慎用)。

  2. H2 和 MySQL 语法差异
    H2 支持 AUTO_INCREMENT,但写法和 MySQL 不完全一样。后来我干脆本地也用 Docker 起个 MySQL 容器,保持环境一致。

  3. DevTools 热部署失效
    原来是因为我改了 pom.xml 或静态资源,它只监听 classpath 下的 class 文件变化。后来学会用 Ctrl+F9(Build Project)手动触发。


性能与可维护性:我的执念

作为被线上事故教育过的人,我特别在意两点:

  • 接口幂等性:创建用户的 POST 接口其实应该用 PUT + 唯一 ID,或者加防重 Token。但现在 MVP 阶段先忍着。
  • 日志上下文:每个请求加 traceId,方便排查。可以用 MDC + Logback 实现,不过 Spring Cloud Sleuth 更省事(但引入了额外依赖)。

另外,代码格式统一很重要。我们团队强制用 Spotless 插件,每次 commit 自动格式化,避免 PR 里吵“空格还是 tab”。


最后跑起来,验证一下

启动应用,用 curl 测试:

curl -X POST http://localhost:8080/api/users \
  -H "Content-Type: application/json" \
  -d '{"name":"张三","email":"zhangsan@example.com"}'

返回 201 Created,搞定!

再访问 http://localhost:8080/h2-console(记得在配置里开启 spring.h2.console.enabled=true),还能直接查数据库——开发体验拉满。


写在最后

60 分钟,从零到一个可运行的 Spring Boot 应用,其实并不难。难点在于如何让它在生产环境中稳如老狗。Fine-tuning 不是一次性的工作,而是随着业务增长不断迭代的过程。

我现在每天边刷题边优化这个小项目,想着跳槽时能拿它当作品集。虽然创业公司节奏快、需求乱,但正是这种“什么都要自己搞”的环境,逼我学会了快速搭建可靠系统的能力。

如果你也在准备面试,或者刚接手一个后端项目,不妨试试 Spring Boot。它可能不是最炫酷的框架,但绝对是最能让你在 deadline 前睡个好觉的那个。

对了,刚才产品经理又发消息了:“那个接口,能不能加个导出 Excel 功能?” …… 我默默打开了 Apache POI 的文档。


附:常用配置速查表

配置项 开发环境 生产环境
ddl-auto create-drop validate
show-sql true false
数据库 H2 / 本地 MySQL 远程 MySQL + 连接池
日志级别 DEBUG INFO
Actuator 端点 全开 只开 health, metrics

技术分享不易,如果对你有帮助,欢迎点赞、转发。下次聊聊怎么用 Spring Boot + Redis 做缓存穿透防护——那可是我去年双11熬夜修的 Bug。

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝