1. 项目概述
这个图书管理系统是一个典型的Web应用开发项目,采用前后端分离架构。前端使用Vue.js框架构建用户界面,后端基于SpringBoot框架提供RESTful API服务,数据存储采用MySQL关系型数据库,通过MyBatis实现数据持久化操作。整套系统实现了图书信息的增删改查、借阅归还管理、用户权限控制等核心功能模块。
提示:完整源码的提供意味着这是一个教学演示项目,适合Java全栈开发学习者参考。我在实际开发中发现,这类管理系统虽然业务逻辑不复杂,但完整实现前后端协作流程对新手特别有价值。
2. 技术栈选型分析
2.1 后端技术组合
SpringBoot 2.x作为基础框架,主要基于以下考虑:
- 自动配置特性大幅减少XML配置
- 内嵌Tomcat简化部署流程
- starter依赖管理规范
- 与MyBatis的天然集成支持
数据库操作层选择MyBatis而非JPA的原因是:
- 需要编写明确SQL语句的教学演示
- 复杂查询场景更直观可控
- 与现有Java技能栈更匹配
2.2 前端技术方案
Vue 2.x版本的选择考量:
- 渐进式框架学习曲线平缓
- 组件化开发模式清晰
- 与Element UI组件库完美配合
- 相比React更轻量快速上手
实测开发中,axios处理HTTP请求时需要注意:
// 请求拦截器需统一处理token axios.interceptors.request.use(config => { config.headers['Authorization'] = getToken() return config })3. 数据库设计要点
3.1 核心表结构
图书表(book)关键字段设计:
CREATE TABLE `book` ( `id` int(11) NOT NULL AUTO_INCREMENT, `isbn` varchar(20) NOT NULL COMMENT '国际标准书号', `title` varchar(100) NOT NULL, `author` varchar(50) NOT NULL, `publisher` varchar(50) DEFAULT NULL, `publish_date` date DEFAULT NULL, `status` tinyint(1) DEFAULT '1' COMMENT '1-在馆 2-借出', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `idx_isbn` (`isbn`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;3.2 关联关系处理
借阅记录表(borrow)设计特别注意:
- 建立与用户表(user)和图书表(book)的外键约束
- 添加索引提高查询效率
- 使用逻辑删除而非物理删除
ALTER TABLE `borrow` ADD INDEX `idx_user_book` (`user_id`, `book_id`), ADD CONSTRAINT `fk_borrow_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`), ADD CONSTRAINT `fk_borrow_book` FOREIGN KEY (`book_id`) REFERENCES `book` (`id`);4. 后端核心实现
4.1 RESTful API设计
图书管理接口规范示例:
GET /api/books 查询图书列表 POST /api/books 新增图书 GET /api/books/{id} 获取图书详情 PUT /api/books/{id} 更新图书信息 DELETE /api/books/{id} 删除图书记录SpringBoot中统一响应格式:
@RestControllerAdvice public class ResponseAdvice implements ResponseBodyAdvice<Object> { @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { return Result.success(body); } }4.2 业务逻辑层实现
图书借阅服务关键代码:
@Service @Transactional public class BorrowServiceImpl implements BorrowService { @Autowired private BookMapper bookMapper; @Autowired private BorrowMapper borrowMapper; @Override public Result borrowBook(Integer userId, Integer bookId) { // 检查图书状态 Book book = bookMapper.selectById(bookId); if (book == null || book.getStatus() != BookStatus.AVAILABLE) { throw new BusinessException("图书不可借阅"); } // 创建借阅记录 Borrow borrow = new Borrow(); borrow.setUserId(userId); borrow.setBookId(bookId); borrow.setBorrowDate(LocalDate.now()); borrow.setDueDate(LocalDate.now().plusDays(30)); borrowMapper.insert(borrow); // 更新图书状态 book.setStatus(BookStatus.BORROWED); bookMapper.updateById(book); return Result.success(); } }5. 前端关键功能实现
5.1 图书列表展示
使用Element UI表格组件实现:
<template> <el-table :data="bookList" border style="width: 100%"> <el-table-column prop="isbn" label="ISBN" width="180"></el-table-column> <el-table-column prop="title" label="书名"></el-table-column> <el-table-column prop="author" label="作者"></el-table-column> <el-table-column label="状态"> <template #default="{row}"> <el-tag :type="row.status === 1 ? 'success' : 'danger'"> {{ row.status === 1 ? '在馆' : '借出' }} </el-tag> </template> </el-table-column> </el-table> </template> <script> export default { data() { return { bookList: [] } }, created() { this.fetchBooks() }, methods: { async fetchBooks() { const res = await this.$http.get('/api/books') this.bookList = res.data } } } </script>5.2 表单验证处理
图书新增表单验证规则:
export default { data() { return { rules: { isbn: [ { required: true, message: '请输入ISBN', trigger: 'blur' }, { pattern: /^\d{10,13}$/, message: 'ISBN格式不正确' } ], title: [ { required: true, message: '请输入书名', trigger: 'blur' }, { min: 1, max: 100, message: '长度在1到100个字符' } ] } } } }6. 系统安全与优化
6.1 权限控制实现
基于Spring Security的JWT认证方案:
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .antMatchers("/api/auth/**").permitAll() .anyRequest().authenticated() .and() .addFilter(new JwtAuthenticationFilter(authenticationManager())) .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS); } }6.2 性能优化实践
- MyBatis二级缓存配置:
<settings> <setting name="cacheEnabled" value="true"/> </settings> <mapper namespace="com.example.mapper.BookMapper"> <cache eviction="LRU" flushInterval="60000" size="512"/> </mapper>- 前端路由懒加载:
const BookList = () => import('./views/BookList.vue') const BookDetail = () => import('./views/BookDetail.vue')7. 部署与测试
7.1 多环境配置
SpringBoot的profile配置示例:
# application-dev.yml server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/library_dev username: devuser password: dev123 # application-prod.yml server: port: 80 spring: datasource: url: jdbc:mysql://prod-db:3306/library username: produser password: ${DB_PASSWORD}7.2 自动化测试方案
JUnit5集成测试示例:
@SpringBootTest @AutoConfigureMockMvc class BookControllerTest { @Autowired private MockMvc mockMvc; @Test void shouldReturnBookList() throws Exception { mockMvc.perform(get("/api/books") .header("Authorization", "Bearer testtoken")) .andExpect(status().isOk()) .andExpect(jsonPath("$.data.length()").value(10)); } }8. 开发经验与技巧
- 接口文档自动生成:使用Swagger UI时,注意在Controller方法上添加详细注解:
@ApiOperation("根据ID获取图书详情") @GetMapping("/{id}") public Result<Book> getById(@PathVariable Integer id) { return Result.success(bookService.getById(id)); }- 前端跨域问题解决方案:开发环境下配置proxyTable:
module.exports = { devServer: { proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } } }- 数据库连接池优化建议:
# application.properties spring.datasource.hikari.maximum-pool-size=20 spring.datasource.hikari.minimum-idle=5 spring.datasource.hikari.idle-timeout=30000 spring.datasource.hikari.connection-timeout=2000- 实际开发中遇到的典型问题:
- MyBatis结果集映射问题:当数据库字段名与Java属性名不一致时,要么使用别名,要么配置mapUnderscoreToCamelCase
- Vue组件通信混乱:复杂场景建议使用Vuex集中管理状态
- 日期时间处理:统一使用Java 8的LocalDateTime,避免时区问题