基于Spring Boot构建RESTful API,集成MySQL实现数据持久化,设计Book/User实体类映射数据库表结构,通过@RestController暴露借阅/归还/查询接口,结合JWT实现权限认证,采用Lombok简化POJO
技术选型与架构设计
组件 |
技术方案 |
说明 |
后端框架 |
Spring Boot 3.x + Java 17 |
快速构建RESTful API,内置Tomcat容器 |
数据库 |
MySQL 8.0 |
存储用户、图书、借阅记录等核心数据 |
ORM框架 |
Spring Data JPA |
简化数据库操作,自动生成查询方法 |
安全框架 |
Spring Security + JWT |
实现用户认证与权限控制 |
日志系统 |
Logback + ELK(可选) |
记录系统运行日志,便于问题追踪 |
API文档 |
Swagger 3.0 |
自动生成可视化接口文档 |
数据库设计
表结构设计
表名 |
字段说明 |
users |
id (主键): 用户唯一标识
username : 用户名
password : 加密密码
role : 用户角色(ADMIN/USER)
created_at : 创建时间 |
books |
id (主键): 图书唯一标识
title : 书名
author : 作者
isbn : ISBN号
category : 分类
stock : 库存数量
status : 状态(AVAILABLE/BORROWED) |
borrow_records |
id (主键): 记录唯一标识
user_id (外键): 借阅用户ID
book_id (外键): 图书ID
borrow_time : 借阅时间
return_time : 归还时间
due_time : 到期时间 |
关键约束
- 外键约束:
borrow_records.user_id
关联 users.id
,borrow_records.book_id
关联 books.id
- 唯一索引:
users.username
唯一,books.isbn
唯一
- 软删除:通过
status
字段标记数据状态(如图书下架)
核心API设计
用户管理
功能 |
API路径 |
方法 |
权限 |
说明 |
用户注册 |
/api/users/register |
POST |
无 |
密码需加密存储(BCrypt) |
用户登录 |
/api/users/login |
POST |
无 |
返回JWT令牌,包含角色信息 |
获取用户信息 |
/api/users/me |
GET |
USER/ADMIN |
需携带有效JWT |
删除用户(管理员) |
/api/users/{id} |
DELETE |
ADMIN |
仅管理员可删除普通用户 |
图书管理
功能 |
API路径 |
方法 |
权限 |
说明 |
查询所有图书 |
/api/books |
GET |
USER/ADMIN |
支持分页、按分类/作者/ISBN筛选 |
添加图书(管理员) |
/api/books |
POST |
ADMIN |
必填字段:title, author, isbn, stock |
修改图书信息 |
/api/books/{id} |
PUT |
ADMIN |
可修改库存、状态等 |
删除图书 |
/api/books/{id} |
DELETE |
ADMIN |
逻辑删除(status标记) |
借阅管理
功能 |
API路径 |
方法 |
权限 |
说明 |
借阅图书 |
/api/borrow/{bookId} |
POST |
USER |
检查库存>0且用户未超最大借阅数 |
归还图书 |
/api/return/{bookId} |
POST |
USER |
更新归还时间,释放库存 |
查询借阅记录 |
/api/borrow/records |
GET |
USER/ADMIN |
分页展示借阅历史 |
关键代码实现
实体类定义(Java)
// User.java
@Entity
@Table(name = "users")
public class User {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password; // BCrypt加密存储
private String role; // ADMIN/USER
private LocalDateTime createdAt;
// Getters/Setters省略
}
// Book.java
@Entity
@Table(name = "books")
public class Book {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String author;
private String isbn;
private String category;
private Integer stock;
private String status; // AVAILABLE/BORROWED
// Getters/Setters省略
}
借阅逻辑(Service层)
// BorrowService.java
@Transactional
public void borrowBook(Long userId, Long bookId) {
// 1. 检查图书状态
Book book = bookRepository.findById(bookId)
.orElseThrow(() -> new ResourceNotFoundException("Book not found"));
if (!BookStatus.AVAILABLE.equals(book.getStatus())) {
throw new BadRequestException("Book is not available");
}
// 2. 检查用户借阅数量
int borrowCount = borrowRecordRepository.countByUserIdAndReturnTimeIsNull(userId);
if (borrowCount >= MAX_BORROW_LIMIT) {
throw new BadRequestException("Exceed maximum borrow limit");
}
// 3. 更新图书状态并保存记录
book.setStatus(BookStatus.BORROWED);
bookRepository.save(book);
BorrowRecord record = new BorrowRecord();
record.setUserId(userId);
record.setBookId(bookId);
record.setBorrowTime(LocalDateTime.now());
record.setDueTime(LocalDateTime.now().plusDays(BORROW_PERIOD_DAYS));
borrowRecordRepository.save(record);
}
JWT认证流程
// AuthController.java
@PostMapping("/login")
public ResponseEntity<TokenResponse> login(@RequestBody LoginRequest request) {
// 1. 验证用户名密码
User user = userRepository.findByUsername(request.getUsername())
.orElseThrow(() -> new BadCredentialsException("Invalid credentials"));
if (!passwordEncoder.matches(request.getPassword(), user.getPassword())) {
throw new BadCredentialsException("Invalid credentials");
}
// 2. 生成JWT令牌
String token = jwtUtils.generateToken(user.getId(), user.getRole());
// 3. 返回响应
return ResponseEntity.ok(new TokenResponse(token, user.getRole()));
}
单元测试示例
测试场景 |
方法名 |
预期结果 |
用户注册成功 |
testRegisterUser |
返回HTTP 201,用户存入数据库 |
图书库存不足 |
testBorrowBookStockZero |
抛出BadRequestException |
管理员添加图书 |
testAdminAddBook |
返回HTTP 201,图书可查询到 |
JWT令牌验证失败 |
testInvalidToken |
返回HTTP 401,拒绝访问 |
相关问题与解答
问题1:如何扩展系统支持图书分类管理?
解答:

- 新增分类表:创建
categories
表,存储分类ID和名称。
- 修改图书表:在
books
表中添加category_id
外键字段,关联categories
表。
- API调整:
- 添加
/api/categories
接口用于增删改查分类。
- 在查询图书接口中增加
categoryId
筛选参数。
- 前端适配:在图书详情页展示分类信息,并提供按分类筛选功能。
问题2:如何实现逾期归还罚款功能?
解答:

- 数据库调整:在
borrow_records
表中添加fine_amount
字段(默认0)。
- 归还逻辑修改:
- 在
returnBook
方法中检查当前时间是否超过due_time
。
- 如果逾期,按每日罚款金额计算总罚款(例如每日租金的10%)。
- 更新
fine_amount
字段并持久化。
- API扩展:
- 新增
/api/fines/{userId}
接口,查询用户未支付罚款总额。
- 在用户支付罚款后,更新罚款状态并记录