后端开发者工程实践指南

0 阅读16分钟

后端开发者工程实践指南 前言 关键词: SDK 、 JDK 、 Spring Boot 、 Maven 、 Tomcat 、 Sa Token 、 Docker 、 灰度发布 这篇文章的目标是把一条完整的后端开发链路串起来:从开发工具、项目运行、依赖管理,到权限校验、日志、数据库、缓存、接口规范,再到部署与构建。下面针对开发中遇到的问题与注意事项关键点展开分享

田亚行

2026-05-23 17:2415 分钟读完250

后端开发者工程实践指南

前言

关键词:SDKJDKSpring BootMavenTomcatSa-TokenDocker灰度发布

这篇文章的目标是把一条完整的后端开发链路串起来:从开发工具、项目运行、依赖管理,到权限校验、日志、数据库、缓存、接口规范,再到部署与构建。下面针对开发中遇到的问题与注意事项关键点展开分享.


1. SDK,JDK 和 Spring Boot

SDK,全称 Software Development Kit,中文一般叫“软件开发工具包”。它本质上是一组用来开发某类应用的软件工具集合,通常包括:

  • API 或类库
  • 文档
  • 示例代码
  • 调试或构建工具

如果把“开发应用”理解成“搭建一套生产线”,那么 SDK 就是一整套工具箱。

JDK 是 Java 语言专属的 SDK

JDK,全称 Java Development Kit,是 Java 开发必须安装的工具包。它不仅包含运行 Java 程序需要的环境,还包含编译、调试、打包等开发能力。

常见组成包括:

  • javac:把 .java 编译成 .class
  • java:运行 Java 程序
  • javadoc:生成文档
  • jar:打包程序

可以简单理解为:

想写 Java,就离不开 JDK。

Spring Boot 是写后端的开发框架

严格来说,Spring Boot 更接近“后端开发框架”或“后端工程脚手架”,而不是狭义上的 SDK。但从“帮你更高效地开发后端系统”这个角度来看,也可以把它理解成一套面向后端开发的能力集合。

Spring Boot 帮你做了几件非常重要的事:

  • 帮你快速搭建 Web 项目
  • 自动装配常用组件
  • 内置 Web 服务器
  • 统一配置方式
  • 简化依赖管理

所以在日常开发里,我们通常会这样理解:

  • JDK 解决“怎么写和运行 Java”
  • Spring Boot 解决“怎么高效写后端项目”

2. Maven:依赖管理、打包和运行的核心工具

Java 项目很少完全手写所有代码,大部分都会依赖大量第三方库,例如:

  • Spring Boot
  • MyBatis / JPA
  • MySQL 驱动
  • Redis 客户端
  • 日志组件

这时候就需要 Maven 来统一管理依赖、构建和打包。

Maven 主要做什么

Maven 在项目里通常负责三件事:

  1. 管理依赖包

  2. 执行构建流程

  3. 打包并运行项目

pom.xml 是 Maven 的配置清单

一个 Maven 项目的核心文件通常就是 pom.xml。你可以把它理解成项目的“构建说明书”。

它通常定义:

  • 项目坐标:groupIdartifactIdversion
  • 依赖列表:项目需要哪些 jar 包
  • 构建插件:如何编译、测试、打包
  • Java 版本:例如 17 或 21

示例:

<project>
    <modelVersion>4.0.0</modelVersion>

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

    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>1.0.0</version>

    <properties>
        <java.version>17</java.version>
    </properties>

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

常见命令

# 编译项目
mvn compile

# 运行测试
mvn test

# 打包
mvn package

# 启动 Spring Boot 项目
mvn spring-boot:run

Maven 往往也是构建流水线的基础。


3. 项目是怎么跑起来的:Tomcat、端口和 HTTP 请求

很多人第一次启动 Spring Boot,会误以为“项目启动”只是 Java 主函数运行了。实际上,对于 Web 项目来说,项目启动的核心是:HTTP 服务启动了

Tomcat 是服务器

Tomcat 是一个 Java Web 服务器,负责接收客户端发来的 HTTP 请求,并把请求转交给你的后端代码处理。

比如用户访问:

http://localhost:8080/user/list

请求流程通常是:

  1. 浏览器或接口工具发起 HTTP 请求

  2. Tomcat 接收到请求

  3. Spring Boot 把请求路由到对应 Controller

  4. 业务代码处理后返回响应

Spring Boot 自带 Tomcat

这是 Spring Boot 非常省心的一点:不需要你手动安装 Tomcat

只要项目里引入了 Web 相关依赖,例如:

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

启动项目时,Spring Boot 会自动把内置 Tomcat 一起启动。

所以可以这样理解:

  • 项目启动 = 启动内置 Tomcat
  • 项目停止 = 关闭 Tomcat

默认端口是 8080

Spring Boot 默认端口通常是 8080。如果本机已经有别的进程占用了这个端口,项目就会启动失败。

修改方式:

server.port=8081

也可以写在 application.yml

server:
  port: 8081

如何排查端口占用

查看谁占用了 8080

lsof -i :8080

杀掉对应进程(把 1234 替换成实际 PID):

kill -9 1234

这类操作虽然常见,但线上环境不建议直接粗暴 kill -9,本地开发排障可以接受。


4. 内网穿透:让本地服务被外网访问

很多开发场景下,你的服务跑在本地电脑上,但又需要让别人访问,比如:

  • 前端同学联调接口
  • 第三方平台做回调测试
  • 移动端真机调试
  • 给测试环境临时演示

这时候就会用到内网穿透

内网穿透解决什么问题

你的本地服务地址可能是:

http://127.0.0.1:8080

这个地址只有你自己电脑能访问,外部设备和外网服务访问不到。内网穿透工具会帮你把这个本地端口映射成一个公网可访问地址。

常见用途:

  • 支付回调调试
  • OAuth 登录回调
  • Webhook 联调
  • 移动端调用本地接口

实践建议

  • 只在开发和调试阶段使用
  • 不要暴露未加鉴权的敏感接口
  • 配合白名单、签名或 token 做访问控制
  • 尽量限制暴露时间和访问范围

5. Sa-Token:轻量级认证与权限框架

后端项目几乎绕不开登录、鉴权、权限控制。Sa-Token 是 Java 生态里比较常见的一套安全框架,适合做:

  • 登录认证
  • 会话管理
  • 权限校验
  • 角色校验
  • token 管理
  • 单点登录扩展

它适合放在什么位置

你可以把 Sa-Token 理解成“系统入口的门卫”。

典型请求流程是:

  1. 用户登录成功

  2. 服务端签发 token

  3. 用户后续请求携带 token

  4. 服务端校验 token 是否有效

  5. 决定是否允许访问接口

常见场景

  • StpUtil.login(userId):用户登录
  • StpUtil.checkLogin():检查是否已登录
  • StpUtil.checkPermission("user:add"):检查权限

如果项目需要快速落地登录体系,Sa-Token 是一个上手成本较低的方案。


6. 数据存储与缓存:别把所有压力都丢给数据库

后端系统的数据存储通常不止一种方式。最常见的组合是:

  • 数据库:负责持久化
  • 缓存:负责提速和减压

数据库存什么

数据库适合保存核心业务数据,例如:

  • 用户信息
  • 订单信息
  • 权限关系
  • 系统配置

缓存存什么

缓存通常用于存放:

  • 登录态
  • 验证码
  • 热点数据
  • 查询结果
  • 限流计数

最常见的缓存组件是 Redis

为什么要用缓存

因为数据库不是无限快的。高频读取场景如果每次都查库,会带来:

  • 响应变慢
  • 数据库压力变大
  • 并发能力下降

缓存的价值就在于:

  • 提升读取速度
  • 降低数据库压力
  • 改善系统吞吐量

但要注意缓存一致性、过期策略和击穿问题,不能一上来就“全量缓存”。


7. 数据库连接、建表、表结构与表关系

后端开发离不开数据库设计。一个项目是否稳定,往往跟表结构设计质量高度相关。

先连接数据库

Spring Boot 常见配置方式如下:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

创建表时关注什么

建表不只是“字段能存进去就行”,还要考虑:

  • 字段类型是否合理
  • 是否允许为空
  • 默认值是否明确
  • 是否需要索引
  • 是否需要唯一约束
  • 是否要记录创建和更新时间

一个典型用户表示例:

CREATE TABLE sys_user (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(64) NOT NULL UNIQUE,
    password VARCHAR(255) NOT NULL,
    nickname VARCHAR(64),
    status TINYINT NOT NULL DEFAULT 1,
    create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

表关系怎么理解

常见关系包括:

  • 一对一:用户和用户详情
  • 一对多:一个部门下有多个用户
  • 多对多:一个用户有多个角色,一个角色也能属于多个用户

如果表关系没设计清楚,后面接口、权限、统计和扩展都会变得很痛苦。


8. 登录黑白名单校验

登录并不是“账号密码对了就一定放行”。实际系统里常常还会有黑白名单策略。

黑名单

黑名单表示:命中后直接拒绝。

常见黑名单对象:

  • 被禁用用户
  • 风险 IP
  • 风险设备
  • 多次异常登录账号

白名单

白名单表示:只有在允许范围内才放行。

常见白名单场景:

  • 指定 IP 才能登录后台
  • 指定账号才能访问灰度功能
  • 指定租户或组织才能启用某模块

推荐做法

把登录校验拆成多层:

  1. 基础身份校验:账号密码、验证码

  2. 状态校验:账号是否启用

  3. 策略校验:是否命中黑名单

  4. 放行校验:是否满足白名单

这样既清晰,也更利于后续维护。


9. API 文档与 APIpost:让接口联调更顺畅

接口开发不仅是把接口写出来,还要让别人能看懂、能调通、能导入工具里直接测试。

APIpost 常用于接口调试、导入导出接口集合、协作测试等场景。

为什么要重视接口文档

如果接口没有清晰说明,联调时常见问题会非常多:

  • 参数名对不上
  • 类型不明确
  • 是否必填不清楚
  • 返回字段解释不完整

用 Javadoc 注解补充接口说明

即使项目里还没完整接入 Swagger / OpenAPI,也建议先把接口说明写进代码注释里。

示例:

/**
 * 用户登录接口
 *
 * @param req 登录请求参数,包含账号和密码
 * @return 登录结果,返回 token 和用户基础信息
 */
@PostMapping("/login")
public ApiResult<LoginResp> login(@RequestBody LoginReq req) {
    return ApiResult.success(authService.login(req));
}

这样做至少有两个好处:

  • 代码可读性更高
  • 后续生成接口文档更容易

如果团队使用 APIpost,可以结合导出接口集合,让前后端和测试共享统一接口定义。


10. 日志:出了问题,第一时间看什么

日志不是“可有可无的输出”,而是后端系统排障和审计的生命线。

为什么日志重要

一个接口报错后,你往往不会第一时间去猜,而是先看日志里有没有:

  • 请求参数
  • 核心流程节点
  • 异常堆栈
  • 数据库或远程调用信息

建议记录哪些日志

  • 应用启动日志
  • 接口访问日志
  • 业务关键节点日志
  • 异常日志
  • 安全审计日志

注意事项

  • 不要把密码、密钥、token 明文打进日志
  • 不要无节制打印大对象
  • 日志级别要区分清楚:INFOWARNERROR
  • 统一日志格式,便于检索和采集

一个成熟项目里,日志既服务开发排障,也服务线上审计和运营分析。


11. 代码规范:Map 与 Object 的边界要清楚

很多初学者写接口时喜欢“先用 Map 顶一下”,短期看很快,长期看会埋很多坑。

Map 的问题

如果一个请求参数或返回值全靠 Map<String, Object> 表达,会出现:

  • 字段名容易写错
  • 类型不明确
  • IDE 无法很好提示
  • 文档难维护
  • 后期重构困难

更推荐的做法:创建明确的类

也就是常说的:

  • 请求用 Request DTO
  • 返回用 Response DTO
  • 数据库实体用 Entity
  • 业务内部传递可用 VO 或 BO

示例:

public class LoginReq {
    private String username;
    private String password;
}

public class LoginResp {
    private String token;
    private Long userId;
    private String nickname;
}

Map 什么时候能用

Map 不是不能用,而是要用在真正合适的场景:

  • 动态字段
  • 聚合统计结果
  • 临时透传结构
  • 不固定 key 的配置数据

原则很简单:结构稳定,就建类;结构不稳定,再考虑 Map。


12. 全局响应封装:统一接口返回格式

一个成熟的后端系统,不应该每个接口都各自返回不同结构。统一响应格式是非常重要的基础规范。

目标结构:

{
  "success": true,
  "message": "ok",
  "data": {}
}

这是一种非常常见也很实用的设计。

为什么要全局封装

统一返回格式的好处包括:

  • 前端更容易处理
  • 测试更容易校验
  • 错误码和提示语更统一
  • 接口风格更一致

一个支持泛型的 ApiResult 示例

public class ApiResult<T> {

    private boolean success;
    private String message;
    private T data;

    public static <T> ApiResult<T> success(T data) {
        ApiResult<T> result = new ApiResult<>();
        result.success = true;
        result.message = "ok";
        result.data = data;
        return result;
    }

    public static <T> ApiResult<T> fail(String message) {
        ApiResult<T> result = new ApiResult<>();
        result.success = false;
        result.message = message;
        result.data = null;
        return result;
    }
}

Controller 中的使用方式:

@GetMapping("/user/{id}")
public ApiResult<UserResp> getUser(@PathVariable Long id) {
    return ApiResult.success(userService.getById(id));
}

这类封装通常还会进一步扩展:

  • 状态码 code
  • 时间戳 timestamp
  • 链路追踪号 traceId

13. 用户埋点:把行为日志送到服务端

很多业务不只关心“接口有没有成功”,还关心“用户做了什么”。这时候就要引入用户埋点

什么是埋点

埋点就是在用户行为发生时,记录一条事件数据,例如:

  • 页面浏览
  • 按钮点击
  • 登录成功
  • 下单提交
  • 功能开关使用

“界面不显”是什么意思

通常指埋点逻辑不直接影响用户界面表现。用户不会因为埋点而看到额外按钮或提示,但系统会在后台把行为数据发送到服务端。

服务端能做什么

服务端收到埋点后,可以用于:

  • 用户行为分析
  • 漏斗分析
  • 功能使用统计
  • 问题排查
  • 安全审计

实践建议

  • 明确事件名称和字段规范
  • 控制发送频率,避免刷爆服务端
  • 注意隐私和敏感信息脱敏
  • 埋点日志与业务日志尽量分层管理

14. 部署与灰度发布:不要一把梭直接全量上线

后端开发写完代码并不意味着工作结束,真正的挑战常常发生在上线阶段。

什么是部署

部署就是把你的应用发布到目标环境,让外部用户或其他系统能够访问。

常见环境包括:

  • 开发环境
  • 测试环境
  • 预发环境
  • 生产环境

什么是灰度发布

灰度发布是指:不是一次性把新版本放给所有用户,而是先给一部分流量使用。

这样做的价值非常大:

  • 降低上线风险
  • 尽早发现问题
  • 出问题时影响范围更小

常见灰度方式

  • 按用户 ID 灰度
  • 按 IP 灰度
  • 按请求头灰度
  • 按机器实例比例灰度

如果系统是核心业务系统,灰度几乎是必须具备的发布能力。


15. Docker:统一运行环境,减少“我本地没问题”

后端项目在不同机器上运行时,经常遇到环境差异问题,例如:

  • JDK 版本不一致
  • 系统依赖不同
  • 配置文件不一致
  • 启动命令各不相同

Docker 的意义就在于:把应用和它依赖的运行环境一起打包。

Docker 带来的好处

  • 环境一致
  • 部署更标准化
  • 扩容更方便
  • 更适合 CI/CD

一个基础 Dockerfile 示例

FROM eclipse-temurin:17-jre

WORKDIR /app

COPY target/demo.jar app.jar

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "app.jar"]

这表示:

  • 基于 JRE 17 运行
  • 把打好的 jar 放进容器
  • 暴露 8080 端口
  • 启动时执行 java -jar app.jar

16. 打包构建脚本:把重复动作沉淀下来

一个工程化项目,不能每次都靠人手敲一堆命令。构建脚本的意义就是把重复、稳定的流程固化下来。

常见构建动作

  • 清理旧产物
  • 编译代码
  • 执行测试
  • 打 jar 包
  • 构建 Docker 镜像
  • 推送到镜像仓库

示例脚本

#!/usr/bin/env bash

set -e

echo "clean and package..."
mvn clean package -DskipTests

echo "build docker image..."
docker build -t demo:1.0.0 .

echo "done."

为什么脚本重要

因为它能把“个人经验”变成“团队标准动作”。

一个清晰的构建脚本可以帮助团队:

  • 降低操作出错概率
  • 提升交付效率
  • 让新人更快上手

17. 一条完整的 Spring Boot 后端开发链路

把上面的内容连起来,一个典型的 Spring Boot 后端项目开发流程通常是这样的:

  1. 安装 JDK,具备 Java 开发能力

  2. 使用 Spring Boot 初始化后端工程

  3. 用 Maven 管理依赖,并通过 pom.xml 维护构建配置

  4. 启动项目,内置 Tomcat 在指定端口提供 HTTP 服务

  5. 配置数据库连接,完成建表和表关系设计

  6. 引入缓存提升性能

  7. 使用 Sa-Token 实现登录认证与权限控制

  8. 建立黑白名单等安全校验机制

  9. 规范接口返回结构,统一封装 ApiResult<T>

  10. 用注释和接口工具维护 API 文档

  11. 接入日志与用户埋点,提升可观测性

  12. 使用 Docker 和构建脚本完成标准化部署

  13. 通过灰度发布降低上线风险

这条链路既是技术实现路径,也是后端工程能力逐步成熟的过程。


结语

后端开发不是只会写几个接口就够了。真正的工程实践,关注的是整个系统如何被开发、运行、保护、观察、交付和迭代。

不要把 JDKMavenTomcatSa-Token、数据库、缓存、日志、Docker 这些概念割裂开来看。它们并不是零散知识点,而是一套完整的后端工程协作体系。

当你能把这些工具和概念串成一条链路时,你就不只是“会写接口”,而是在真正进入后端开发这门工程实践。