在数字化管理需求日益增长的背景下,本文将设计一个基于B/S架构的图书管理系统。系统采用前后端分离开发模式,后端使用Spring Boot框架实现业务逻辑,前端通过JavaScript+HTML+CSS构建交互界面,MySQL数据库完成数据持久化存储。该系统可满足图书馆日常管理需求,具备图书查询、借阅、归还等核心功能。
技术栈 | 说明 |
|---|---|
后端框架 | Spring Boot 3.1.4 + MyBatis-Plus 3.5.3.1 |
前端技术 | HTML5 + CSS3 + JavaScript ES6 + Bootstrap 5.3.0 |
数据库 | MySQL 8.0.33 |
安全框架 | Spring Security 6.1.3 |
开发工具 | IntelliJ IDEA 2023.2 + Visual Studio Code 1.89.1 |

字段名 | 类型 | 约束条件 | 说明 |
|---|---|---|---|
id | INT | PRIMARY KEY AUTO_INCREMENT | 用户ID |
username | VARCHAR(50) | UNIQUE NOT NULL | 用户名 |
password | VARCHAR(100) | NOT NULL | 加密密码 |
role | VARCHAR(20) | DEFAULT 'USER' | 角色(USER/ADMIN) |
字段名 | 类型 | 约束条件 | 说明 |
|---|---|---|---|
id | INT | PRIMARY KEY AUTO_INCREMENT | 图书ID |
title | VARCHAR(100) | NOT NULL | 书名 |
author | VARCHAR(50) | NOT NULL | 作者 |
isbn | VARCHAR(20) | UNIQUE | ISBN编号 |
stock | INT | DEFAULT 0 | 库存数量 |
字段名 | 类型 | 约束条件 | 说明 |
|---|---|---|---|
id | INT | PRIMARY KEY AUTO_INCREMENT | 记录ID |
user_id | INT | FOREIGN KEY REFERENCES users(id) | 用户ID |
book_id | INT | FOREIGN KEY REFERENCES books(id) | 图书ID |
borrow_date | DATE | DEFAULT CURRENT_DATE | 借阅日期 |
return_date | DATE | NULL | 应还日期 |
status | VARCHAR(20) | DEFAULT 'BORROWED' | 状态(已借/已还) |
package com.example.library.entity;
import jakarta.persistence.*;
import lombok.Data;
import java.time.LocalDate;
@Data
@Entity
@Table(name = "books")
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(unique = true, length = 20)
private String isbn;
@Column(name = "publish_date")
private LocalDate publishDate;
@Column(nullable = false)
private Integer stock = 0;
}package com.example.library.repository;
import com.example.library.entity.Book;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
public interface BookRepository extends JpaRepository<Book, Long> {
List<Book> findByTitleContainingOrAuthorContaining(String title, String author);
@Transactional
@Modifying
@Query("UPDATE Book b SET b.stock = b.stock - 1 WHERE b.id = :bookId AND b.stock > 0")
int decreaseStock(Long bookId);
@Transactional
@Modifying
@Query("UPDATE Book b SET b.stock = b.stock + 1 WHERE b.id = :bookId")
int increaseStock(Long bookId);
}package com.example.library.service;
import com.example.library.entity.Book;
import com.example.library.exception.BusinessException;
import com.example.library.repository.BookRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import static com.example.library.constant.ErrorCode.*;
@Service
@RequiredArgsConstructor
public class BookService {
private final BookRepository bookRepository;
public Page<Book> getBooks(Pageable pageable) {
return bookRepository.findAll(pageable);
}
public List<Book> searchBooks(String keyword) {
return bookRepository.findByTitleContainingOrAuthorContaining(keyword, keyword);
}
public Book addBook(Book book) {
return bookRepository.save(book);
}
public void borrowBook(Long bookId) {
int updated = bookRepository.decreaseStock(bookId);
if (updated == 0) {
throw new BusinessException(BOOK_STOCK_INSUFFICIENT);
}
}
public void returnBook(Long bookId) {
bookRepository.increaseStock(bookId);
}
}package com.example.library.controller;
import com.example.library.entity.Book;
import com.example.library.service.BookService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/books")
@RequiredArgsConstructor
public class BookController {
private final BookService bookService;
@GetMapping
public ResponseEntity<Page<Book>> getBooks(
@PageableDefault(size = 10) Pageable pageable) {
return ResponseEntity.ok(bookService.getBooks(pageable));
}
@GetMapping("/search")
public ResponseEntity<List<Book>> searchBooks(
@RequestParam String keyword) {
return ResponseEntity.ok(bookService.searchBooks(keyword));
}
@PostMapping
public ResponseEntity<Book> addBook(@RequestBody Book book) {
return ResponseEntity.ok(bookService.addBook(book));
}
@PostMapping("/{bookId}/borrow")
public ResponseEntity<Void> borrowBook(@PathVariable Long bookId) {
bookService.borrowBook(bookId);
return ResponseEntity.ok().build();
}
@PostMapping("/{bookId}/return")
public ResponseEntity<Void> returnBook(@PathVariable Long bookId) {
bookService.returnBook(bookId);
return ResponseEntity.ok().build();
}
}package com.example.library.handler;
import com.example.library.exception.BusinessException;
import com.example.library.vo.CommonResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BusinessException.class)
public ResponseEntity<CommonResponse<Void>> handleBusinessException(BusinessException e) {
return ResponseEntity
.status(e.getErrorCode().getHttpStatus())
.body(CommonResponse.error(e.getErrorCode()));
}
}package com.example.library.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/books/**").permitAll()
.anyRequest().authenticated()
);
return http.build();
}
}<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>智慧图书馆管理系统</title>
<!-- Bootstrap 5.3.0 -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Font Awesome 图标 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--primary-color: #3498db;
--secondary-color: #2c3e50;
--accent-color: #e74c3c;
--light-bg: #f8f9fa;
--card-shadow: 0 8px 16px rgba(0,0,0,0.1);
}
body {
background-color: var(--light-bg);
font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
}
.navbar-brand {
font-weight: 700;
color: var(--primary-color);
}
.hero-section {
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
color: white;
padding: 3rem 0;
margin-bottom: 2rem;
}
.card {
border: none;
border-radius: 12px;
transition: transform 0.3s, box-shadow 0.3s;
margin-bottom: 1.5rem;
box-shadow: var(--card-shadow);
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 12px 24px rgba(0,0,0,0.15);
}
.book-cover {
height: 180px;
background-size: cover;
background-position: center;
border-radius: 8px 8px 0 0;
}
.book-actions {
display: flex;
gap: 0.5rem;
margin-top: auto;
}
.action-btn {
flex: 1;
padding: 0.5rem;
}
.card-footer {
background: white;
border-top: none;
}
.stats-card {
border-radius: 12px;
color: white;
margin-bottom: 1.5rem;
}
.stats-card.primary {
background: linear-gradient(to right, #3498db, #2c3e50);
}
.stats-card.warning {
background: linear-gradient(to right, #f39c12, #d35400);
}
.stats-card.success {
background: linear-gradient(to right, #2ecc71, #27ae60);
}
.search-bar {
padding: 1rem;
background: white;
border-radius: 12px;
box-shadow: var(--card-shadow);
margin-bottom: 2rem;
}
.search-input {
border: 2px solid var(--primary-color);
border-radius: 50px;
padding: 0.75rem 1.5rem;
}
.book-detail {
display: none;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 80%;
max-width: 800px;
background: white;
border-radius: 16px;
z-index: 1000;
box-shadow: 0 25px 50px rgba(0,0,0,0.25);
padding: 2rem;
}
.detail-backdrop {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
z-index: 999;
}
</style>
</head>
<body>
<!-- 导航栏 -->
<nav class="navbar navbar-expand-lg bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="#">
<i class="fas fa-book me-2"></i>智慧图书馆
</a>
<button class="navbar-toggler" type="button">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse">
<ul class="navbar-nav me-auto">
<li class="nav-item">
<a class="nav-link active" href="#">
<i class="fas fa-home me-1"></i>首页
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">
<i class="fas fa-book-open me-1"></i>图书管理
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">
<i class="fas fa-user-clock me-1"></i>借阅管理
</a>
</li>
</ul>
<div class="d-flex align-items-center">
<div class="dropdown me-3">
<a class="btn btn-outline-primary dropdown-toggle" href="#" role="button">
<i class="fas fa-bell"></i>
<span class="badge bg-danger position-absolute top-0 start-100 translate-middle">3</span>
</a>
</div>
<div class="dropdown">
<a class="d-flex align-items-center text-decoration-none dropdown-toggle" href="#">
<img src="https://ui-avatars.com/api/?name=用户管理员" class="rounded-circle me-2" width="40" height="40">
<strong>管理员</strong>
</a>
</div>
</div>
</div>
</div>
</nav>
<!-- 头部横幅 -->
<section class="hero-section">
<div class="container text-center">
<h1 class="display-4 fw-bold mb-3">发现知识的无限可能</h1>
<p class="lead mb-4">高效管理您的图书资源,提升借阅体验</p>
<div class="d-flex justify-content-center gap-3">
<button class="btn btn-light btn-lg px-4">
<i class="fas fa-book me-1"></i>浏览藏书
</button>
<button class="btn btn-outline-light btn-lg px-4">
<i class="fas fa-plus me-1"></i>添加书籍
</button>
</div>
</div>
</section>
<div class="container">
<!-- 搜索区域 -->
<div class="search-bar">
<div class="input-group">
<input type="text" class="form-control search-input" placeholder="搜索书名、作者、ISBN...">
<button class="btn btn-primary px-4">
<i class="fas fa-search me-1"></i>搜索
</button>
<button class="btn btn-outline-secondary">
<i class="fas fa-sliders"></i>筛选
</button>
</div>
</div>
<!-- 统计卡片 -->
<div class="row">
<div class="col-md-4">
<div class="stats-card primary p-4 rounded">
<h5>藏书总数</h5>
<div class="d-flex align-items-center justify-content-between">
<h2 class="mb-0">1,254</h2>
<i class="fas fa-book fa-3x opacity-25"></i>
</div>
</div>
</div>
<div class="col-md-4">
<div class="stats-card warning p-4 rounded">
<h5>当前借阅</h5>
<div class="d-flex align-items-center justify-content-between">
<h2 class="mb-0">328</h2>
<i class="fas fa-book-reader fa-3x opacity-25"></i>
</div>
</div>
</div>
<div class="col-md-4">
<div class="stats-card success p-4 rounded">
<h5>可用库存</h5>
<div class="d-flex align-items-center justify-content-between">
<h2 class="mb-0">926</h2>
<i class="fas fa-check-circle fa-3x opacity-25"></i>
</div>
</div>
</div>
</div>
<!-- 图书列表 -->
<div class="row mt-4">
<h3 class="mb-4"><i class="fas fa-bookmark me-2"></i>热门藏书</h3>
<!-- 图书卡片 1 -->
<div class="col-md-4">
<div class="card h-100">
<div class="book-cover" style="background-image: url('https://picsum.photos/id/24/400/300')"></div>
<div class="card-body">
<h5 class="card-title">Java核心技术 卷I</h5>
<p class="text-muted">Cay S. Horstmann</p>
<div class="d-flex justify-content-between align-items-center mt-3">
<span class="badge bg-success">库存: 12</span>
<span class="badge bg-primary">ISBN: 9787115473891</span>
</div>
</div>
<div class="card-footer">
<div class="book-actions">
<button class="btn btn-primary btn-sm action-btn">
<i class="fas fa-bookmark me-1"></i>借阅
</button>
<button class="btn btn-outline-primary btn-sm action-btn">
<i class="fas fa-info-circle me-1"></i>详情
</button>
</div>
</div>
</div>
</div>
<!-- 图书卡片 2 -->
<div class="col-md-4">
<div class="card h-100">
<div class="book-cover" style="background-image: url('https://picsum.photos/id/20/400/300')"></div>
<div class="card-body">
<h5 class="card-title">深入理解JavaScript</h5>
<p class="text-muted">Nicholas C. Zakas</p>
<div class="d-flex justify-content-between align-items-center mt-3">
<span class="badge bg-warning text-dark">库存: 3</span>
<span class="badge bg-primary">ISBN: 9787115422462</span>
</div>
</div>
<div class="card-footer">
<div class="book-actions">
<button class="btn btn-primary btn-sm action-btn">
<i class="fas fa-bookmark me-1"></i>借阅
</button>
<button class="btn btn-outline-primary btn-sm action-btn">
<i class="fas fa-info-circle me-1"></i>详情
</button>
</div>
</div>
</div>
</div>
<!-- 图书卡片 3 -->
<div class="col-md-4">
<div class="card h-100">
<div class="book-cover" style="background-image: url('https://picsum.photos/id/8/400/300')"></div>
<div class="card-body">
<h5 class="card-title">Spring Boot实战</h5>
<p class="text-muted">Craig Walls</p>
<div class="d-flex justify-content-between align-items-center mt-3">
<span class="badge bg-success">库存: 8</span>
<span class="badge bg-primary">ISBN: 9787115451479</span>
</div>
</div>
<div class="card-footer">
<div class="book-actions">
<button class="btn btn-primary btn-sm action-btn">
<i class="fas fa-bookmark me-1"></i>借阅
</button>
<button class="btn btn-outline-primary btn-sm action-btn">
<i class="fas fa-info-circle me-1"></i>详情
</button>
</div>
</div>
</div>
</div>
</div>
<!-- 图书详情模态框 -->
<div class="detail-backdrop"></div>
<div class="book-detail">
<button class="btn btn-sm btn-light position-absolute top-0 end-0 m-3">
<i class="fas fa-times"></i>
</button>
<div class="row">
<div class="col-md-4">
<div class="book-cover h-100" style="background-image: url('https://picsum.photos/id/24/800/600')"></div>
</div>
<div class="col-md-8">
<h3>Java核心技术 卷I</h3>
<p class="lead text-muted">Cay S. Horstmann</p>
<div class="mt-4">
<h5><i class="fas fa-info-circle me-2"></i>图书信息</h5>
<ul class="list-group list-group-flush">
<li class="list-group-item d-flex justify-content-between">
<span>ISBN:</span>
<span class="fw-bold">9787115473891</span>
</li>
<li class="list-group-item d-flex justify-content-between">
<span>出版日期:</span>
<span class="fw-bold">2023-05-15</span>
</li>
<li class="list-group-item d-flex justify-content-between">
<span>分类:</span>
<span class="fw-bold">编程语言/计算机科学</span>
</li>
<li class="list-group-item d-flex justify-content-between">
<span>状态:</span>
<span class="badge bg-success">可借阅</span>
</li>
</ul>
</div>
<div class="mt-4">
<h5><i class="fas fa-file-alt me-2"></i>内容简介</h5>
<p class="card-text">本书针对Java SE 17全面更新,是经典的Java核心技术卷I,提供了完整且深入的Java语言介绍、面向对象程序设计和用户界面编程等内容...</p>
</div>
<div class="mt-4">
<button class="btn btn-primary w-100 py-3">
<i class="fas fa-bookmark me-2"></i>立即借阅本书
</button>
</div>
</div>
</div>
</div>
</div>
<!-- JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script>
// 模拟图书数据
const books = [
{
id: 1,
title: "Java核心技术 卷I",
author: "Cay S. Horstmann",
isbn: "9787115473891",
cover: "https://picsum.photos/id/24/400/300",
description: "本书针对Java SE 17全面更新,是经典的Java核心技术卷I...",
publishDate: "2023-05-15",
category: "编程语言/计算机科学",
stock: 12
},
{
id: 2,
title: "深入理解JavaScript",
author: "Nicholas C. Zakas",
isbn: "9787115422462",
cover: "https://picsum.photos/id/20/400/300",
description: "本书讲解了JavaScript语言的所有部分和功能...",
publishDate: "2022-11-20",
category: "Web开发/前端",
stock: 3
},
{
id: 3,
title: "Spring Boot实战",
author: "Craig Walls",
isbn: "9787115451479",
cover: "https://picsum.photos/id/8/400/300",
description: "Spring改变了Java企业级开发的方式,而Spring Boot改变了Spring应用开发的方式...",
publishDate: "2023-02-10",
category: "后端开发",
stock: 8
}
];
// 详情弹窗交互
document.querySelectorAll('.btn-outline-primary').forEach(button => {
button.addEventListener('click', function() {
const card = this.closest('.card');
const title = card.querySelector('.card-title').textContent;
const book = books.find(b => b.title === title);
if(book) {
const detailView = document.querySelector('.book-detail');
detailView.querySelector('h3').textContent = book.title;
detailView.querySelector('.lead').textContent = book.author;
detailView.querySelector('.book-cover').style.backgroundImage = `url(${book.cover})`;
detailView.querySelectorAll('.list-group-item span.fw-bold')[0].textContent = book.isbn;
detailView.querySelectorAll('.list-group-item span.fw-bold')[1].textContent = book.publishDate;
detailView.querySelectorAll('.list-group-item span.fw-bold')[2].textContent = book.category;
detailView.querySelector('.card-text').textContent = book.description;
document.querySelector('.detail-backdrop').style.display = 'block';
detailView.style.display = 'block';
}
});
});
// 关闭详情弹窗
document.querySelector('.book-detail .btn').addEventListener('click', function() {
document.querySelector('.detail-backdrop').style.display = 'none';
document.querySelector('.book-detail').style.display = 'none';
});
// 搜索功能
document.querySelector('.search-bar button.btn-primary').addEventListener('click', function() {
const searchTerm = document.querySelector('.search-input').value.toLowerCase();
document.querySelectorAll('.card').forEach(card => {
const title = card.querySelector('.card-title').textContent.toLowerCase();
const author = card.querySelector('.text-muted').textContent.toLowerCase();
if(title.includes(searchTerm) || author.includes(searchTerm)) {
card.style.display = '';
card.parentElement.classList.add('animate__animated', 'animate__fadeIn');
} else {
card.style.display = 'none';
}
});
});
// 借阅功能
document.querySelectorAll('.book-actions .btn-primary').forEach(button => {
button.addEventListener('click', function() {
const card = this.closest('.card');
const title = card.querySelector('.card-title').textContent;
const badge = card.querySelector('.badge');
// 简单借阅效果(实际中应调用后端API)
const currentStock = parseInt(badge.textContent.split(' ')[1]);
if(currentStock > 0) {
badge.textContent = `库存: ${currentStock - 1}`;
// 添加成功提示
this.innerHTML = '<i class="fas fa-check me-1"></i>已借阅';
this.classList.remove('btn-primary');
this.classList.add('btn-success');
this.disabled = true;
setTimeout(() => {
alert(`《${title}》借阅成功!请在30天内归还`);
}, 300);
} else {
alert('库存不足,无法借阅');
}
});
});
</script>
</body>
</html>

# 后端部署方式
mvn clean package
java -jar target/library-system-0.0.1-SNAPSHOT.jar
# 前端部署
cd frontend
npm install
npm run build本图书系统通过Spring Boot+HTML+JavaScript技术栈实现了完整的图书管理功能,具备良好的扩展性。未来可扩展电子书资源模块、移动端适配、智能推荐系统等功能。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。