系列:后端路线 · 完整示例
把 Part 1(MySQL) ~ Part 4(部署) 全部焊死在一个项目里。这是一个复制即可跑的最小用户管理系统:建表 → 实体 → Mapper → Service → Controller → 接口自测。读完你已具备独立交付一个后端模块的能力。

1. 功能清单

接口 方法 路径 说明
注册用户 POST /api/users 新增
用户列表 GET /api/users 分页查询
用户详情 GET /api/users/{id} 按主键查
更新用户 PUT /api/users/{id} 改资料
删除用户 DELETE /api/users/{id} 逻辑/物理删除
按名查询 GET /api/users?username=xxx 条件查询

2. 建表 SQL(Part 1 的加强版)

1
2
3
4
5
6
7
8
9
10
11
12
CREATE TABLE `user` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
`username` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '用户名',
`age` TINYINT NOT NULL DEFAULT 0 COMMENT '年龄',
`balance` DECIMAL(10,2) NOT NULL DEFAULT 0.00 COMMENT '余额',
`status` TINYINT NOT NULL DEFAULT 1 COMMENT '1正常 2禁用',
`deleted` TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除标记',
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

3. 项目关键文件

3.1 依赖(pom.xml 核心)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.7</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>

3.2 配置(application.yml)

1
2
3
4
5
6
7
8
9
10
11
12
13
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/demo_db?useUnicode=true&characterEncoding=utf8mb4&serverTimezone=Asia/Shanghai
username: root
password: your_password
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted # 逻辑删除字段
logic-not-delete-value: 0
logic-delete-value: 1

3.3 实体(Entity)

1
2
3
4
5
6
7
8
9
10
11
12
13
@TableName("user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String username;
private Integer age;
private BigDecimal balance;
private Integer status;
private Integer deleted;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
// getter / setter 省略
}

3.4 Mapper

1
2
@Mapper
public interface UserMapper extends BaseMapper<User> {}

3.5 Service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Service
public class UserService extends ServiceImpl<UserMapper, User> {

public User register(String username, int age) {
// 业务校验:用户名唯一(也可靠唯一索引兜底)
if (this.lambdaQuery().eq(User::getUsername, username).count() > 0) {
throw new RuntimeException("用户名已存在");
}
User u = new User();
u.setUsername(username);
u.setAge(age);
u.setBalance(BigDecimal.ZERO);
u.setStatus(1);
this.save(u);
return u;
}

public IPage<User> pageList(long current, long size) {
return this.page(new Page<>(current, size));
}
}

3.6 Controller(统一响应)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
@RestController
@RequestMapping("/api/users")
public class UserController {

@Autowired
private UserService userService;

/** 注册 */
@PostMapping
public Result<User> register(@RequestBody User dto) {
return Result.ok(userService.register(dto.getUsername(), dto.getAge()));
}

/** 列表(分页) */
@GetMapping
public Result<IPage<User>> list(@RequestParam(defaultValue="1") long current,
@RequestParam(defaultValue="10") long size) {
return Result.ok(userService.pageList(current, size));
}

/** 详情 */
@GetMapping("/{id}")
public Result<User> detail(@PathVariable Long id) {
return Result.ok(userService.getById(id));
}

/** 更新 */
@PutMapping("/{id}")
public Result<Boolean> update(@PathVariable Long id, @RequestBody User dto) {
dto.setId(id);
return Result.ok(userService.updateById(dto));
}

/** 删除(逻辑删除) */
@DeleteMapping("/{id}")
public Result<Boolean> delete(@PathVariable Long id) {
return Result.ok(userService.removeById(id));
}
}

3.7 统一响应包装(Result)

1
2
3
4
5
6
7
8
9
10
11
public class Result<T> {
private int code;
private String msg;
private T data;
public static <T> Result<T> ok(T data) {
Result<T> r = new Result<>();
r.code = 0; r.msg = "ok"; r.data = data;
return r;
}
// getter / setter 省略
}

4. 端到端自测(curl)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 1. 注册
curl -X POST http://localhost:8080/api/users \
-H "Content-Type: application/json" \
-d '{"username":"zhang","age":20}'
# → {"code":0,"msg":"ok","data":{"id":1,"username":"zhang","age":20,...}}

# 2. 列表
curl "http://localhost:8080/api/users?current=1&size=10"

# 3. 详情
curl http://localhost:8080/api/users/1

# 4. 更新
curl -X PUT http://localhost:8080/api/users/1 \
-H "Content-Type: application/json" \
-d '{"age":21}'

# 5. 删除(触发逻辑删除,deleted 置 1)
curl -X DELETE http://localhost:8080/api/users/1

5. 这条链路的”全栈印证”

1
2
3
curl ──HTTP──► Controller(路由/参数) ──► Service(业务/校验)
──► Mapper(CRUD)
──► MySQL(持久化, Part1)
  • Part 1 的建表 → 这里 user
  • Part 2 的分层 → Controller/Service/Mapper/Entity
  • Part 3 的协议 → POST/GET/PUT/DELETE + JSON + 统一响应
  • Part 4 的部署 → mvn packagejava -jar 即可对外服务

6. 可继续加强的方向(留给你练手)

  • 登录接口 + JWT(Part 3 认证)
  • 参数校验 @Valid + 全局异常处理器(统一错误码)
  • 分页/排序/条件查询封装
  • 热点查询加 Redis 缓存(下个专题)
  • Docker 容器化部署

下一篇(收官):常见问题与调试技巧——把”跑不起来/调不通”的高频坑一次性列给你。