news 2026/7/14 23:57:51

计算机毕业设计262—基于Springboot+Vue3+Ai对话的图书馆图书借阅系统(源代码+数据库+开题+PPT)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
计算机毕业设计262—基于Springboot+Vue3+Ai对话的图书馆图书借阅系统(源代码+数据库+开题+PPT)

毕设所有选题:
https://blog.csdn.net/2303_76227485/article/details/131104075

基于Springboot+Vue3+Ai对话的图书馆图书借阅系统(源代码+数据库+开题+PPT)

项目编号:262

一、系统介绍

本项目前后端分离,分为用户、管理员2种角色。

1、用户:

  • 图书协同过滤推荐、热门图书、热门分类、图书搜索、图书借阅、续借、还书、图书预约、评论、查看通知、AI助手、个人信息

2、管理员:

  • 图书管理:图书信息录入,图书信息查询,图书信息修改,图书信息删除,图书分类管理
  • 用户管理:启用禁用
  • 借阅管理:借阅记录查询,图书归还,借阅审核,逾期管理
  • 预约管理:预约记录查询,预约取消,预约通知
  • 评论管理:评论查看,评论删除
  • 统计分析:借阅统计,热门图书排行,用户借阅排行,图书库存统计,逾期统计

3、亮点:

  • 实现ai对话优化用户体验
  • 使用协同过滤算法为用户推荐图书
  • 后台首页大屏使用echarts图表统计,更直观的看出系统的运行数据
  • 使用定时任务查询逾期的借阅并通知用户

二、所用技术

后端技术栈:

  • Springboot3
  • mybatisPlus
  • Jwt
  • Mysql
  • Maven

前端技术栈:

  • Vue3
  • Vue-router
  • axios
  • elementPlus
  • echarts

三、环境介绍

基础环境 :IDEA/eclipse, JDK1.8, Mysql5.7及以上, Maven3.6, node16, navicat, 通义千问apikey

所有项目以及源代码本人均调试运行无问题 可支持远程调试运行

四、页面截图

1、用户:
















2、管理员:









五、浏览地址

前台地址:http://localhost:3000

  • 用户账号密码:zhangsan/123456

  • 管理员账户密码:admin/123456

六、部署教程

  1. 使用Navicat或者其它工具,在mysql中创建对应名称的数据库,并执行项目的sql文件

  2. 使用IDEA/Eclipse导入backend项目,若为maven项目请选择maven,等待依赖下载完成

  3. 修改application.yml里面的数据库配置和通义千问的apikey配置,src/main/java/com/library/LibraryManagementApplication.java启动后端项目

  4. vscode或idea打开frontend项目

  5. 在编译器中打开terminal,执行npm install 依赖下载完成后执行 npm run serve,执行成功后会显示访问地址

七、协同过滤推荐部分代码

@OverridepublicIPage<BookVO>recommendBooksByCF(LonguserId,Integerpage,Integersize){// 1:获取目标用户的借阅记录(已借阅的图书ID)Set<Long>userBorrowedBookIds=getBorrowedBookIds(userId);if(CollectionUtils.isEmpty(userBorrowedBookIds)){// 无借阅历史,返回热门图书(兜底策略)returngetHotBooks(page,size);}// 2:构建用户-图书借阅矩阵(用户ID -> 图书ID -> 借阅次数)Map<Long,Map<Long,Integer>>userBookMatrix=buildUserBookMatrix();// 3:计算目标用户与其他用户的相似度Map<Long,Double>userSimilarityMap=calculateUserSimilarity(userId,userBookMatrix);// 4:筛选相似度最高的N个用户List<Long>similarUserIds=userSimilarityMap.entrySet().stream().sorted((e1,e2)->Double.compare(e2.getValue(),e1.getValue())).limit(SIMILAR_USER_COUNT).map(Map.Entry::getKey).collect(Collectors.toList());// 5:收集相似用户借阅过、目标用户未借阅的图书,计算推荐分数Map<Long,Double>bookRecommendScore=calculateBookRecommendScore(similarUserIds,userSimilarityMap,userBookMatrix,userBorrowedBookIds);// 6:按推荐分数排序,过滤无效图书,分页返回returngetRecommendBookPage(bookRecommendScore,page,size);}/** * 获取用户已借阅的图书ID */privateSet<Long>getBorrowedBookIds(LonguserId){returnborrowRecordMapper.selectList(newcom.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<BorrowRecord>().eq(BorrowRecord::getUserId,userId).in(BorrowRecord::getStatus,Constants.BORROW_STATUS_BORROWED,Constants.BORROW_STATUS_RETURNED)).stream().map(BorrowRecord::getBookId).collect(Collectors.toSet());}/** * 构建用户-图书借阅矩阵 */privateMap<Long,Map<Long,Integer>>buildUserBookMatrix(){// 查询所有有效借阅记录(排除待审核/拒绝的)List<BorrowRecord>allBorrowRecords=borrowRecordMapper.selectList(newcom.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<BorrowRecord>().in(BorrowRecord::getStatus,Constants.BORROW_STATUS_BORROWED,Constants.BORROW_STATUS_RETURNED));// 统计每个用户对每本书的借阅次数Map<Long,Map<Long,Integer>>userBookMatrix=newHashMap<>();for(BorrowRecordrecord:allBorrowRecords){LonguserId=record.getUserId();LongbookId=record.getBookId();userBookMatrix.putIfAbsent(userId,newHashMap<>());Map<Long,Integer>bookCountMap=userBookMatrix.get(userId);bookCountMap.put(bookId,bookCountMap.getOrDefault(bookId,0)+1);}// 过滤借阅次数过少的记录(减少噪声)userBookMatrix.values().forEach(bookCountMap->bookCountMap.entrySet().removeIf(entry->entry.getValue()<MIN_BORROW_COUNT));// 过滤无有效借阅的用户userBookMatrix.entrySet().removeIf(entry->entry.getValue().isEmpty());returnuserBookMatrix;}/** * 计算目标用户与其他用户的余弦相似度 */privateMap<Long,Double>calculateUserSimilarity(LongtargetUserId,Map<Long,Map<Long,Integer>>userBookMatrix){Map<Long,Integer>targetUserRatings=userBookMatrix.get(targetUserId);if(CollectionUtils.isEmpty(targetUserRatings)){returnnewHashMap<>();}Map<Long,Double>similarityMap=newHashMap<>();for(Map.Entry<Long,Map<Long,Integer>>entry:userBookMatrix.entrySet()){LongotherUserId=entry.getKey();if(otherUserId.equals(targetUserId)){continue;// 跳过自己}Map<Long,Integer>otherUserRatings=entry.getValue();// 计算余弦相似度doublesimilarity=calculateCosineSimilarity(targetUserRatings,otherUserRatings);if(similarity>0){// 只保留正相似的用户similarityMap.put(otherUserId,similarity);}}returnsimilarityMap;}/** * 计算两个用户的余弦相似度 * 公式:相似度 = (A·B) / (|A| * |B|),其中A·B是点积,|A|是A的模长 */privatedoublecalculateCosineSimilarity(Map<Long,Integer>userARatings,Map<Long,Integer>userBRatings){// 找出共同借阅的图书Set<Long>commonBookIds=newHashSet<>(userARatings.keySet());commonBookIds.retainAll(userBRatings.keySet());if(commonBookIds.isEmpty()){return0.0;// 无共同图书,相似度为0}// 计算点积doubledotProduct=0.0;for(LongbookId:commonBookIds){dotProduct+=userARatings.get(bookId)*userBRatings.get(bookId);}// 计算模长doublenormA=Math.sqrt(userARatings.values().stream().mapToDouble(r->r*r).sum());doublenormB=Math.sqrt(userBRatings.values().stream().mapToDouble(r->r*r).sum());if(normA==0||normB==0){return0.0;}returndotProduct/(normA*normB);}/** * 计算图书推荐分数(相似用户相似度 * 借阅次数) */privateMap<Long,Double>calculateBookRecommendScore(List<Long>similarUserIds,Map<Long,Double>userSimilarityMap,Map<Long,Map<Long,Integer>>userBookMatrix,Set<Long>userBorrowedBookIds){Map<Long,Double>bookScoreMap=newHashMap<>();for(LongsimilarUserId:similarUserIds){doublesimilarity=userSimilarityMap.get(similarUserId);Map<Long,Integer>similarUserBooks=userBookMatrix.get(similarUserId);for(Map.Entry<Long,Integer>entry:similarUserBooks.entrySet()){LongbookId=entry.getKey();intborrowCount=entry.getValue();// 跳过目标用户已借阅的图书if(userBorrowedBookIds.contains(bookId)){continue;}// 推荐分数 = 相似度 * 借阅次数(加权)doublescore=similarity*borrowCount;bookScoreMap.put(bookId,bookScoreMap.getOrDefault(bookId,0.0)+score);}}returnbookScoreMap;}/** * 过滤无效图书,分页返回推荐列表 */privateIPage<BookVO>getRecommendBookPage(Map<Long,Double>bookScoreMap,Integerpage,Integersize){if(CollectionUtils.isEmpty(bookScoreMap)){// 无推荐结果,返回热门图书returngetHotBooks(page,size);}// 按推荐分数降序排序List<Long>recommendBookIds=bookScoreMap.entrySet().stream().sorted((e1,e2)->Double.compare(e2.getValue(),e1.getValue())).map(Map.Entry::getKey).collect(Collectors.toList());// 过滤下架/库存不足的图书List<Long>validBookIds=recommendBookIds.stream().filter(bookId->{Bookbook=bookMapper.selectById(bookId);returnbook!=null&&book.getStatus()==Constants.BOOK_STATUS_ONLINE&&book.getAvailableQuantity()>0;}).collect(Collectors.toList());// 分页处理Page<BookVO>resultPage=newPage<>(page,size);intstart=(page-1)*size;intend=Math.min(start+size,validBookIds.size());if(start>=validBookIds.size()){resultPage.setRecords(newArrayList<>());resultPage.setTotal(0);returnresultPage;}// 查询分页后的图书VOList<Long>pageBookIds=validBookIds.subList(start,end);List<BookVO>bookVOs=pageBookIds.stream().map(this::getBookById).collect(Collectors.toList());resultPage.setRecords(bookVOs);resultPage.setTotal(validBookIds.size());returnresultPage;}/** * 兜底策略:返回热门图书(按借阅次数排序) */privateIPage<BookVO>getHotBooks(Integerpage,Integersize){Page<Book>bookPage=newPage<>(page,size);// 查询上架且有库存的热门图书(按借阅次数降序)List<Book>hotBooks=bookMapper.selectList(newcom.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<Book>().eq(Book::getStatus,Constants.BOOK_STATUS_ONLINE).gt(Book::getAvailableQuantity,0).orderByDesc(Book::getBorrowCount));// 分页处理Page<BookVO>resultPage=newPage<>(page,size);intstart=(page-1)*size;intend=Math.min(start+size,hotBooks.size());if(start>=hotBooks.size()){resultPage.setRecords(newArrayList<>());resultPage.setTotal(0);returnresultPage;}List<BookVO>bookVOs=hotBooks.subList(start,end).stream().map(book->this.getBookById(book.getId())).collect(Collectors.toList());resultPage.setRecords(bookVOs);resultPage.setTotal(hotBooks.size());returnresultPage;}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/2 13:08:01

【C/C++】MPSC无锁队列

MPSC Queue&#xff1a;多生产者单消费者无锁队列 SPSC无锁队列&#xff0c;参考https://blog.csdn.net/qq_46105170/article/details/157458924。 概述 MPSC&#xff08;Multi-Producer Single-Consumer&#xff09;队列是一种允许多个生产者线程同时写入、但只有一个消费者…

作者头像 李华
网站建设 2026/7/1 12:28:20

本地部署FastGPT使用在线大语言模型

FastGPT 是一个基于 LLM 大语言模型的知识库问答系统&#xff0c;提供开箱即用的数据处理、模型调用等能力&#xff0c;它背后依赖OneApi开源项目来访问各种大语言模型提供的能力。各大语言模型提供的访问接口规范不尽相同&#xff0c;为此OneApi项目提供了统一的API接口去对接…

作者头像 李华
网站建设 2026/7/14 3:29:49

为pngme拓展对gif格式支持

为pngme拓展对gif格式支持引言GIF格式简读GIF结构原始数据到结构数据读屏幕逻辑数据读图像数据读取扩展块读取子块链将文本写入应用扩展块结构数据到原始数据引言 前序文章为pngme拓展加密功能与jpg格式支持-CSDN博客&#xff0c;其中所提到的东西&#xff0c;本文不会重复提及…

作者头像 李华