一、 项目背景与意义在全民阅读和知识共享的时代背景下传统图书借阅模式面临着空间限制、管理成本高、书籍流通率低等挑战。共享书屋作为一种新型的社区化图书共享模式旨在通过技术手段盘活闲置图书资源促进知识传播与社区互动。本系统基于 SpringBoot 后端与微信小程序前端进行设计与实现其核心意义在于资源高效利用将个人或社区的闲置图书数字化管理实现跨地域、跨时间的共享极大提升书籍的流通率和利用率。便捷的用户体验用户通过熟悉的微信小程序即可完成找书、预约、借阅、归还、评价等全流程操作无需下载额外APP使用门槛低。智能化管理系统后台实现对书籍库存、用户借阅记录、预约状态、逾期提醒等功能的自动化管理降低人工管理成本。社区文化构建通过书籍共享、读书笔记分享、用户评价等功能构建线上阅读社区增强用户粘性与互动。技术实践价值项目整合了当前主流的企业级后端框架与国民级前端生态为学习全栈开发、微服务架构、小程序开发提供了完整的实战案例。二、 技术栈选型2.1 后端技术栈 (SpringBoot)核心框架Spring Boot 2.7Web框架Spring MVC数据持久层MyBatis-Plus / Spring Data JPA数据库MySQL 8.0缓存Redis (用于会话管理、热点数据缓存、分布式锁)安全与认证Spring Security JWT (JSON Web Token)API文档Swagger2 / Knife4j消息队列RabbitMQ / RocketMQ (用于异步处理借阅通知、逾期提醒等)文件存储本地存储 / 阿里云OSS / 腾讯云COS (用于存储书籍封面图片)部署与监控Docker, Nginx, Spring Boot Admin, Prometheus Grafana2.2 前端技术栈 (微信小程序)开发框架微信小程序原生框架 / uni-app (跨端可选)UI组件库Vant Weapp / WeUI状态管理小程序全局变量 / mobx-miniprogram网络请求微信小程序原生 wx.request / 封装后的axios风格库地图服务腾讯位置服务 (用于展示书屋地理位置)云开发 (可选)微信云开发 (提供数据库、存储、云函数可简化后端部署)2.3 开发与协作工具版本控制Git项目管理Maven / Gradle接口调试Postman / ApifoxIDEIntelliJ IDEA (后端), 微信开发者工具 (前端)三、 系统核心功能模块设计3.1 用户端 (微信小程序)用户认证微信一键登录、手机号绑定。书屋浏览地图模式/列表模式查看附近书屋查看书屋详情地址、开放时间、藏书量。书籍检索按书名、作者、ISBN、分类进行搜索支持扫码添加书籍。借阅流程查看书籍详情 - 预约/直接借阅 - 生成取书码 - 到柜扫码取书 - 扫码归还。个人中心我的借阅记录、我的预约、我的捐赠、读书笔记、积分与信用体系。消息通知借阅成功、预约到书、逾期提醒、系统公告等微信模板消息推送。社区互动书籍评价、评分、读书笔记分享与点赞。3.2 管理端 (Web后台可选SpringBoot Admin或独立前端)系统管理用户管理、角色权限管理管理员、书屋管理员、普通用户。书屋管理书屋信息的增删改查地理位置设置柜机管理。书籍管理书籍信息录入支持ISBN扫码自动填充、分类管理、库存管理、书籍上架/下架。借阅管理所有借阅记录查询、逾期处理、手动归还操作。数据统计借阅量统计、热门书籍排行、用户活跃度分析、库存预警。运营管理公告发布、积分规则设置、消息推送管理。四、 核心代码实现示例4.1 后端核心书籍借阅服务层 (SpringBoot MyBatis-Plus)package com.sharedlibrary.book.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.sharedlibrary.book.entity.Book; import com.sharedlibrary.book.entity.BorrowRecord; import com.sharedlibrary.book.entity.User; import com.sharedlibrary.book.enums.BookStatusEnum; import com.sharedlibrary.book.enums.BorrowStatusEnum; import com.sharedlibrary.book.exception.BusinessException; import com.sharedlibrary.book.mapper.BookMapper; import com.sharedlibrary.book.mapper.BorrowRecordMapper; import com.sharedlibrary.book.service.BorrowService; import com.sharedlibrary.book.util.RedisLockUtil; import com.sharedlibrary.book.util.SnowflakeIdWorker; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; /** 书籍借阅服务实现类 */ Slf4j Service RequiredArgsConstructor public class BorrowServiceImpl extends ServiceImplBorrowRecordMapper, BorrowRecord implements BorrowService { private final BookMapper bookMapper; private final RedisLockUtil redisLockUtil; private final SnowflakeIdWorker idWorker; /** 用户借阅书籍 param userId 用户ID param bookId 书籍ID param libraryId 书屋ID return 借阅记录ID */ Override Transactional(rollbackFor Exception.class) public Long borrowBook(Long userId, Long bookId, Long libraryId) { // 分布式锁防止超借 String lockKey book_borrow_lock: bookId; boolean lockAcquired redisLockUtil.tryLock(lockKey, 10, 3000); if (!lockAcquired) { throw new BusinessException(系统繁忙请稍后再试); } try { // 1. 检查书籍状态 Book book bookMapper.selectById(bookId); if (book null) { throw new BusinessException(书籍不存在); } if (!BookStatusEnum.AVAILABLE.getCode().equals(book.getStatus())) { throw new BusinessException(书籍当前不可借阅状态 book.getStatus()); } // 2. 检查用户借阅资格如信用分、未归还数量等此处省略 // ... // 3. 创建借阅记录 BorrowRecord record new BorrowRecord(); record.setId(idWorker.nextId()); record.setUserId(userId); record.setBookId(bookId); record.setLibraryId(libraryId); record.setBorrowTime(LocalDateTime.now()); record.setExpectedReturnTime(LocalDateTime.now().plusDays(book.getBorrowDays())); // 根据书籍配置借阅天数 record.setStatus(BorrowStatusEnum.BORROWED.getCode()); this.save(record); // 4. 更新书籍状态为“已借出” book.setStatus(BookStatusEnum.BORROWED.getCode()); book.setBorrowRecordId(record.getId()); bookMapper.updateById(book); log.info(用户[{}]成功借阅书籍[{}]借阅记录ID[{}], userId, bookId, record.getId()); return record.getId(); } finally { redisLockUtil.unlock(lockKey); } } /** 用户归还书籍 param recordId 借阅记录ID param libraryId 归还的书屋ID */ Override Transactional(rollbackFor Exception.class) public void returnBook(Long recordId, Long libraryId) { BorrowRecord record this.getById(recordId); if (record null) { throw new BusinessException(借阅记录不存在); } if (!BorrowStatusEnum.BORROWED.getCode().equals(record.getStatus())) { throw new BusinessException(书籍不在借阅状态无法归还); } // 1. 更新借阅记录状态为“已归还” record.setStatus(BorrowStatusEnum.RETURNED.getCode()); record.setActualReturnTime(LocalDateTime.now()); record.setReturnLibraryId(libraryId); this.updateById(record); // 2. 更新书籍状态为“可借阅” Book book bookMapper.selectById(record.getBookId()); if (book ! null) { book.setStatus(BookStatusEnum.AVAILABLE.getCode()); book.setBorrowRecordId(null); bookMapper.updateById(book); } // 3. 处理逾期逻辑计算逾期天数扣减信用分等 handleOverdueIfNecessary(record); log.info(借阅记录[{}]已归还书籍[{}]状态已更新, recordId, record.getBookId()); } private void handleOverdueIfNecessary(BorrowRecord record) { // 逾期处理逻辑... } }4.2 后端核心微信小程序登录与JWT认证配置package com.sharedlibrary.auth.config; import com.sharedlibrary.auth.filter.JwtAuthenticationTokenFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; /** Spring Security 配置类 */ Configuration EnableGlobalMethodSecurity(prePostEnabled true) public class SecurityConfig extends WebSecurityConfigurerAdapter { Autowired private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter; Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } Bean Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } Override protected void configure(HttpSecurity http) throws Exception { http // 关闭csrf .csrf().disable() // 不通过Session获取SecurityContext .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeRequests() // 允许匿名访问的接口 .antMatchers( /api/wx/login, // 微信登录 /api/books/list, // 书籍列表 /api/libraries/nearby, // 附近书屋 /swagger-ui/, // Swagger UI /v2/api-docs, /webjars/ ).permitAll() // 除上面外的所有请求全部需要鉴权认证 .anyRequest().authenticated(); // 添加JWT过滤器 http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); // 允许跨域 http.cors(); } }4.3 前端核心微信小程序书籍列表页 (WXML JS)!-- pages/book/list/list.wxml -- view classpage-container !-- 搜索栏 -- view classsearch-bar van-search value{{searchKeyword}} placeholder搜索书名/作者/ISBN bind:searchonSearch bind:clearonClearSearch / /view !-- 筛选标签 -- scroll-view classfilter-tags scroll-x van-tag wx:for{{categoryList}} wx:keyid type{{activeCategoryId item.id ? primary : plain}} bind:taponCategoryTap>// pages/book/list/list.js Page({ data: { searchKeyword: , categoryList: [], activeCategoryId: 0, // 0表示全部 bookList: [], pageNum: 1, pageSize: 10, loading: false, hasMore: true }, onLoad(options) { this.loadCategories(); this.loadBookList(true); }, // 加载分类 loadCategories() { wx.request({ url: https://your-api.com/api/categories, success: (res) { if (res.data.code 200) { this.setData({ categoryList: [{ id: 0, name: 全部 }, ...res.data.data] }); } } }); }, // 加载书籍列表 loadBookList(reset false) { if (this.data.loading || (!this.data.hasMore !reset)) return; this.setData({ loading: true }); const { pageNum, pageSize, searchKeyword, activeCategoryId } this.data; const params { pageNum: reset ? 1 : pageNum, pageSize, keyword: searchKeyword, categoryId: activeCategoryId 0 ? null : activeCategoryId }; wx.request({ url: https://your-api.com/api/books, data: params, success: (res) { if (res.data.code 200) { const newList res.data.data.list || []; this.setData({ bookList: reset ? newList : [...this.data.bookList, ...newList], hasMore: newList.length pageSize, pageNum: reset ? 2 : pageNum 1, loading: false }); } }, fail: () { this.setData({ loading: false }); wx.showToast({ title: 加载失败, icon: none }); } }); }, // 搜索 onSearch(e) { this.setData({ searchKeyword: e.detail }); this.loadBookList(true); }, // 清空搜索 onClearSearch() { this.setData({ searchKeyword: }); this.loadBookList(true); }, // 切换分类 onCategoryTap(e) { const id e.currentTarget.dataset.id; this.setData({ activeCategoryId: id }); this.loadBookList(true); }, // 点击书籍跳转详情 onBookTap(e) { const bookId e.currentTarget.dataset.id; wx.navigateTo({ url: /pages/book/detail/detail?id${bookId} }); }, // 上拉加载更多 onReachBottom() { this.loadBookList(); }, // 下拉刷新 onPullDownRefresh() { this.loadBookList(true); wx.stopPullDownRefresh()