Spring Boot 3.2 + MySQL 8.0 图书馆管理系统:从 8 张表设计到 CRUD 接口实现
Spring Boot 3.2 + MySQL 8.0 图书馆管理系统实战指南
1. 技术栈选型与环境配置
在开始构建图书馆管理系统之前,我们需要明确技术选型并完成开发环境准备。本系统采用当前主流的技术组合:
- 后端框架 :Spring Boot 3.2(基于Spring Framework 6)
- 数据库 :MySQL 8.0(支持JSON类型和窗口函数)
- ORM工具 :Spring Data JPA + Hibernate 6
- 构建工具 :Gradle 8.2(支持Java 17+)
- API文档 :SpringDoc OpenAPI 2.0
1.1 开发环境准备
首先确保你的开发环境满足以下要求:
# 检查Java版本
java -version
# 应输出:openjdk version "17.0.5"...
# 检查MySQL版本
mysql --version
# 应输出:mysql Ver 8.0.32...
创建Gradle项目时, build.gradle 关键依赖配置如下:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
1.2 数据库连接配置
在 application.yml 中配置MySQL连接:
spring:
datasource:
url: jdbc:mysql://localhost:3306/library_db?useSSL=false&serverTimezone=UTC
username: library_admin
password: secure_password
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: validate
show-sql: true
properties:
hibernate:
format_sql: true
注意:生产环境务必使用连接池(如HikariCP)并启用SSL加密连接
2. 数据库设计与实体建模
基于图书馆业务需求,我们设计8张核心表,以下是它们的ER关系:
| 表名 | 主要功能 | 关联表 |
|---|---|---|
| book | 存储图书基本信息 | book_type |
| book_type | 图书分类信息 | - |
| borrower | 借阅者个人信息 | borrow_card |
| borrow_card | 借阅证信息 | - |
| admin | 管理员信息 | - |
| reserve_record | 预借记录 | book, borrow_card |
| borrow_record | 借阅记录 | book, borrow_card |
| overdue_record | 逾期记录 | borrow_record |
2.1 核心实体类实现
使用JPA实体映射数据库表,以下是 Book 实体类的典型实现:
@Entity
@Table(name = "book")
@Getter
@Setter
@NoArgsConstructor
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 100)
private String title;
@Column(nullable = false, length = 50)
private String author;
@Column(nullable = false, length = 20)
private String isbn;
@ManyToOne
@JoinColumn(name = "type_id")
private BookType type;
@Column(nullable = false)
private Integer totalCopies;
@Column(nullable = false)
private Integer availableCopies;
@Column(nullable = false)
private LocalDate publishDate;
@Column(length = 500)
private String description;
@Version
private Integer version;
}
实体设计时的几个关键点:
- 使用
@Version实现乐观锁,防止并发修改冲突 - 关联关系使用
@ManyToOne/@OneToMany等注解 - 字段约束通过
@Column的nullable、length等属性设置
2.2 数据库初始化脚本
创建 schema.sql 用于初始化表结构:
CREATE TABLE IF NOT EXISTS book_type (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL UNIQUE,
description VARCHAR(200)
);
CREATE TABLE IF NOT EXISTS book (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(100) NOT NULL,
author VARCHAR(50) NOT NULL,
isbn VARCHAR(20) NOT NULL UNIQUE,
type_id BIGINT NOT NULL,
total_copies INT NOT NULL CHECK(total_copies > 0),
available_copies INT NOT NULL CHECK(available_copies >= 0),
publish_date DATE NOT NULL,
description VARCHAR(500),
FOREIGN KEY (type_id) REFERENCES book_type(id)
);
3. 核心业务逻辑实现
3.1 借阅业务流程实现
借阅业务涉及多个步骤的校验和状态变更,典型实现如下:
@Service
@RequiredArgsConstructor
@Transactional
public class BorrowService {
private final BookRepository bookRepository;
private final BorrowCardRepository cardRepository;
private final BorrowRecordRepository recordRepository;
public BorrowResult borrowBook(Long bookId, String cardNumber) {
// 1. 验证借阅证有效性
BorrowCard card = cardRepository.findByCardNumber(cardNumber)
.orElseThrow(() -> new BusinessException("借阅证不存在"));
if (!card.isActive()) {
throw new BusinessException("借阅证已失效");
}
// 2. 检查图书可用性
Book book = bookRepository.findById(bookId)
.orElseThrow(() -> new BusinessException("图书不存在"));
if (book.getAvailableCopies() <= 0) {
throw new BusinessException("该图书已全部借出");
}
// 3. 检查用户借阅上限
long borrowedCount = recordRepository.countByCardAndReturnDateIsNull(card);
if (borrowedCount >= card.getMaxBorrowLimit()) {
throw new BusinessException("已达到最大借阅数量限制");
}
// 4. 创建借阅记录
BorrowRecord record = new BorrowRecord();
record.setBook(book);
record.setCard(card);
record.setBorrowDate(LocalDate.now());
record.setDueDate(LocalDate.now().plusDays(card.getBorrowDays()));
recordRepository.save(record);
// 5. 更新图书库存
book.setAvailableCopies(book.getAvailableCopies() - 1);
bookRepository.save(book);
return new BorrowResult(record.getId(), record.getDueDate());
}
}
3.2 归还业务实现
归还业务需要考虑逾期处理等场景:
public ReturnResult returnBook(Long recordId) {
BorrowRecord record = recordRepository.findById(recordId)
.orElseThrow(() -> new BusinessException("借阅记录不存在"));
if (record.getReturnDate() != null) {
throw new BusinessException("该图书已归还");
}
// 设置归还日期
record.setReturnDate(LocalDate.now());
recordRepository.save(record);
// 更新图书库存
Book book = record.getBook();
book.setAvailableCopies(book.getAvailableCopies() + 1);
bookRepository.save(book);
// 检查是否逾期
if (record.getReturnDate().isAfter(record.getDueDate())) {
OverdueRecord overdue = createOverdueRecord(record);
return new ReturnResult(true, overdue.getFineAmount());
}
return new ReturnResult(false, null);
}
4. RESTful API设计
4.1 控制器层实现
采用Spring MVC实现RESTful接口,以下是图书管理API示例:
@RestController
@RequestMapping("/api/books")
@RequiredArgsConstructor
public class BookController {
private final BookService bookService;
@GetMapping
public Page<BookDTO> searchBooks(
@RequestParam(required = false) String title,
@RequestParam(required = false) String author,
@RequestParam(required = false) Long typeId,
@PageableDefault(sort = "title", direction = ASC) Pageable pageable) {
BookSearchCriteria criteria = new BookSearchCriteria(title, author, typeId);
return bookService.searchBooks(criteria, pageable);
}
@PostMapping
@ResponseStatus(CREATED)
public BookDTO addBook(@Valid @RequestBody BookCreationDTO dto) {
return bookService.addBook(dto);
}
@PutMapping("/{id}")
public BookDTO updateBook(@PathVariable Long id, @Valid @RequestBody BookUpdateDTO dto) {
return bookService.updateBook(id, dto);
}
@DeleteMapping("/{id}")
@ResponseStatus(NO_CONTENT)
public void deleteBook(@PathVariable Long id) {
bookService.deleteBook(id);
}
}
4.2 API文档生成
使用SpringDoc OpenAPI自动生成API文档,配置示例:
@Configuration
public class OpenApiConfig {
@Bean
public OpenAPI libraryOpenAPI() {
return new OpenAPI()
.info(new Info().title("Library Management API")
.description("API for library management system")
.version("v1.0")
.license(new License().name("Apache 2.0")))
.externalDocs(new ExternalDocumentation()
.description("Library Management Wiki")
.url("https://example.com/docs"));
}
}
访问 /v3/api-docs 获取JSON格式的API定义,或 /swagger-ui.html 查看交互式文档。
5. 高级功能实现
5.1 预约排队系统
当图书全部借出时,用户可以加入等待队列:
public class BookReservationService {
private final ReservationQueueRepository queueRepository;
@Transactional
public ReservationResult reserveBook(Long bookId, String cardNumber) {
// 检查是否已有预约记录
boolean exists = queueRepository.existsByBookIdAndCardNumber(bookId, cardNumber);
if (exists) {
throw new BusinessException("您已预约该图书");
}
// 获取当前排队位置
int queuePosition = queueRepository.countByBookId(bookId) + 1;
// 创建预约记录
ReservationQueue queue = new ReservationQueue();
queue.setBookId(bookId);
queue.setCardNumber(cardNumber);
queue.setQueuePosition(queuePosition);
queue.setReserveDate(LocalDateTime.now());
queueRepository.save(queue);
return new ReservationResult(queue.getId(), queuePosition);
}
@Scheduled(fixedRate = 3600000) // 每小时检查一次
public void processReservationQueue() {
// 获取可预约的图书列表
List<Long> availableBooks = getAvailableBooks();
availableBooks.forEach(bookId -> {
// 获取队列中的第一个用户
Optional<ReservationQueue> firstInQueue =
queueRepository.findFirstByBookIdOrderByReserveDateAsc(bookId);
firstInQueue.ifPresent(queue -> {
// 发送通知
sendReservationNotification(queue.getCardNumber(), bookId);
// 从队列中移除
queueRepository.delete(queue);
});
});
}
}
5.2 逾期计算策略
实现灵活的逾期计算规则:
public interface OverdueCalculator {
BigDecimal calculateFine(LocalDate dueDate, LocalDate returnDate);
}
@Component
@RequiredArgsConstructor
public class SimpleOverdueCalculator implements OverdueCalculator {
private final OverduePolicyRepository policyRepository;
@Override
public BigDecimal calculateFine(LocalDate dueDate, LocalDate returnDate) {
if (!returnDate.isAfter(dueDate)) {
return BigDecimal.ZERO;
}
long daysOverdue = ChronoUnit.DAYS.between(dueDate, returnDate);
OverduePolicy policy = policyRepository.findActivePolicy()
.orElseThrow(() -> new BusinessException("逾期政策未配置"));
return policy.getDailyFine().multiply(new BigDecimal(daysOverdue));
}
}
6. 系统安全与性能优化
6.1 安全防护措施
- 认证与授权 :集成Spring Security实现RBAC
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
private final UserDetailsService userDetailsService;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll()
.requestMatchers("/api/books/**").hasAnyRole("LIBRARIAN", "ADMIN")
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.sessionManagement(session ->
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.addFilterBefore(jwtAuthFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
- 数据验证 :使用Bean Validation注解
public class BookCreationDTO {
@NotBlank
@Size(max = 100)
private String title;
@NotBlank
@Size(max = 50)
private String author;
@ISBN
private String isbn;
@NotNull
@Positive
private Integer totalCopies;
@NotNull
@PastOrPresent
private LocalDate publishDate;
}
6.2 性能优化技巧
- 查询优化 :使用JPA的
@EntityGraph解决N+1问题
public interface BookRepository extends JpaRepository<Book, Long> {
@EntityGraph(attributePaths = {"type"})
Page<Book> findByTitleContaining(String title, Pageable pageable);
}
- 缓存策略 :对热点数据使用Spring Cache
@Service
@RequiredArgsConstructor
@CacheConfig(cacheNames = "books")
public class BookService {
private final BookRepository bookRepository;
@Cacheable(key = "#id")
public BookDTO getBookById(Long id) {
return bookRepository.findById(id)
.map(this::convertToDTO)
.orElseThrow(() -> new EntityNotFoundException("Book not found"));
}
@CacheEvict(key = "#id")
public void updateBook(Long id, BookUpdateDTO dto) {
// 更新逻辑
}
}
- 批量操作 :使用JPA的批量插入
spring.jpa.properties.hibernate.jdbc.batch_size=50
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true
7. 测试策略与实践
7.1 单元测试示例
使用JUnit 5和Mockito测试服务层:
@ExtendWith(MockitoExtension.class)
class BorrowServiceTest {
@Mock
private BookRepository bookRepository;
@Mock
private BorrowCardRepository cardRepository;
@InjectMocks
private BorrowService borrowService;
@Test
void shouldThrowWhenBookNotAvailable() {
// 准备测试数据
Book book = new Book();
book.setAvailableCopies(0);
when(bookRepository.findById(anyLong()))
.thenReturn(Optional.of(book));
// 验证异常抛出
assertThrows(BusinessException.class,
() -> borrowService.borrowBook(1L, "CARD123"));
}
}
7.2 集成测试配置
使用 @SpringBootTest 进行集成测试:
@SpringBootTest
@AutoConfigureMockMvc
class BookControllerIT {
@Autowired
private MockMvc mockMvc;
@Test
void shouldReturn404WhenBookNotFound() throws Exception {
mockMvc.perform(get("/api/books/999"))
.andExpect(status().isNotFound());
}
}
测试数据准备可以使用 @Sql 注解:
@Test
@Sql(scripts = "/test-data/books.sql")
void shouldReturnBookWhenExists() throws Exception {
mockMvc.perform(get("/api/books/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.title").value("Effective Java"));
}
8. 部署与监控
8.1 Docker化部署
创建 Dockerfile 构建镜像:
FROM eclipse-temurin:17-jdk-jammy
WORKDIR /app
COPY build/libs/library-management-*.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
使用Docker Compose编排服务:
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/library_db
SPRING_DATASOURCE_USERNAME: library_admin
depends_on:
mysql:
condition: service_healthy
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: library_db
MYSQL_USER: library_admin
MYSQL_PASSWORD: secure_password
ports:
- "3306:3306"
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 10s
retries: 5
8.2 监控与指标
集成Spring Boot Actuator监控端点:
management:
endpoints:
web:
exposure:
include: health, metrics, prometheus
metrics:
export:
prometheus:
enabled: true
关键监控指标包括:
- 数据库连接池使用情况
- HTTP请求延迟和错误率
- JVM内存和GC情况
- 业务指标(如每日借阅量)
9. 项目扩展方向
9.1 微服务化改造
当系统规模扩大时,可考虑拆分为以下服务:
- 用户服务 :管理借阅者和管理员账户
- 目录服务 :管理图书元数据
- 借阅服务 :处理借阅、归还等业务流程
- 通知服务 :发送预约到货、逾期提醒等通知
9.2 前端技术选型建议
现代前端技术栈组合推荐:
- 框架 :React/Vue 3
- UI库 :Ant Design/Element Plus
- 状态管理 :Redux Toolkit/Pinia
- 构建工具 :Vite
9.3 智能化功能扩展
- 推荐系统 :基于用户借阅历史的协同过滤推荐
- 逾期预测 :使用机器学习预测可能的逾期用户
- 智能排架 :优化图书物理存放位置
在实际项目中,我们采用了分阶段实现策略,先确保核心借阅流程的稳定性,再逐步添加高级功能。对于数据一致性要求高的操作,使用 @Transactional 确保原子性,并通过重试机制处理乐观锁冲突。
更多推荐

所有评论(0)