简介一套面向高校课程设计与期末大作业场景的智能笔记系统完整源码包。后端采用Spring Boot前端使用Vue3并配套微信小程序端覆盖笔记分类、笔记信息、笔记标签的增删改查以及智能排序、按收藏推荐、评论管理和配置管理等模块适合完成前后端分离项目的计算机专业学生参考复用。资源共679个文件10.46MB代码以82个java后端接口、72个vue前端组件、50个wxss与44个wxml小程序页面文件为主另有sql脚本、json配置及png素材目录结构清晰便于按模块定位。已包含完整前后端分离工程和数据库脚本可降低环境搭建与联调成本已有34人浏览学习。对照源码可掌握Spring Boot统一CRUD与权限注解设计、Vue3和小程序多端复用思路以及智能排序和推荐功能的具体落地方式适合作为课程设计答辩或期末大作业的完整参考。1. 智能笔记系统是什么先别急着写代码三端分离的工程要这样拆你拿到的这套工程名字里已经把技术栈交代清楚了后端 SpringBoot、管理端 Vue3、移动端微信小程序再配一份 SQL 脚本做数据初始化。很多第一次接触前后端分离笔记系统的开发者会先被“智能”两个字带偏以为里面有什么高深算法。实际上这里的“智能”更多体现在笔记的标签归类、全文检索、多端同步这些产品功能上技术骨架就是一套典型的三端分离应用。这套方案能解决的问题很直接一个笔记数据源三种使用入口。管理员在 Web 端维护分类和用户普通用户拿微信小程序随手记所有数据通过 SpringBoot 提供的 RESTful API 读写 MySQL。适合拿来当毕设骨架、企业内部知识库原型或者作为你学习 SpringBoot Vue3 小程序三端联调的练手工程。2. 先看系统架构SpringBoot 接口层与 Vue3 小程序双前端的边界划分2.1 三个端各管什么事数据模型与请求流向拆这种工程的第一件事不是启动项目而是把三个端的职责边界画清楚。常见做法是后端只做数据管理和业务校验不关心页面长什么样Vue3 后台负责管理类界面比如用户列表、笔记分类统计、系统配置微信小程序负责高频的移动端操作比如快速记录、语音转文字入口如果集成了、按标签浏览笔记。三者通过 HTTP 接口通信数据模型以笔记note为核心向外关联用户user、分类category、标签tag三张表。数据流向通常是这样的小程序端调用wx.request发起请求携带 token 访问 SpringBoot 的/api/note/list之类的接口后端从 MySQL 查出数据返回 JSON小程序渲染列表。Vue3 管理端走的是同样的逻辑只是接口前缀可能是/admin而且多了一层权限校验。这套工程前后端分离体现在代码层面就是两个独立的前端工程加一个后端工程彼此之间只认接口契约不共享任何页面代码。2.2 SpringBoot 工程结构controller / service / mapper 三层的常见组织方式后端拿到手先看包结构。标准 SpringBoot 工程会按controller、service、mapper或dao、entity或model分包。Controller 层只做参数接收和结果封装Service 层写业务逻辑Mapper 层用 MyBatis-Plus 或 JdbcTemplate 操作数据库。如果你的工程里用的是 MyBatis-Plus那么 Mapper 接口一般继承BaseMapperT单表 CRUD 不用写 SQL复杂查询才需要自己写Select注解或 XML 映射文件。看application.yml配置文件时重点确认三个参数数据源连接、端口号、MyBatis-Plus 的日志级别。数据源决定了 SQL 脚本能不能接得上端口号决定了前端代理往哪转发日志级别决定了排查问题时 SQL 能不能打出来。常见配置长这样server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/note_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: yourpassword driver-class-name: com.mysql.cj.jdbc.Driver mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: id-type: auto这里serverTimezoneAsia/Shanghai是必须写的漏掉它会在连接 MySQL 8.x 时直接报时区错误。id-type: auto表示主键走数据库自增。MyBatis-Plus 的日志配置只在开发环境打开生产环境记得关掉否则每次请求都会把 SQL 打到日志里量大的时候磁盘很快就满了。2.3 Vue3 管理端怎么组织与后端对接的接口封装方式Vue3 工程一般基于 Vite 构建目录结构里有src/api、src/views、src/router这些约定。与后端对接的关键在src/api目录下的请求封装文件通常会基于 axios 实例化一个带拦截器的请求对象。拦截器做两件事请求发出前从 localStorage 或 Pinia 里取 token 塞到 header响应回来后判断 HTTP 状态码401 跳登录页其他错误统一弹提示。import axios from axios const request axios.create({ baseURL: /api, timeout: 10000 }) request.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers.Authorization Bearer ${token} } return config }) request.interceptors.response.use( response response.data, error { if (error.response error.response.status 401) { window.location.href /login } return Promise.reject(error) } ) export default request这段封装里baseURL用了相对路径/api这意味着开发环境下需要在 Vite 配置代理把请求转发到后端 8080 端口部署时则由 Nginx 做路径转发。如果直接写死http://localhost:8080会出现两个问题一是跨域二是换环境部署要改代码。用相对路径配合代理是前后端分离项目里最稳妥的做法。3. 把工程跑起来从 SQL 脚本到双端启动的最小操作顺序3.1 SQL 脚本导入执行顺序与两种常见执行方式拿到带 SQL 脚本的工程第一步永远是建库建表。先看 SQL 文件里有没有CREATE DATABASE语句有的话直接执行整个文件没有就先手动建库再执行。执行方式有两种命令行和图形化工具。命令行适合服务器环境图形化工具适合本地开发。命令行执行方式mysql -u root -p -e CREATE DATABASE IF NOT EXISTS note_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; mysql -u root -p note_db /path/to/note_db.sql图形化工具Navicat 或 DataGrip执行时注意一个细节打开 SQL 文件后先检查文件开头的建库语句如果你的连接已经选了某个库再执行CREATE DATABASE会冲突。我一般做法是用工具先建好空库然后右键这个库选择运行 SQL 文件只执行建表和插入数据的部分。执行成功后检查一下表数量笔记系统一般至少五张表——用户表、分类表、笔记表、标签表、笔记标签关联表外加一个数据字典表。3.2 后端启动JDK 版本、Maven 依赖与端口占用排查后端启动的坑大半出在环境不一致。SpringBoot 版本和 JDK 版本有对应关系SpringBoot 2.x 要求 JDK 8 或 11SpringBoot 3.x 必须 JDK 17 起。如果工程用的是 SpringBoot 2.4你本地装的是 JDK 17虽然能编过但某些旧版依赖会出幺蛾子。先看pom.xml里的spring-boot-starter-parent版本号再对照本地java -version。# 查看本地 JDK 版本 java -version # Maven 清理并重新打包跳过测试 mvn clean package -DskipTests # 启动后端 java -jar target/notes-server.jarMaven 打包慢是常态第一次会把依赖全下下来。如果报Failed to configure a DataSource说明配置文件和数据库对不上回去检查用户名密码。如果报端口被占用# 查看 8080 端口占用 lsof -i :8080 # 杀掉占用进程macOS/LinuxWindows 用 netstat -ano | findstr 8080 kill -9 PID开发阶段我更推荐直接在 IDEA 里启动Debug 模式能看到完整的异常栈。启动成功的标志不是控制台打印了 Spring 图标就算完要看到Started Application in x.xx seconds这行日志才算数。3.3 Vue3 管理端启动npm install 慢与代理配置Vue3 工程启动相对简单但npm install卡住是新手遇到最多的玄学问题。镜像源换成国内源能解决大部分情况。# 设置镜像源 npm config set registry https://registry.npmmirror.com # 安装依赖 npm install # 启动开发服务器 npm run dev启动后浏览器访问http://localhost:5173能看到登录页说明前端基础没问题。但此时点登录大概率失败因为请求代理还没配。打开vite.config.js确认 proxy 配置import { defineConfig } from vite import vue from vitejs/plugin-vue export default defineConfig({ plugins: [vue()], server: { port: 5173, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } })changeOrigin: true这个参数别漏它让后端看到的请求头 Host 变成后端地址避免某些后端框架做域名校验时拒绝请求。配置改完要重启 dev server 才生效。3.4 微信小程序端导入AppID 选择与后端地址绑定微信小程序端的坑和 Web 端完全不一样。用微信开发者工具导入工程时AppID 可以选择测试号不需要注册企业账号。导入后第一件事是找到config.js或utils/request.js里的baseURL把它改成后端可访问的地址。注意这里不能用localhost因为微信开发者工具模拟器里 localhost 指向的是你电脑真机预览时指向的是手机自己必须填局域网 IP 或已部署的服务器域名。// config.js module.exports { baseURL: http://192.168.1.100:8080/api, timeout: 10000 }填局域网 IP 时要保证手机和电脑在同一网段并且后端启动时监听了0.0.0.0而不是默认的127.0.0.1。在application.yml里加一行配置server: address: 0.0.0.0这是很多小程序连不上后端的隐藏原因——后端只听本地回环地址局域网根本访问不到。4. 微信小程序登录与笔记同步token 鉴权与接口对接的三个关键参数4.1 微信登录流程code 换 openid 再换 token微信小程序登录和传统的用户名密码登录完全不一样。小程序端调用wx.login()拿到临时code把这个 code 发给后端后端拿着 code 加上小程序的appid和secret去微信接口换openid和session_key。拿到 openid 后后端再去数据库查这个用户是否存在不存在就自动注册一个。整个流程里前端全程不接触secret这是安全底线。// 小程序端 wx.login({ success: async (res) { if (res.code) { const loginRes await request.post(/auth/login, { code: res.code }) wx.setStorageSync(token, loginRes.data.token) } } })对应地后端 Controller 接收这个 code然后调用微信接口PostMapping(/auth/login) public Result login(RequestBody LoginRequest req) { String url https://api.weixin.qq.com/sns/jscode2session ?appid appid secret secret js_code req.getCode() grant_typeauthorization_code; // 用 RestTemplate 或 OkHttp 发起 GET 请求 // 解析返回的 openid // 查询或创建用户生成 JWT token 返回 }grant_type固定值authorization_code这是微信接口文档规定的js_code就是前端传过来的临时凭证有效期只有五分钟而且只能用一次。后端拿到session_key不要存库它只用于解密手机号和用户敏感数据普通场景用不到。4.2 小程序端请求封装携 token 请求与 401 处理小程序没有 axios 用但wx.request的封装逻辑类似。所有请求都走同一个入口自动把 token 加进去响应回来后统一处理业务码。// utils/request.js const request (url, method GET, data {}) { return new Promise((resolve, reject) { const token wx.getStorageSync(token) wx.request({ url: ${baseURL}${url}, method, data, header: { Content-Type: application/json, Authorization: token ? Bearer ${token} : }, success: (res) { if (res.data.code 200) { resolve(res.data.data) } else if (res.data.code 401) { // token 过期重新登录 wx.removeStorageSync(token) wx.navigateTo({ url: /pages/login/login }) reject(res.data) } else { wx.showToast({ title: res.data.message, icon: none }) reject(res.data) } }, fail: reject }) }) }这里后端返回的code是业务状态码和 HTTP 状态码是两回事。好的后端设计会统一返回结构比如{ code: 200, message: success, data: {...} }。前端只判断业务码HTTP 200 不代表业务成功。4.3 笔记同步逻辑增量拉取与本地缓存移动端笔记应用有个刚需场景是弱网或断网时也能记。完整做法是本地缓存 增量同步笔记表加一个updated_at时间戳字段每次拉取时带上本地最新时间后端只返回这个时间点之后修改的笔记。-- 增量同步的核心查询 SELECT * FROM note WHERE user_id #{userId} AND updated_at #{lastSyncTime} ORDER BY updated_at ASC小程序端把返回的增量数据合并进本地 storage同时维护一个lastSyncTime变量。本地新增的笔记先存 storage 里标记sync_status 0等网络恢复后调批量提交接口。这个方案实现成本不高但体验提升明显——用户不关心网络细节打开就能记同步在后台静默完成。5. 三端联调避坑SpringBoot 版本冲突、跨域与小程序白屏的 5 条排查记录5.1 SpringBoot 版本太高导致的依赖不兼容现象后端启动直接抛NoSuchMethodError或者ClassNotFoundException指向某个第三方库的方法或类。原因工程 pom 里锁了 SpringBoot 2.7但你本地 Maven 仓库里有更高版本的传递依赖或者你自己加依赖时没有指定版本Maven 拉了最新版和 SpringBoot 2.7 的自动配置冲突。最常见的是 MyBatis-Plus 和 SpringBoot 3.x 的兼容问题——旧版 MyBatis-Plus 不支持 SpringBoot 3 的 Jakarta 命名空间。解决打开 pom.xml检查所有依赖是否显式声明了版本号。SpringBoot 父 POM 管理的依赖不要重复写版本没管理的必须写。确认无误后执行mvn clean package -DskipTests重新构建。换过 JDK 版本后这一步尤其有必要。5.2 vue 打包放进 SpringBoot 后页面白屏现象开发环境一切正常npm run build后把 dist 目录放进 SpringBoot 的static目录访问首页白屏控制台报资源 404。原因Vue Router 默认用 history 模式路由路径是/notes这种真实路径。后端没有配置路径回退刷新或直接访问子路径时后端找不到对应的 controller返回 404。解决两个方案二选一。路由改成 hash 模式最简单createWebHashHistory()替换掉createWebHistory()URL 会变成/#/notes不存在服务端回退问题。或者后端加一个路由回退配置把所有非 API 请求转发到index.html。我倾向 hash 模式省事且稳定微信小程序内嵌 WebView 时也不容易出问题。5.3 小程序自定义导航栏在不同机型上位置错乱现象安卓手机上导航栏标题偏上iPhone 上偏下或者胶囊按钮遮挡标题。原因自定义导航栏时你把标题写死在固定高度上。但微信小程序的胶囊按钮右上角那三个点位置在不同机型上不一样顶部状态栏高度也不同。解决动态获取胶囊信息用wx.getMenuButtonBoundingClientRect()拿到胶囊的 top 和 height再往上推算出导航栏的安全高度。这个需求在小程序笔记应用里几乎是必做的因为默认导航栏样式太简陋但自定义导航栏的计算逻辑特别容易踩坑。5.4 前后端分离跨域后端配了 CORS 还是报错现象Vue3 管理端访问后端接口浏览器控制台报Access-Control-Allow-Origin相关错误。原因前后端分离部署在不同端口前端 5173后端 8080浏览器同源策略拦截了响应。有时候后端配了CrossOrigin但只解决了部分请求比如预检请求 OPTIONS 没被处理。解决开发阶段直接用 Vite 代理绕开跨域问题。部署阶段用 Nginx 做反向代理前端请求/api由 Nginx 转发到后端。后端配 CORS 是最后的手段而且要注意allowedOrigin不能用*否则携带着Authorization头的请求会被拦。5.5 数据库时间差了 8 小时现象小程序里显示的笔记时间比实际时间晚了 8 小时。原因MySQL 的serverTimezone默认是 UTCJSON 序列化时间时又按 UTC 输出传到前端再转一次本地时区一来一回就差了 8 小时。解决JDBC URL 里加serverTimezoneAsia/Shanghai同时确认 MySQL 时区变量也正确。注意serverTimezone加在 JDBC URL 上只管连接层如果 MySQL 全局时区是SYSTEM而系统时区是 UTC依然会差。-- 查看 MySQL 时区 SELECT global.time_zone, session.time_zone; -- 临时修改时区重启失效 SET global time_zone 08:00;6. 进阶技巧把笔记检索从 LIKE 查询升级成本地词向量整套系统跑通之后你可以开始琢磨“智能”这个点。大多数笔记系统自带搜索就是一条WHERE title LIKE %关键词%的 SQL分词的边界问题、同义词问题、错别字问题全都解决不了。这里的进阶方向是做一个不依赖外部服务、不烧钱、离线可跑的本地检索增强。我会用 jieba 分词 TF-IDF 向量化 余弦相似度做一个轻量级语义搜索。笔记量在万条以内时性能完全够用。核心思路是笔记入库时先分词计算每个词的 TF-IDF 权重存成倒排索引搜索时把查询词同样分词算查询向量和每篇笔记向量的余弦相似度按相似度排序返回 TopK。import jieba from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.metrics.pairwise import cosine_similarity import numpy as np # 假设 notes 是从数据库查出的笔记列表 def search_notes(query, notes, top_k5): # 对所有笔记做分词 corpus [ .join(jieba.lcut(n[title] n[content])) for n in notes] vectorizer TfidfVectorizer() matrix vectorizer.fit_transform(corpus) # 查询词分词并向量化 query_vec vectorizer.transform([ .join(jieba.lcut(query))]) # 算余弦相似度 scores cosine_similarity(query_vec, matrix).flatten() # 取 TopK 并返回 indices np.argsort(scores)[::-1][:top_k] return [(notes[i], float(scores[i])) for i in indices]fit_transform只在应用启动时执行一次把已入库的笔记全量建索引。新笔记写入时增量更新matrix即可。TfidfVectorizer默认会过滤停用词但中文停用词表需要自己补充“的、了、吗、呢”这类词在英文默认词表里根本不存在。分词时去掉标点和数字否则特征矩阵会变得稀疏且没有意义。这个方案有个代价不小的坑jieba 的首次加载会很慢大约 2 到 3 秒如果在小程序每次搜索都调后端现算用户会明显感觉到卡顿。我当时的做法是在后端启动时预热分词器把词典加载到内存里搜索接口只走矩阵运算。实测一万条笔记的检索响应时间能做到 200 毫秒以内这个体感远好于让用户等 3 秒。做这个升级时踩过一次翻车直接把全部笔记的全文拼接成一个大字符串去 vectorizer结果相似度全部趋同TopK 返回的内容完全不相关。原因是 TF-IDF 里的 IDF 在文档数很少时区分度极低一篇文档和一百篇文档的 IDF 计算结果完全不是一个量级。后来把笔记按段落切分每段作为一个独立文档参与索引搜索结果才变得可用。这个教训让我意识到索引粒度直接影响检索质量并不是把数据丢给算法就完事。希望这套笔记系统的拆解和排错思路能帮到你照着这个路径走一遍你就能摸清前后端分离项目从零到交付的所有关键节点。本文还有配套的精品资源点击获取