恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0高校汉服租赁系统开发实战

  • 首页
  • 资讯中心
  • /
  • SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0高校汉服租赁系统开发实战

相关资讯

Presto ANALYZE 语句详解:表与列统计信息收集指南 2026/9/24 19:18:59
AI智能体时代的数据主权:权限粒度、内存生命周期与上下文隔离 2026/9/24 19:13:58
Flutter跨平台开发OpenHarmony游戏库App:设置模块全流程实战 2026/9/24 19:13:58

最新资讯

毕业设计实战:Seq2seq+LSTM+Attention情绪检测聊天机器人
OPNET CSMA/CD仿真全流程:从场景搭建到参数对比分析
托尼·霍尔逝世:从快速排序到“十亿美元错误”null的前世今生
Postman+Newman接口自动化实战:从手工调试到CI流水线
爬虫-分析-可视化:黑龙江旅游景点数据分析系统全流程解析
Kubernetes 集群与应用监控实战:从 Heapster 到 Prometheus 的云原生可观测体系

今日推荐

JavaWeb购物车系统实现:基于Session存储的完整工程示例
面向对象综合训练:从图书管理系统掌握封装、继承与多态
Lombok与JDK版本冲突引发NoSuchFieldError:根因排查与修复指南

本周热门

BrewUI:给Homebrew套上图形界面,让macOS软件包管理更简单
BrewUI:让Homebrew包管理变得可视化与高效
公式与文本对齐全攻略:从Word到LaTeX的实用技巧

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0高校汉服租赁系统开发实战

发布时间:2026/9/24 19:18:59
SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0高校汉服租赁系统开发实战 最近帮朋友救急接手了一个Java Web方向的项目高校汉服租赁网站系统技术栈定的是SpringBoot2 Vue3 MyBatis-Plus MySQL8.0要求前后端分离配套开发文档。项目本身不算特别重但把汉服租赁这种带衣物租赁周期尺码库存押金管理的业务走通一遍踩了不少值得记录的坑正好整理出来给准备做毕设、课程设计或者想抄一个校园租赁类项目作业的同学当参考。这篇我会从技术选型逻辑、项目目录规划、数据库设计、租赁业务核心流程、前后端实现以及部署时MySQL8.0那几个经典问题这几个角度展开全程按实际开发顺序讲代码思路多于完整代码毕竟每个学校的课程设计要求不一样直接抄代码意义不大搞清楚为什么这么设计才值钱。1. 为什么定这套技术栈SpringBoot2 Vue3 MyBatis-Plus MySQL8.01.1 从需求反推选型而不是先选型再套需求做毕业设计最忌讳的事情就是一上来堆技术名词。你去看那些评分比较高的项目技术栈不一定最新但每一样都能说清楚解决了什么问题。这个汉服租赁系统核心需求其实特别实在学生用户能注册登录、浏览汉服列表、按分类筛选、查看详情、加入购物车、下单租赁、支付押金和租金。管理员能维护服装信息名称、分类、尺码、日租金、押金、图片、处理订单状态、处理归还和续租、查看统计。整个流程要符合高校社团实际使用场景也就是社团统一采购一批汉服向校内有活动需求的学生出租订单有明确起止日期不存在无限库存。基于这个需求SpringBoot2足够稳。SpringBoot3虽然已经发布一段时间但很多教程资源、第三方集成方案还停留在SpringBoot2的惯性里对毕设来说稳定、资料多、踩坑少才是硬指标。Vue3作为前端框架则纯粹是趋势问题现在新开的Vue项目没有必要再回到Vue2的Options API老路上去Composition API在处理复杂的表单与状态联动时明显更顺手。MyBatis-Plus解决了单表CRUD的大量重复劳动尤其后台管理的增删改查页面几乎没有手写SQL的必要。MySQL8.0则是当前主流版本处理utf8mb4中文排序、窗口函数都比5.7省心。1.2 为什么没有用Spring Data JPA很多同学会纠结MyBatis-Plus和Spring Data JPA到底选哪个。我这次选MyBatis-Plus核心原因就一个租赁系统的订单查询往往有复杂的多条件动态拼装。比如查询某个时间段内、某个分类下、尺码为M、且尚未被预订的汉服这种需求用JPA的Specification写起来会绕一大圈而MyBatis-Plus的QueryWrapper LambdaQueryWrapper几乎是一行代码的事情配合MP自带的分页插件PaginationInnerInterceptor后台分页列表开发效率碾压。对比一下大概是这样对比维度MyBatis-PlusSpring Data JPA单表CRUD继承BaseMapper即完成非常快继承JpaRepository即完成也快多条件动态查询QueryWrapper/LambdaQueryWrapper简洁直观Specification/Criteria写法繁琐分页分页插件一行配置物理分页Pageable自带但复杂查询需要改造复杂SQLXML写SQL灵活可控JPQL或原生SQL稍显别扭学习成本低中与MyBatis生态衔接原生兼容需要额外适配从实际执行效率上看JPA的ManyToOne、懒加载这些问题处理不好反而容易出现N1查询对毕设答辩来说是个隐患。Mp在这一点上更直白查出来的就是DTO或Map不需要考虑实体关联关系。1.3 前端为什么是Vue3 Vite而不是Vue2 Webpack标题里写的是Vue3这里的细节需要注意的是初始化工具。如果有人还在用vue create命令创建Vue2项目就明显落后了。当前主流是用Vite初始化Vue3工程命令是npm create vitelatest。Vite依赖原生ESM本地开发启动速度快到几乎没有等待感和Webpack那种动辄十来秒的冷启动完全不是一个体验。在Vue3内部组合式API配合script setup语法让组件逻辑复用变得非常直接。以汉服列表页的筛选功能为例分类、价格区间、尺码、上架时间这几个筛选条件以前Vue2里要写在data、computed、watch三个地方Vue3里只用ref和computed就能完成闭环逻辑全部收敛在一个script setup块里读代码的人一眼就能看懂筛选逻辑是怎么流转的。2. 项目目录结构怎么设计从Maven后端到Vite前端2.1 后端标准目录结构与包拆分逻辑一个规范的Java Web项目目录结构本身就是评分点。Maven约定的结构是hanfu-rental/ ├── src/main/java/com/example/hanfu/ │ ├── controller/ # 控制层只做参数接收与结果封装 │ ├── service/ # 业务层核心逻辑全部在这里 │ │ └── impl/ # Service实现类 │ ├── mapper/ # MyBatis-Plus的Mapper接口 │ ├── entity/ # 数据库实体类 │ ├── dto/ # 接收前端参数的对象 │ ├── vo/ # 返回前端的视图对象 │ ├── config/ # 配置类MyBatis-Plus分页、CORS、拦截器等 │ ├── common/ # 通用返回结果、异常处理、常量 │ ├── utils/ # JWT工具、日期工具等 │ └── HanfuApplication.java # 启动类 ├── src/main/resources/ │ ├── mapper/ # MyBatis XML文件 │ ├── application.yml │ └── static/ # 本地存储上传文件的目录 └── pom.xml这里最想强调的一点是Controller一定要薄。很多毕设项目把业务逻辑写在Controller里看起来代码没少写但以后每次改动都可能牵一发动全身。租赁系统的核心业务比如下单预占库存归还时计算延期费用这些逻辑必须放在Service层Controller只负责确认用户登录状态、接收参数、调用Service、返回结果。DTO和VO的区分也很重要直接拿数据库实体返回给前端会造成两个麻烦一是多余的字段暴露给前端比如密码哈希值二是数据库表结构调整时前端接口也跟着变耦合太重。我的习惯是Entity绝不直接出参至少套一层VO。2.2 前端目录结构与路由设计前端部分我用Vite初始化目录也做了分层hanfu-web/ ├── src/ │ ├── api/ # 所有axios请求封装 │ ├── components/ # 公共组件 │ ├── router/ # 路由配置 │ ├── store/ # Pinia状态管理 │ ├── views/ # 页面组件 │ │ ├── home/ # 首页 │ │ ├── hall/ # 汉服列表页 │ │ ├── detail/ # 详情页 │ │ ├── cart/ # 购物车 │ │ ├── order/ # 订单确认/我的订单 │ │ ├── user/ # 个人中心/登录注册 │ │ └── admin/ # 后台管理 │ ├── utils/ # 请求拦截器、日期工具 │ ├── App.vue │ └── main.js └── package.json路由设计上要注意一个点前台商城和后台管理虽然都在同一个工程里但应拆成两套路由嵌套。前台是普通用户浏览使用后台需要管理员权限因此在路由守卫router.beforeEach里需要先判断目标路由是否带有meta.requiresAdmin标记如果有就检查Pinia里保存的userInfo.role是否为1管理员。之所以强调这个是因为很多毕设直接用一个路由表不做权限区分答辩时老师一问你怎么控制管理员页面访问就答不上来。2.3 需要一份含文档的项目文档里应该写什么这个项目标题特别注明了含文档实际指的是完整的开发文档包括需求分析、数据库设计说明书、接口文档、部署说明。文档不见得要几十页但一定要覆盖这几个点需求分析画清楚角色图谱。这个系统至少有游客、学生用户、管理员三种角色分别能做什么。用例图把注册、登录、浏览、下单、支付、管理服装、订单处理这些用例列出来。数据库表结构说明每张表的字段、类型、注释、关联关系。接口文档建议用Swagger/knife4j自动生成不用手写Markdown但要保证注释写得规范。部署文档如何初始化数据库、修改配置文件、启动后端、启动前端。别觉得这些简单就不写评分老师最看重的恰恰是这个。3. 数据库设计汉服租赁比普通商品交易多出来的那些坑3.1 核心数据表汉服租赁本质上是一个有库存、有租期的租赁交易系统和普通电商 buying 一次性商品最大的区别在于库存的占用是按时间区间计算的。表结构我按模块拆分成用户、服装、订单、内容管理、日志五个部分以下是最核心的几张表用户表sys_user字段类型说明idbigint主键自增usernamevarchar(50)登录名唯一passwordvarchar(100)BCrypt加密后的密码nicknamevarchar(50)昵称/姓名phonevarchar(20)联系方式avatarvarchar(255)头像图片地址roletinyint0普通用户 1管理员statustinyint0正常 1禁用create_timedatetime注册时间汉服表t_clothing这个表的重点是要体现租赁属性和尺码属性字段类型说明idbigint主键namevarchar(100)服装名称例如齐胸襦裙-淡紫category_idbigint关联分类表covervarchar(255)封面图imagestext详情图多张图片用逗号分隔sizesvarchar(50)可租尺码例如S,M,Ltotal_stockint总库存件数daily_pricedecimal(10,2)日租金depositdecimal(10,2)押金statustinyint1上架 0下架descriptiontext服装描述材质、适合身高、适用场合create_timedatetime上架时间订单表t_order和订单明细表t_order_item其实是租赁系统最核心的部分。一个订单可以包含多件汉服每一件在明细里记录租赁开始日期和结束日期订单表t_order字段类型说明idbigint订单IDorder_novarchar(32)订单编号时间戳随机数生成user_idbigint下单用户total_amountdecimal(10,2)租金总额deposit_amountdecimal(10,2)押金总额statustinyint0待支付 1已支付 2租赁中 3待归还 4已完成 5已取消create_timedatetime下单时间pay_timedatetime支付时间return_timedatetime实际归还时间订单明细表t_order_item字段类型说明idbigint主键order_idbigint关联订单IDclothing_idbigint关联汉服IDclothing_namevarchar(100)服装名称快照sizevarchar(10)租赁尺码daily_pricedecimal(10,2)当时日租金快照daysint租赁天数start_datedate开始日期end_datedate结束日期item_amountdecimal(10,2)单项金额3.2 为什么订单明细里要冗余服装名称和价格快照这个设计很多人第一次做会忽略。一条订单明细关联了clothing_id按第三范式来说确实不应该冗余clothing_name和daily_price。但租赁场景里存在一个实际痛点服装信息每天都在变化管理员可能修改名称、调价、下架。如果订单明细只是指向服装表那用户在我的订单里看历史订单时服装名称和价格可能已经不是下单时的样子了要是管理员刚好把服装下架了前端查不到关联数据还会出现空指针或订单页面数据缺失。所以订单明细保留快照字段既不是偷懒也不是不遵守范式而是对业务场景的真实妥协。同理也在订单里冗余了user_id对应的用户昵称避免后台订单列表每次都要连表查询用户表。3.3 尺码与库存怎么建模网上不少二手项目把尺码直接拼成一个字符串XL,XXL,L存在一个字段里这样确实省了事但一旦需要按尺码精确查询库存就会很痛苦。更合理的做法是单独建一张库存表t_clothing_stock字段类型说明idbigint主键clothing_idbigint关联汉服sizevarchar(10)尺码stockint这个尺码的库存件数为什么需要拆这张表因为汉服不同尺码的备货数量往往不对等比如社团采购时M码买了10件XXL码可能只有2件。每次下单占用的是特定尺码的库存不是笼统的整件服装减少1。库存表拆出来后查询某件汉服当前哪些尺码还有货就变成了一条简单的SQLWHERE clothing_id ? AND stock 0。查询某个时间段是否有货就复杂一点需要排除已经被订单占用的时间区间这一块也是租赁系统最核心的冲突检测逻辑下一节详细说。4. 租赁业务核心逻辑预占、冲突检测与延期归还4.1 下单时怎么做租期冲突检测普通电商下单只需要判断库存数量是否足够因为商品不存在被借走的状态。租赁系统不一样一件汉服在5月1日至5月3日被A同学预订了那B同学就算在4月30日下单也不能选择5月1日至5月3日这个区间。冲突检测的SQL设计逻辑如下以clothing_id 10、尺码M、新订单时间区间为start 2024-05-01、end 2024-05-03为例需要查出所有与该区间有重叠的已支付或租赁中的订单SELECT COUNT(*) FROM t_order_item oi INNER JOIN t_order o ON oi.order_id o.id WHERE oi.clothing_id 10 AND oi.size M AND o.status IN (1, 2, 3) -- 已支付、租赁中、待归还均视为占用 AND oi.start_date 2024-05-03 AND oi.end_date 2024-05-01这段SQL的精髓在于重叠区间判断条件已有订单开始日期 新订单结束日期且已有订单结束日期 新订单开始日期两个条件同时满足即代表时间区间存在重叠。这是区间重叠判断的经典公式比用是否在某两个时间点之间这种直觉写法要严谨得多。4.2 库存扣减与防超卖冲突检测通过之后还需要对库存进行防并发操作。这里有两个常见方案方案一先查库存再在代码里判断是否大于0最后UPDATE减少库存。这种方式在高并发下会出现超卖因为两个线程同时查到stock1然后都执行了扣减最终库存变成-1。方案二把判断写进SQL语句利用MySQL的行锁保证原子性UPDATE t_clothing_stock SET stock stock - 1 WHERE clothing_id 10 AND size M AND stock 0如果UPDATE影响行数为1说明扣减成功如果影响行数为0说明库存不足或尺码不存在。这是一个非常实用的防超卖写法不需要手写SELECT FOR UPDATE也不需要引入Redis分布式锁在毕设和小型项目的并发量级下完全够用。需要注意一点库存扣减必须和创建订单在同一个事务里执行。如果订单创建成功但库存扣减失败事务回滚两个操作要么都成功要么都失败。Spring的Transactional注解就是干这个的。4.3 归还、延期与押金退还流程租赁结束用户归还汉服后管理员在后台点击确认归还。这个动作要做的事情比表面看起来多修改订单状态为已完成status4。回补库存根据订单明细里的服装ID和尺码执行stock stock 数量。计算是否需要补交费用如果实际归还日期晚于订单结束日期按超出的天数乘以日租金计算延期费。更新押金状态全款退还、扣减延期费后退还、或者因服装损坏扣除赔偿金后把剩余押金退还。延期费的计算在Service层里就是个纯函数逻辑long diffDays ChronoUnit.DAYS.between(orderItem.getEndDate(), actualReturnDate); if (diffDays 0) { BigDecimal lateFee dailyPrice.multiply(BigDecimal.valueOf(diffDays)); // 记录到订单的额外费用字段 }这里也是用ChronoUnit.DAYS.between而不是(endDate.getTime() - startDate.getTime()) / 86400000后者在夏令时、闰秒等极端情况下容易出现一天误差虽然中国没有夏令时了但养成好习惯没坏处。另外一个业务细节值得在答辩时主动提出来学生社团的租赁大多数不涉及物流配送所以整套系统没有做收货地址和运费模块订单都默认线下自取。这个决策一定要在需求分析里写清楚否则评委老师会问为什么不考虑运费。5. 后端接口设计从登录鉴权到订单管理的实现思路5.1 JWT登录鉴权与拦截器配置整个系统的接口多数需要登录后才能访问但列表页、详情页可以让游客浏览。我采用JWT做无状态鉴权流程是用户提交用户名密码调用/api/auth/login。后端用BCrypt验证密码验证通过后生成JWT放入claims中保存userId和role返回前端。前端把token存在localStorage在axios请求拦截器里统一加入Authorization: Bearer token请求头。后端在SpringBoot中注册拦截器拦截所有/api/**请求排除掉登录、注册、商品列表等白名单地址。校验token通过后解析出用户信息放入ThreadLocal或RequestContext。这里特别提醒一个坑JWT的SECRET_KEY一定不要写死在代码里至少要放在application.yml的外部配置里。另外HS256算法足够用不用为了炫技去搞RS256你那点用户量根本不存在证书分发问题。5.2 统一返回结果与全局异常处理前后端分离项目最忌讳每个接口返回结构不一致。我的习惯是定义一个通用返回体ResultTpublic class ResultT { private Integer code; // 200成功 401未登录 500服务器错误 private String message; private T data; }同时用RestControllerAdvice做全局异常捕获。修改一个特别容易踩的坑全局异常处理器一定要区分业务异常和系统异常。业务异常比如该时间段已被预订应该返回code200但message提示还是直接返回code500我建议业务异常返回code200但携带业务错误码因为HTTP状态码用于标识请求是否完成而不是业务是否成功。这在前端axios拦截器里处理起来最顺滑只需要判断res.data.code不需要关心HTTP 4xx/5xx的语义问题。5.3 MyBatis-Plus分页配置后台管理页面几乎每个列表都需要分页MyBatis-Plus自带的分页插件配置起来很简单但要小心版本差异。SpringBoot2 MyBatis-Plus 3.5.x的配置是Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }这个配置加完Service层里直接PageClothingVO page clothingMapper.selectPage(new Page(pageNum, pageSize), new LambdaQueryWrapperClothing() .eq(StringUtils.hasText(categoryId), Clothing::getCategoryId, categoryId) .like(StringUtils.hasText(keyword), Clothing::getName, keyword) .eq(status ! null, Clothing::getStatus, status));LambdaQueryWrapper的条件里第一个参数是boolean为true时才拼接该条件这种写法可以完全避免字符串拼接SQL的麻烦。这也是MyBatis-Plus相对原生MyBatis最大的价值所在。5.4 图片上传的本地存储方案汉服的展示图片是刚需每件衣服至少一张封面图详情页还需要多张展示图。考虑到毕设项目没有条件买OSS我用本地存储方案配置虚拟路径映射把/upload/**映射到本机磁盘目录。上传接口接收MultipartFile校验图片类型和大小存储到配置的目录。返回给前端时拼接成完整的可访问URL。配置虚拟路径映射的方法是Configuration public class WebConfig implements WebMvcConfigurer { Value(${upload.path}) private String uploadPath; Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(/upload/**) .addResourceHandler(file: uploadPath); } }如果没做这个映射前端访问图片会404部署时尤其容易忘记记一下。6. Vue3前端的关键实现从首页到后台管理6.1 首页与列表页的渲染逻辑前端首页主要展示轮播图、分类入口、热销汉服推荐。轮播图数据可以做成后台可管理也可以先写死在接口里我建议做成banner表管理员可以修改轮播图前后端联调更完整。列表页是重头戏筛选条件包括分类、尺码、日租金区间、是否可租。这个页面我用Vue3的computed来处理当前筛选条件下有哪些服装script setup import { ref, computed, onMounted } from vue const clothesList ref([]) const filter ref({ categoryId: , size: , maxPrice: null }) const filteredList computed(() { return clothesList.value.filter(item { if (filter.value.categoryId item.categoryId ! filter.value.categoryId) return false if (filter.value.size !item.sizes.includes(filter.value.size)) return false if (filter.value.maxPrice item.dailyPrice filter.value.maxPrice) return false return true }) }) /script这里的核心逻辑是页面渲染时始终使用filteredList而不是直接使用原始列表clothesList。这样无论用户怎么改筛选条件视图层都会自动重新计算不需要写一堆事件监听和手动赋值代码。6.2 购物车与本地状态管理购物车数据我用Pinia管理状态定义为一个数组每个元素包含clothingId、name、cover、dailyPrice、size、startDate、endDate、days、itemAmount。为什么购物车里要记录起止日期因为汉服租赁的租金计算依赖租赁天数把日期放进购物车项里下单时就能直接算出总金额购物车页面也可以展示小计日租金 × 天数。用Pinia的好处是在首页、列表页、详情页都可以很方便地往购物车里添加商品而不需要组件间事件层层传递。我在状态里封装了一个addItem(payload)方法内部自动计算日期差并设置itemAmount这也是租赁系统与普通电商购物车最大的差异点。6.3 订单确认页与支付模拟订单确认页需要展示购物车里的全部商品确认租赁起止日期并展示租金合计、押金合计。然后用户点击提交订单后端完成库存预占和订单创建。支付这块因为毕设不接真实支付通常做成模拟支付创建订单后前端调用/api/order/pay/{orderId}后端直接把订单状态从待支付改为已支付。有一点要注意已支付状态和租赁中并不一样。已支付表示用户付了钱但租期还没开始租赁中表示租期已经开始。如果用户的租期是明天开始那么今天订单状态就是已支付而系统在后台仍然要把它显示为即将开始。很多毕设项目把这两个状态混为一谈导致时间判断逻辑出错。状态机设计建议这样走0待支付下单后未支付超时可取消。1已支付已付款租期未开始。2租赁中当前日期在Start到End之间。3待归还End日期已过但未确认归还。4已完成已确认归还。5已取消用户取消或超时系统取消。在实际开发中租赁中和待归还之间不需要定时任务去扫描转换可以在查询列表时根据start_date、end_date与today的比较动态计算出来避免写复杂的定时器。6.4 后台管理系统用Element Plus快速搭建后台管理页面使用Element Plus布局就是经典的侧边栏顶部主内容区。核心页面包括仪表盘订单量、营收、租赁中的订单数、服装管理增删改查、分类管理、订单管理列表、查看详情、确认归还、用户管理列表、禁用启用、公告管理。管理员的订单列表是含金量最高的页面因为这里需要同时展示用户信息、服装信息、租赁时间、订单金额、押金状态、订单状态。设计表格时建议用el-table嵌套多个列在操作栏根据订单状态动态显示按钮已支付显示确认出借待归还显示确认归还已完成后只读。6.5 Vue3中用Axios封装请求的写法所有接口请求统一走src/utils/request.js在里面封装axios实例、请求拦截器和响应拦截器。响应拦截器要统一处理401跳转登录和业务错误码service.interceptors.response.use( (response) { const res response.data if (res.code 200) { return res } if (res.code 401) { localStorage.removeItem(token) router.push(/login) } ElMessage.error(res.message || 请求失败) return Promise.reject(new Error(res.message || 请求失败)) }, (error) { ElMessage.error(error.message || 网络异常) return Promise.reject(error) } )这样在页面里调用时只需要关心成功分支返回res.data失败分支由拦截器统一处理页面代码干净很多。7. MySQL8.0部署与配置最容易被卡住的那几个点7.1 安装与初始化的基本流程MySQL8.0和5.7的最大变化之一是默认认证插件从mysql_native_password改成了caching_sha2_password。这个变化带来的直接后果是老版本JDBC驱动、老版本Navicat12以下连接MySQL8.0时会报Authentication plugin caching_sha2_password cannot be loaded错误。解决办法有两个一是用最新版本JDBC驱动和最新版Navicat。SpringBoot2的mysql-connector-java依赖要注意版本我使用的依赖坐标是dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId scoperuntime/scope /dependencySpringBoot2.7.x管理该依赖的版本默认是8.0.x一般不需要显式指定版本号但如果是特别旧的SpringBoot版本需要手动加上版本号。二是如果实在要用老客户端可以建用户时指定老认证插件CREATE USER hanfu% IDENTIFIED WITH mysql_native_password BY yourpassword; GRANT ALL PRIVILEGES ON hanfu_db.* TO hanfu%; FLUSH PRIVILEGES;但不推荐长期这么干MySQL官方已经明确mysql_native_password在后续版本会被移除。7.2 时区问题与URL参数MySQL8.0连接时最经典的一个错误是The server time zone value ???ú??????? is unrecognized or represents more than one time zone。这是因为MySQL服务器时区没有设置JDBC无法解析。解决方式是JDBC URL带上serverTimezone参数spring: datasource: url: jdbc:mysql://localhost:3306/hanfu_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalseallowPublicKeyRetrievaltrue username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.DriverallowPublicKeyRetrievaltrue也是MySQL8.0下很容易踩的坑不加这个参数首次连接时如果认证方式是caching_sha2_passwordJDBC可能因为无法获取公钥而报错Public Key Retrieval is not allowed。开发环境建议直接加上。7.3 Docker部署MySQL8.0的细节不少同学的MySQL是直接用Docker启动的命令通常长这样docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD123456 \ -e TZAsia/Shanghai \ -v /opt/mysql/data:/var/lib/mysql \ -v /opt/mysql/conf:/etc/mysql/conf.d \ mysql:8.0这里要提醒的是TZAsia/Shanghai这个环境变量虽然设置了但MySQL内部的time_zone系统变量不一定被同步设置。建议在容器启动后执行docker exec -it mysql8 mysql -uroot -p123456进入MySQL后执行SELECT NOW();如果返回的时间是UTC而不是北京时间就要手动设置全局时区SET GLOBAL time_zone 08:00; SET time_zone 08:00;更彻底的做法是在MySQL配置文件my.cnf的[mysqld]段里写上default-time-zone 08:00。毕设项目里时间字段比较多时区不一致会导致订单的创建时间、租赁日期全部差8个小时排查起来非常痛苦。7.4 导入SQL文件时中文乱码MySQL8.0默认字符集是utf8mb4按理说不该乱码但如果你用命令导入SQL文件可能会因为SQL文件本身的编码格式与数据库连接编码不一致而出现乱码。解决方案是在导入时显式指定字符集mysql -uroot -p123456 --default-character-setutf8mb4 hanfu_db hanfu.sql如果是从Navicat里导入的导入前先看右下角连接属性里的编码设置是否选择了utf8mb4。同时检查建表语句里是否显式指定了DEFAULT CHARSETutf8mb4如果建库语句漏了这个表默认可能是latin1。另外application.yml里的连接URL已经带了characterEncodingutf8这里的utf8实际上在MySQL里会被理解为utf8mb3对于绝大多数汉字存储没有任何问题。但为了追求规范的字符集配置建议在MySQL端的库、表、JDBC URL统一使用utf8mb4。8. 开发中实际碰到的问题与排查思路8.1 MyBatis-Plus的Mapper XML路径问题如果用MyBatis-Plus写复杂SQLXML文件放在src/main/resources/mapper/目录下但mapper接口在com.example.hanfu.mapper包中不配置的话项目启动时会提示Invalid bound statement (not found)。配置点有两个。第一个是在application.yml里声明mapper XML的位置mybatis-plus: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.hanfu.entity第二个是在启动类或配置类上加MapperScan(com.example.hanfu.mapper)让Spring能扫描到Mapper接口。这两个配置缺一个都不行前者找不到XML后者注册不了Bean。网上经常有人问Mapper接口和XML放在同一个文件夹下应该怎么配置那是指把mapper包也建在src/main/java下然后配置mapper-locations: classpath:com/example/hanfu/mapper/*.xml。我建议老老实实把XML放resources/mapper不要搞那些花活省得构建时被Maven过滤掉。8.2 跨域请求CORS配置前端Vite开发服务在http://localhost:5173后端SpringBoot在http://localhost:8080两者端口不同必然触发跨域。开发阶段的解决方式是后端配置CORSConfiguration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOriginPatterns(*) .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*) .allowCredentials(true) .maxAge(3600); } }注意这里用的是allowedOriginPatterns(*)而不是allowedOrigins(*)因为如果设置了allowCredentials(true)allowedOrigins( * )在较新的Spring版本会被拒绝而allowedOriginPatterns没有这个问题。如果已经配置了JWT拦截器还需要注意一个细节预检请求OPTIONS方法不应被拦截。拦截器里要加判断if (OPTIONS.equalsIgnoreCase(request.getMethod())) { return true; }否则前端浏览器发起的预检请求过不了拦截器实际业务请求发不出去表现就是前端报CORS错误但后端日志里根本没有业务日志排查半天找不到原因。8.3 日期参数传递的格式问题前端传递客户选择的租赁日期通常是2024-05-01这种字符串后端如果用Date类型接收需要配置全局日期格式。推荐的做法是前端直接传字符串或LocalDate后端实体字段用LocalDate接收配合DateTimeFormat(pattern yyyy-MM-dd)public Result? createOrder(RequestBody OrderCreateDTO dto) { // dto中的 startDate 类型为 LocalDate可直接使用 }LocalDate和LocalDateTime在Jackson反序列化时的处理与Date不同需要依赖jackson-datatype-jsr310SpringBoot2默认引入了该依赖无需额外配置。但如果前端传到后端的是时间戳或带时区的ISO字符串就要额外写JsonFormat注解指定格式。8.4 数据库字段名与Java属性的映射MySQL的字段习惯是下划线风格create_timeJava属性是驼峰createTime。MyBatis-Plus默认开启了下划线转驼峰映射理论上不需要额外配置。但如果踩到createTime查询出来是null先看实体类有没有加TableField(create_time)再检查application.yml里是否不小心写错mybatis-plus: configuration: map-underscore-to-camel-case: true这个值默认就是true真正的坑往往出在实体类字段用了Integer或BigDecimal等包装类型却初始化为null或者数据库字段和实体类字段对不上但没报错只显示null排查思路要放到字段名对不上这个方向。9. 验收前最后一轮自查让项目能经得住答辩的几个细节9.1 演示数据要厚毕设项目最尴尬的一件事是演示时数据库里只有两条测试数据老师一点下一页就到头了。我做这个项目时前期就往每张表里灌了足够的演示数据服装表至少20条覆盖齐胸襦裙、齐腰襦裙、圆领袍、褙子、马面裙、斗篷等热门汉服品类尺码覆盖S到XL价格从每天20元到120元不等。订单表也造了十几单状态覆盖待支付、已支付、租赁中、待归还、已完成、已取消六种情况。这样演示时不管点哪个列表页展示效果都是满的。9.2 权限控制要能现场演示答辩老师可能会做两件事第一用普通用户登录后直接输入后台管理地址看看能不能访问第二直接调用后台接口看看能不能拿到数据。针对这两点我的处理方式是路由守卫拦截页面访问同时后端接口层用拦截器校验/api/admin/**下的所有接口必须具有管理员角色。这样即使前端绕过了路由后端也会拒绝返回数据。后端权限校验可以做一个简单的RequireAdmin注解配合AOP实现也可以在拦截器里根据URL前缀做判断。我建议做成注解的方式这样后续如果有新加的后台接口只需要在方法上加注解即可Target(ElementType.METHOD) Retention(RetentionPolicy.RUNTIME) public interface RequireAdmin { }AOP切面里从RequestContext取当前用户判断role是否等于1不等于就抛出无权限异常。9.3 接口文档必须能实时生成含文档这个卖点在验收时必须体现出来。我给项目集成了knife4j它是Swagger的增强UI效果比原生Swagger好看很多展示接口列表、参数说明、在线调试都方便。SpringBoot2集成knife4j的依赖是dependency groupIdcom.github.xiaoymin/groupId artifactIdknife4j-openapi2-spring-boot-starter/artifactId version4.4.0/version /dependency然后写一个Knife4jConfig配置类定义文档标题为高校汉服租赁系统接口文档版本号写上1.0.0。启动项目后访问http://localhost:8080/doc.html就能看到所有接口。这个细节在答辩时非常加分因为老师只要打开这个页面就能看到项目的全部接口和参数定义不需要去翻代码。9.4 优化答辩时的演示路径我建议准备两条演示路径。第一条是普通用户路径注册账号 - 登录 - 浏览汉服 - 筛选 - 查看详情 - 加入购物车 - 提交订单 - 模拟支付 - 查看我的订单。第二条是管理员路径管理员登录 - 后台首页看仪表盘 - 查看订单列表 - 找到待归还订单 - 确认归还 - 去服装管理修改一条服装信息 - 去用户管理禁用一个用户。这两条路径走完项目的核心功能几乎全覆盖不会被追问购物车呢订单管理呢这种尴尬问题。我记得我第一次演示这个项目时最紧张的不是技术点讲不明白而是演示过程中突然发现某个列表页加载不出图片。后来排查是图片上传后存在本地目录但前端访问时路径拼接少了一层/upload前缀。这类细节问题在答辩前一定要自己反复走几遍完整流程尤其是图片、日期、金额这种容易出问题的地方。10. 整体项目落地过程中最值得记住的三个经验第一开发顺序上先做数据库设计再定接口最后写页面。我见过太多项目先写页面再改表结构结果一张订单表的字段改了五六次前端页面跟着返工。数据库表结构一旦定下来就是整个项目的地基后续任何模块的扩展都要在这个地基上盖楼。建议花至少半天到一天时间把表结构、字段注释、关联关系全部评审一遍再动手写代码。第二不要追求全项目都用MyBatis-Plus。MyBatis-Plus确实方便但遇到多表关联的统计查询比如按月统计租赁收入还是写原生SQL更清晰。把这个经验刻在脑子里MyBatis-Plus负责80%的简单CRUDXML负责20%的复杂统计这个小组合能覆盖几乎所有毕设需求。第三日志要留在关键节点。订单创建、库存扣减、归还确认这些操作一定要在Service层加上log.info日志记录关键参数和操作结果。这样一旦线上出问题排查比一脸懵地看前端报错高效得多。我一路开发下来有几个Bug就是靠日志快速定位的比如有一次订单状态一直卡在待支付就是因为回调方法里参数没传到日志一打出来立刻发现是前端传参少了一个字段。这个技术栈的组合在毕业设计市场已经很成熟了SpringBoot2负责稳定兜底Vue3保证前端体验不落伍MyBatis-Plus把开发效率拉满MySQL8.0解决中文与事务问题。把这套流程完整走一遍你得到的不仅是一个能通过答辩的项目更是对租赁类业务系统的深度理解以后再接到类似的校园物品租赁、图书借阅、场地预约项目核心业务逻辑都能直接迁移复用。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号