Spring Boot 3.2 + Vue 3 图书馆管理系统实战:5大核心模块与8张数据库表设计
在数字化转型浪潮下,传统图书馆管理系统正面临技术架构升级的迫切需求。本文将基于Spring Boot 3.2和Vue 3这一黄金技术组合,带你从零构建一个现代化图书馆管理系统。不同于传统理论分析,我们将聚焦工程化实现,通过清晰的代码示例和架构设计,帮助初中级开发者掌握企业级应用开发的核心要领。
1. 技术栈选型与项目初始化
1.1 现代技术栈优势分析
选择Spring Boot 3.2和Vue 3的组合并非偶然,这一技术搭配在2023年全栈开发领域展现出显著优势:
-
后端技术栈 :
- Spring Boot 3.2:内置Tomcat 10支持,提供GraalVM原生镜像编译能力
- MyBatis-Plus 3.5.3:简化CRUD操作,动态SQL生成
- Spring Security 6:OAuth2资源服务器配置
- Hibernate Validator 8:参数校验标准化
-
前端技术栈 :
- Vue 3.3 + Composition API:更好的TypeScript支持
- Pinia 2:状态管理解决方案
- Element Plus 2.3:UI组件库
- Axios 1.3:HTTP客户端
# 后端项目初始化
spring init --dependencies=web,mybatis,security,validation
-g com.library -a library-backend -n library-backend
# 前端项目初始化
npm create vue@latest library-frontend
1.2 项目结构设计
合理的项目结构是大型应用的基础,我们采用分层架构设计:
library-system/
├── backend/ # Spring Boot项目
│ ├── src/
│ │ ├── main/
│ │ │ ├── java/com/library/
│ │ │ │ ├── config/ # 配置类
│ │ │ │ ├── controller/ # 控制器层
│ │ │ │ ├── dto/ # 数据传输对象
│ │ │ │ ├── entity/ # 数据库实体
│ │ │ │ ├── mapper/ # MyBatis接口
│ │ │ │ ├── service/ # 业务逻辑层
│ │ │ │ └── util/ # 工具类
│ │ │ └── resources/
│ │ │ ├── mapper/ # XML映射文件
│ │ │ └── application.yml
├── frontend/ # Vue项目
│ ├── src/
│ │ ├── api/ # API请求封装
│ │ ├── assets/ # 静态资源
│ │ ├── components/ # 公共组件
│ │ ├── router/ # 路由配置
│ │ ├── stores/ # Pinia状态管理
│ │ ├── styles/ # 全局样式
│ │ ├── utils/ # 工具函数
│ │ └── views/ # 页面组件
└── docs/ # 项目文档
2. 核心业务模块设计
2.1 用户认证模块
采用JWT作为认证方案,实现多角色权限控制:
// Spring Security配置核心代码
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.requestMatchers("/api/librarian/**").hasAnyRole("LIBRARIAN", "ADMIN")
.anyRequest().authenticated()
)
.sessionManagement(session ->
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.addFilterBefore(jwtFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@Bean
JwtAuthenticationFilter jwtFilter() {
return new JwtAuthenticationFilter();
}
}
前端路由守卫实现:
// 路由权限控制
router.beforeEach((to, from, next) => {
const authStore = useAuthStore()
const requiresAuth = to.matched.some(record => record.meta.requiresAuth)
const requiredRoles = to.meta.roles || []
if (requiresAuth && !authStore.isAuthenticated) {
next('/login')
} else if (requiredRoles.length && !requiredRoles.includes(authStore.user.role)) {
next('/403')
} else {
next()
}
})
2.2 图书管理模块
实现图书的CRUD操作及复杂查询功能,采用MyBatis-Plus增强功能:
@Service
public class BookServiceImpl extends ServiceImpl<BookMapper, Book>
implements BookService {
@Override
public Page<BookVO> searchBooks(BookQueryDTO queryDTO) {
return lambdaQuery()
.like(StringUtils.hasText(queryDTO.getTitle()), Book::getTitle, queryDTO.getTitle())
.like(StringUtils.hasText(queryDTO.getAuthor()), Book::getAuthor, queryDTO.getAuthor())
.eq(queryDTO.getCategoryId() != null, Book::getCategoryId, queryDTO.getCategoryId())
.eq(Book::getStatus, BookStatus.AVAILABLE)
.page(queryDTO.toPage())
.convert(this::toVO);
}
private BookVO toVO(Book book) {
// 对象转换逻辑
}
}
前端采用组合式API实现分页查询:
<script setup>
const searchForm = reactive({
title: '',
author: '',
category: null
})
const { data, pending, execute } = useAsyncData(
'books',
() => $fetch('/api/books', {
query: {
...searchForm,
page: pagination.value.page,
size: pagination.value.size
}
})
)
const pagination = reactive({
page: 1,
size: 10,
total: 0
})
watchDebounced(
searchForm,
() => {
pagination.page = 1
execute()
},
{ debounce: 500 }
)
</script>
3. 数据库设计与优化
3.1 核心表结构设计
系统共设计8张核心表,关系模型如下:
| 表名 | 主要字段 | 说明 |
|---|---|---|
book
| id, isbn, title, author, status | 图书基本信息 |
book_category
| id, name, parent_id | 图书分类 |
user
| id, username, password, role | 系统用户 |
borrower
| id, user_id, card_number | 借阅者信息 |
borrow_record
| id, book_id, borrower_id, status | 借阅记录 |
reservation
| id, book_id, borrower_id, expire | 预约记录 |
fine
| id, record_id, amount, status | 罚款记录 |
system_log
| id, user_id, operation, time | 系统操作日志 |
3.2 索引优化策略
针对高频查询场景设计索引:
-- 图书表索引
CREATE INDEX idx_book_title ON book(title);
CREATE INDEX idx_book_author ON book(author);
CREATE INDEX idx_book_status ON book(status);
-- 借阅记录索引
CREATE INDEX idx_borrow_borrower ON borrow_record(borrower_id);
CREATE INDEX idx_borrow_book ON borrow_record(book_id);
CREATE INDEX idx_borrow_status ON borrow_record(status);
-- 复合索引示例
CREATE INDEX idx_book_search ON book(title, author, status);
3.3 事务处理示例
借书业务中的事务控制:
@Transactional
public BorrowResult borrowBook(Long bookId, Long borrowerId) {
// 1. 检查图书状态
Book book = bookMapper.selectById(bookId);
if (book == null || book.getStatus() != BookStatus.AVAILABLE) {
return BorrowResult.failed("图书不可借");
}
// 2. 检查借阅者资格
Borrower borrower = borrowerMapper.selectById(borrowerId);
if (borrower == null || borrower.getStatus() != BorrowerStatus.ACTIVE) {
return BorrowResult.failed("借阅者状态异常");
}
// 3. 创建借阅记录
BorrowRecord record = new BorrowRecord();
record.setBookId(bookId);
record.setBorrowerId(borrowerId);
record.setBorrowDate(LocalDate.now());
record.setDueDate(LocalDate.now().plusDays(30));
record.setStatus(BorrowStatus.ON_LOAN);
borrowRecordMapper.insert(record);
// 4. 更新图书状态
book.setStatus(BookStatus.BORROWED);
bookMapper.updateById(book);
return BorrowResult.success(record);
}
4. 前后端交互设计
4.1 API规范设计
采用RESTful风格设计API接口:
| 资源 | GET | POST | PUT | DELETE |
|---|---|---|---|---|
| /api/books | 获取图书列表 | 新增图书 | - | - |
| /api/books/{id} | 获取图书详情 | - | 更新图书信息 | 删除图书 |
| /api/borrow | 查询借阅记录 | 借书操作 | 还书操作 | - |
| /api/reservations | 查询预约记录 | 创建预约 | 取消预约 | - |
4.2 Axios封装示例
前端请求统一封装:
// api/request.js
const service = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
timeout: 10000
})
// 请求拦截器
service.interceptors.request.use(config => {
const authStore = useAuthStore()
if (authStore.token) {
config.headers.Authorization = `Bearer ${authStore.token}`
}
return config
})
// 响应拦截器
service.interceptors.response.use(
response => {
return response.data
},
error => {
if (error.response?.status === 401) {
const authStore = useAuthStore()
authStore.logout()
router.push('/login')
}
return Promise.reject(error)
}
)
export default service
4.3 WebSocket实时通知
实现图书逾期提醒功能:
// WebSocket配置
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws")
.setAllowedOriginPatterns("*")
.withSockJS();
}
}
// 通知服务
@Service
@RequiredArgsConstructor
public class NotificationService {
private final SimpMessagingTemplate messagingTemplate;
public void sendOverdueNotice(Long borrowerId, String message) {
messagingTemplate.convertAndSend(
"/topic/user/" + borrowerId,
new Notification("OVERDUE", message)
);
}
}
前端订阅通知:
// 逾期提醒订阅
const socket = new SockJS('/ws')
const stompClient = Stomp.over(socket)
stompClient.connect({}, () => {
stompClient.subscribe(`/topic/user/${userId}`, (message) => {
const notification = JSON.parse(message.body)
if (notification.type === 'OVERDUE') {
showOverdueAlert(notification.content)
}
})
})
5. 部署与性能优化
5.1 容器化部署方案
使用Docker Compose编排服务:
version: '3.8'
services:
backend:
build: ./backend
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
- DB_URL=jdbc:mysql://db:3306/library
depends_on:
- db
- redis
frontend:
build: ./frontend
ports:
- "80:80"
depends_on:
- backend
db:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=library
volumes:
- db_data:/var/lib/mysql
redis:
image: redis:alpine
ports:
- "6379:6379"
volumes:
db_data:
5.2 性能优化策略
后端优化:
- 启用Spring Boot Actuator监控端点
- 配置HikariCP连接池参数
- 添加二级缓存(Redis)
- 启用GZIP压缩响应
前端优化:
- 路由懒加载
- 组件异步加载
- 静态资源CDN加速
- 启用HTTP/2协议
# 示例:HikariCP配置
spring:
datasource:
hikari:
maximum-pool-size: 20
minimum-idle: 5
idle-timeout: 30000
max-lifetime: 1800000
connection-timeout: 30000
5.3 日志与监控
集成Prometheus和Grafana监控:
// 监控配置
@Configuration
public class MetricsConfig {
@Bean
MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
return registry -> registry.config().commonTags(
"application", "library-system"
);
}
@Bean
public TimedAspect timedAspect(MeterRegistry registry) {
return new TimedAspect(registry);
}
}
前端性能监控:
// 前端性能指标收集
const metrics = {
FCP: 0,
LCP: 0,
FID: 0,
CLS: 0
}
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.name === 'first-contentful-paint') {
metrics.FCP = entry.startTime
} else if (entry.name === 'largest-contentful-paint') {
metrics.LCP = entry.startTime
}
}
})
observer.observe({ type: 'paint', buffered: true })
1984



被折叠的 条评论
为什么被折叠?



