这是我这几年带毕设和帮学弟学妹改项目时,经常被问到一个题目。说实话,“基于SpringBoot和Vue的仙剑七商城平台”这个组合,在计算机毕业设计里属于那种一眼看去不会太惊艳、但做起来非常扎实的选题。它把电商系统最核心的几条链路都覆盖了:用户登录鉴权、商品浏览检索、购物车管理、订单流转、后台商品维护、文件上传存储,每一块都能独立拿出来写一章论文,而且都有真实业务场景做支撑,不是那种空泛的管理系统。
仙剑七本身就是个自带流量的IP,周边商城这个切入点也很讨巧。用户端能浏览游戏手办、原画集、OST专辑这类虚拟和实体商品,管理员端能维护商品上下架、处理订单和库存,整体功能既不复杂到失控,又足够撑起一篇完整的毕设论文。如果你正在做这个题目,或者打算拿类似的商城项目做参考,这篇内容会从选题思路、技术选型、数据库设计、前后端实现,到常见的坑和答辩准备,一整套讲清楚。
1. 选题思路与整体架构设计
1.1 为什么仙剑七商城是个好题目
很多同学选毕设题目时容易走两个极端,要么选个宿舍管理系统、图书馆管理系统这种满大街都是的题目,答辩时老师一听题目就没了兴趣;要么上来就整微服务、分布式、RabbitMQ消息队列,结果还没到中期检查就自己把自己劝退了。仙剑七商城这个题目的好处,在于它处在一个很舒服的中间位置。
从业务维度看,商城系统是经典中的经典,用户、商品、购物车、订单、支付、后台管理,这些模块每一届都在做,但每一次都有不同的实现细节可以聊。从技术维度看,它能承载当下JavaWeb方向的主流技术栈,SpringBoot做后端服务、Vue做前端页面、MySQL存业务数据、Redis做缓存和临时购物车、MinIO做商品图片的对象存储,这一套组合拿到就业市场上也是实实在在能用得上的技能。
而仙剑这个IP给整个项目增加了一点特色。你可以把商品分类设计成角色手办、典藏版、OST、原画设定集,可以在首页做个轮播图展示仙剑七的游戏壁纸,商品详情页可以放一段游戏CG的截图介绍,这些都让系统看起来不是从一个商城模板里直接抠出来的,论文里也能写出“面向特定IP粉丝群体的垂直电商平台”这样的差异化表述,比模糊的“网上商城系统”有价值得多。
1.2 技术选型与版本搭配的讲究
技术选型这块,我见过太多人在第一步就栽了跟头。SpringBoot 3.x已经发布好几年了,但毕设环境里很多人的JDK还停留在8,或者实验室电脑上装的是老版本IDEA。如果把SpringBoot选到3.x,会发现javax命名空间变成了jakarta,很多旧教程里的代码直接跑不起来,而网上绝大多数SpringBoot相关的资料、博客、视频教程还是以2.x为主。所以我对毕设项目的建议一向非常明确:SpringBoot 2.7.x系列 + JDK8,这是最稳的组合。
前端方面,Vue 2和Vue 3的选择同样要注意。如果学校课程里教的是Vue 2,老师可能要求你用Vue 2 + Element UI;如果项目比较新或者你有把握,Vue 3 + Element Plus + Pinia会更符合当前主流。这里没有绝对优劣,核心原则是:不要拿自己不熟悉的技术栈硬上。你选Vue 2,网上教程多到一辈子看不完;你选Vue 3,生态也非常成熟。关键是前后端接口对接的思路要理清楚,Vue版本对你的毕业设计最终效果影响没有想象中那么大。
后端核心依赖我用一张表理出来,方便你对照着做版本检查:
| 组件 | 推荐方案 | 说明 |
|---|---|---|
| 开发框架 | SpringBoot 2.7.18 | 稳定、资料多、兼容JDK8 |
| 持久层 | MyBatis-Plus 3.5.x | 单表CRUD不用写SQL,大幅提升开发效率 |
| 权限鉴权 | JWT + 自定义拦截器 | 比Spring Security简单,论文阶段更容易讲清楚 |
| 缓存 | Redis + StringRedisTemplate | 存验证码、商品热门数据、临时购物车 |
| 对象存储 | MinIO | 本地即可部署,替代OSS,论文里能讲原理 |
| 数据库 | MySQL 8.0 | 5.7也可以,注意驱动版本差异 |
1.3 模块划分与前端路由结构
商城平台按角色拆成两个端,这个思路从需求分析开始就要明确。用户端给普通游客和注册用户使用,游客能浏览商品、搜索、查看详情,注册用户可以加购物车、下订单、查看个人中心;管理员端承担商品管理、分类管理、订单处理、用户管理和轮播图配置这些职责。
这意味着你不能只做一个前后台混在一起的项目,前后端分离的结构从一开始就要搭对。我的建议是把Vue工程内部用路由规则天然隔离成两个区域:/目录下是商城门户,包含首页、商品列表、商品详情、购物车、结算、个人中心;/admin目录下是管理后台,包含登录、商品管理、订单管理、数据概览。管理员登录后跳转到/admin,普通用户登录后留在/继续购物,两者的身份通过JWT里的角色字段区分。
数据库表设计同样围绕这两个端来展开。基础表至少需要:user(用户表)、category(商品分类)、product(商品基本信息)、product_image(商品轮播图)、cart(购物车)、orders(订单主表)、order_item(订单明细表)、banner(首页轮播配置)。这几张表之间用外键逻辑关联,但实际编码时我建议保留实体表关联而不在MySQL里强加物理外键,这样增删数据时更灵活,而且MyBatis-Plus的查询本身也不太依赖数据库层面的外键约束。后续如果时间充裕,可以再加一张product_review商品评价表,让系统功能更完整。
2. 后端SpringBoot核心实现细节
2.1 工程结构搭建与统一返回结果
后端工程我习惯按照“实体层(domain/entity) → 数据访问层(mapper) → 服务层(service) → 控制层(controller)”四层结构来搭。分包时看到很多同学喜欢把所有类平铺在一个包底下,这样做小项目时很舒服,但论文写到“系统设计”章节时,你会发现连系统架构图都画不好。一个规范的包结构大概是这样的:
com.xx.xiange7 ├── controller # 接收前端请求 ├── service # 业务逻辑层 ├── mapper # 数据访问层,继承BaseMapper ├── entity # 数据库实体 ├── vo # 前端展示对象,比如购物车VO、订单VO ├── dto # 接收前端参数的传输对象 ├── config # 注册拦截器、跨域配置、MinIO配置等 ├── common # 统一返回值、异常处理、工具类 └── interceptor # JWT验证拦截器接口设计上有件事必须从一开始就定下来,那就是统一返回结果。前后端分离开发时,如果每个接口返回的JSON结构都不一样,前端对接起来会非常痛苦。我自己习惯用的结构是:
{ "code": 200, "message": "操作成功", "data": {} }配合全局异常处理器@RestControllerAdvice,把业务异常和系统异常都包装成这个格式返回,前端拦截器里只要判断code !== 200就弹出错误提示。这样做还有个额外好处,就是写论文的时候,你可以理直气壮地写“本项目设计了统一响应结构,提升了前后端数据交互的一致性与可维护性”,这句话在答辩时老师是认的。
2.2 登录鉴权:JWT + 拦截器,说得清讲得明
很多商城项目登录用的是Session方式,但前后端分离场景下,我更推荐用JWT。原因很实在:Vue前端可能部署在8080端口,SpringBoot后端跑在8081端口,Session的Cookie跨域处理起来非常麻烦,需要配置跨域允许携带凭证。JWT的机制是服务器登录成功后生成一串加密的Token字符串返回给前端,前端存到localStorage或者Vue的store里,每次请求在请求头Authorization字段带上这个Token,后端拦截器解析合法后放行。
JWT本身由三部分组成:Header(加密算法)、Payload(用户ID、用户名、角色、过期时间)、Signature(签名)。我建议把用户ID和角色放进Token的Payload里,拦截器解析完后直接放到ThreadLocal中,后续业务代码里要用当前登录用户时直接取,不需要每次查数据库。Token加一个合理的过期时间,比如2小时有效,前端在token过期失效时捕获到401状态码,统一跳到登录页。
拦截器里要放行的路径包括登录接口、注册接口、商品列表、商品详情这些游客也能访问的接口。管理后台所有/admin/**相关请求,除了验证Token是否合法,还要额外从Payload里取出角色字段,判断是否为管理员,防止普通用户通过请求地址强行访问后台管理接口,这一点在论文的功能测试章节里可以作为安全测试的用例写进去。
2.3 订单流程与库存扣减方案的取舍
商城系统的核心永远是订单流程。一个完整的订单流程包含:用户从购物车选择商品结算 → 创建订单(订单状态为待付款) → 模拟支付成功 → 订单状态更新为已付款 → 管理员发货 → 订单状态更新为已发货 → 用户确认收货 → 订单状态更新为已完成。这套状态流转不做复杂设计,但要用一个字段清晰地标记当前状态,建议用status字段配合状态枚举类管理。
库存扣减是实现时最容易出问题的地方。我见过最简单的方案是在创建订单时不处理库存,等支付成功后再扣库存,这种方案的问题是,如果用户下单了但一直不付款,或者用户把商品加购了很多件,库存会被占用很久。更合理的做法是下单时直接锁定库存:商品表里维护一个stock字段,创建订单时校验库存是否充足,充足则扣减,扣减失败则订单创建失败抛异常。支付超时或用户主动取消订单时,再把库存加回去。
同时,整个扣减库存的过程一定要放在事务里。给创建订单的方法加上@Transactional注解,保证扣减库存、创建订单主表记录、创建订单明细表记录这三步操作要么全部成功,要么全部回滚,避免出现库存扣了但订单没建成的诡异数据。这里有个容易踩的坑:Spring的@Transactional只对通过代理调用方法的场景生效,即Controller调用Service方法时有效,但Service内部一个方法调用另一个方法时,事务注解常会因为自调用而失效。所以请把创建订单这段逻辑放到独立的Service方法里,不要让同类内部方法互相调用。
支付模块在毕设中不需要接入支付宝或微信支付,做一个模拟支付即可。用户点击“去支付”时,前端弹出确认框,后端把订单状态从待付款改为已付款。论文里可以写“本系统为降低演示复杂度,采用模拟支付流程,实际生产环境可无缝对接第三方支付接口”,这个说法在毕业设计里是完全站得住脚的。
2.4 商品图片上传:MinIO接入SpringBoot
商品图片怎么存、怎么访问,是个很容易被低估的模块。很多毕设项目的图片是直接上传到本地磁盘,然后通过SpringBoot的静态资源映射来访问。这种方式能做,但有两个明显的缺点:第一,项目重新部署或服务器路径变化,图片路径就失效了;第二,论文里没有什么值得写的技术含量。我一直建议用MinIO来做对象存储,它在毕业设计答辩中是个非常加分的技术亮点。
MinIO是开源的分布式对象存储服务,兼容Amazon S3接口,在本地启动一个服务,然后通过Java SDK接入SpringBoot项目。核心操作思路是:前端上传图片到后端,后端调用MinIO客户端把图片存入存储桶,返回一个可访问的文件路径。配置信息放在application.yml中,包括endpoint(MinIO服务地址,本地一般是http://127.0.0.1:9000)、accessKey和secretKey(MinIO默认初始账号)、bucketName。
接入时的关键代码逻辑是:工具类初始化MinIOClient,如果存储桶不存在则先创建;上传文件时生成一个唯一的文件名,用UUID拼上原始文件名,防止路径冲突。MinIO存好图片后返回的外链,直接拼在商品数据里返回给前端,前端Vue的<img>标签直接展示这个URL。注意配置跨域时,要把MinIO的地址加进去,否则图片加载会因跨域被浏览器拦截。
3. 前端Vue工程与交互实现要点
3.1 工程搭建、路由设计与Axios封装
前端工程我推荐直接使用Vue CLI或Vite脚手架创建。Vite工具的启动速度比Webpack快不少,但如果你对Vue CLI更熟悉,用CLI也不会影响任何功能。创建完项目后,先把依赖装上:vue-router管理路由,axios发HTTP请求,UI组件库(Element Plus或Element UI),有需要的话再加上pinia或vuex管理状态。
路由设计要提前理清页面关系。首页/home、商品列表/product(可以挂分类参数如/product?categoryId=3)、商品详情/product/detail/:id、购物车/cart、结算页/checkout、个人中心/profile、登录注册页/login。后台路由全部挂在/admin下,用嵌套路由划分/admin/goods(商品管理)、/admin/order(订单管理)、/admin/category(分类管理)、/admin/overview(数据概览)。路由守卫里判断用户是否有登录状态以及角色权限。
Axios封装是前后端对接的关键环节。我会创建一个request.js工具文件,在axios实例上设置baseURL和请求拦截器、响应拦截器。请求拦截器里从localStorage取出token,加到请求头Authorization上;响应拦截器里判断返回状态码,遇到401跳转登录页,遇到业务错误码直接弹出message提示。这个封装能让你在每个页面里只需要关注写接口逻辑,不需要重复处理异常。前端别忘记处理Vue生产环境的API代理问题。
3.2 核心页面组件与交互细节
先从首页说起。首页通常包含导航栏、轮播图、推荐商品列表三大块。导航栏里的搜索框是关键,输入关键词回车跳转到商品列表页并带上keyword参数,后端接口用LIKE模糊查询匹配商品名称和简介。轮播图数据来源是数据库banner表,后端提供一个查询接口,前端用带指示器和自动播放的组件渲染。推荐商品可以直接查一张is_recommend字段标记为1的商品列表。
商品列表页的核心是筛选逻辑。左侧或顶部展示分类树,点击分类后请求接口带categoryId;价格排序、销量排序这类交互建议前端排序配合后端排序参数一起实现,后端接口接收一个sortField和sortOrder参数,动态拼到SQL里去,前端只需要切换参数重新请求即可。分页用pageNum和pageSize,用分页组件展示。
商品详情页是展示信息最密集的页面。页面分成上下两部分,上面是图片轮播和商品基本信息,下面是商品详情介绍。用户操作上最重要的是“加入购物车”和“立即购买”两个按钮。加入购物车时,如果当前未登录,弹窗提示去登录;如果已登录,调接口把商品ID和数量存进购物车表。立即购买则是把单一商品直接生成一个临时订单流,通常是跳转到确认订单页并带上商品参数,和购物车批量结算共用同一个订单确认组件。
3.3 状态管理与接口联调的实际体验
商城项目里最值得用状态管理的地方就是购物车角标和用户登录状态。如果购物车数量每次都要重新请求接口获取,虽然也能做,但页面切换时会出现短暂的延迟和角标闪烁。建议的做法是:用户登录成功后,在Vue的store里保存用户信息和购物车总数;加购、删除购物车项、下单成功后同步更新store里的数量,这样所有页面的角标都能即时响应,不用整页刷新。
联调阶段建议开启SpringBoot后端的热部署配置,修改后端代码后会自动重启,省去手工重启的时间。前端使用Vite或CLI自带的开发服务器,通过Vite的代理配置/api前缀转发到后端地址,这样开发环境根本没有跨域问题。等到前后端都开发完成,再对生产环境做独立部署:前端npm run build打包出dist目录,后端打成jar包,由Nginx实现静态服务与反向代理分发,这是一套标准的前后端分离部署方案。
3.4 购物车与订单流程的交互逻辑
购物车页我需要特别强调一下“勾选结算”的逻辑。前端购物车列表中每项有一个复选框,用户可以勾选多个商品,底部显示已选商品的总价。点击“去结算”时,把选中的购物车ID列表传到订单确认页,后端创建订单时只处理这些选中的购物车项。选中的状态由前端管理,不要写进数据库,因为它只是一个临时的页面交互状态。对不选中任何商品就点结算的情况,前端做一次校验并给出提示。
订单确认页展示商品列表、总价、收货地址。收货地址表如果在第一版没有设计,这里可以做一个简化处理:用户下单时填写收货人姓名、手机号和详细地址,数据存到订单表的对应字段里。这个方案对毕设来讲完全够用,还省去了一大块地址管理的开发量。如果想让系统更完整,可以单独设计address表,管理多个收货地址,但这不是核心功能,优先级排到后面。
4. 前后端分离开发的踩坑记录
4.1 跨域问题:一次说清楚
跨域是前后端分离开发里第一个拦路虎。浏览器为了安全,默认不允许AJAX请求访问不同源(协议、域名、端口任一不同即是跨域)的地址。前端跑在http://localhost:8080,后端跑在http://localhost:8081,当然是跨域了。
解决方案在后端配置一个CorsFilter或实现WebMvcConfigurer接口添加全局跨域映射。配置里允许的来源根据实际环境写,开发环境可以写http://localhost:8080,生产环境替换成线上的域名,不要图省事用"*"通配符。还有一个容易忽略的点是:如果你的前端请求里带了Authorization这个自定义请求头,跨域配置里allowedHeaders("*")要把它覆盖进去,否则JWT根本到不了后端。请求方式也要把OPTIONS预检请求放行,这部分你不配置的话,前端浏览器会在发真实请求前自己发一个OPTIONS请求探路,如果被拦截,页面就会报跨域错误。
4.2 Token过期、路由守卫与401状态码
JWT过期后,前端接口请求会返回401状态码。如果没有统一处理,用户在界面上的表现就是点击任何按钮都没反应,或者控制台一堆红色报错,非常影响演示效果。处理思路:在Axios响应拦截器里统一判断,如果status === 401,清除本地存储的token和用户信息,用Element Plus的Message组件提示“登录状态已过期,请重新登录”,然后router.push('/login')跳转登录页。这样不论用户操作的是哪个页面,体验都是一致的。
路由守卫要区分两种场景。第一种是用户端权限控制:进入购物车、结算页、个人中心这些需要登录的页面之前,判断本地是否存在有效token,不存在就重定向到登录页。第二种是后台管理权限控制:进入/admin开头的所有路由前,除了判断token,还要判断本地存储的用户角色是否包含管理员角色。这里有一个关键点:路由守卫只解决前端界面跳转问题,接口鉴权后端拦截器也必须做,前端路由跳转可以只看前端本地状态而容易被绕过,真正的权限安全边界在后端,这个思路在答辩时可以和老师深入聊聊。
4.3 图片访问404与MinIO地址不通的排查
商品图片加载不出来,是使用MinIO方案后最常遇到的情况。排查顺序如下:第一步确认MinIO服务是否启动,浏览器直接访问http://127.0.0.1:9000看能不能打开管理页面;第二步确认存储桶里的对象是否真实存在,可以在MinIO控制台查看;第三步在后端日志里查看图片上传后返回的URL格式,把URL复制到浏览器地址栏直接访问,看图片能不能单独打开。
如果单独访问没问题,但前端页面显示不出来,大概率是跨域拦截。在MinIO服务端也需要配置跨域规则(MinIO控制台里的Bucket -> Access Rules,或者在启动MinIO时通过MINIO_CORS_ALLOW_ORIGIN环境变量指定允许的来源)。很多教程压根不提MinIO也有跨域问题,做完项目联调时才发现图片总是一片空白,最后排查半天是这个原因。
数据库表字段里存储图片URL时,建议只存相对路径,如/product/2024/xxx.jpg。前端展示时按环境变量或接口返回的域名前缀拼接成完整路径。这样做的好处是后端从本地MinIO迁移到生产环境对象存储服务时,只需要改一个base地址,不需要改数据库里的数据。
4.4 数据库乱码、事务回滚失效与常见后端异常
数据库乱码问题导致的“???”数据非常让人抓狂。在MySQL里,如果建库时没有指定utf8mb4字符集,或者JDBC连接串里没有显式声明characterEncoding=utf8,中文数据写入后就会出现乱码。建议在application.yml的数据库连接串中完整加上几个参数:useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai,同时建表时统一指定ENGINE=InnoDB DEFAULT CHARSET=utf8mb4,从根上解决问题。
事务回滚失效还要注意自调用问题和异常类型问题。执行SQL时如果抛的是Exception,@Transactional默认只对RuntimeException回滚,对CheckedException是不回滚的,所以建议在@Transactional注解上显式标注rollbackFor = Exception.class,防止出现“库存扣了订单没建但程序没报错”这种数据不一致问题。另外InnoDB引擎下的自动提交模式默认开启,开启事务后commit和rollback是交由Spring代理管理的,异常被try-catch吞掉后事务框架感知不到异常,也就不会回滚,这同样是排查事务失效时要重点检查的点。
5. 论文写作与答辩准备的实战建议
5.1 论文结构怎么搭才不虚
题目里带了“设计与实现”,论文结构基本就定型了。标准章节安排是:第一章绪论,写研究背景和意义、国内外研究现状、主要工作内容;第二章需求分析,写功能性需求(用户端、管理员端)和非功能性需求(性能、安全、易用性),这里建议把用例图画出来;第三章系统设计,写总体架构、功能模块划分、数据库设计,数据库表字段和ER图是这章的核心;第四章系统实现,对应功能模块贴代码和截图,图片处理逻辑、订单状态流转逻辑、JWT鉴权逻辑都是这章的重点;第五章系统测试,写测试环境、功能测试用例表、测试结果分析,非功能测试可以写一点简单的接口响应时间;最后是总结与展望。
写论文最忌讳的就是“堆代码”。每一段核心代码贴出来,都要配一段文字解释设计思路和实现逻辑,比如“该拦截器实现Spring的HandlerInterceptor接口,在preHandle方法中...”这种句式在毕业设计论文里是非常标准的表达,不要直接贴一大段代码不解释。功能截图也是必须的,每个模块至少放一张运行截图,截图要保证数据真实、界面整洁。
5.2 答辩演示与高频提问准备
答辩演示的视频流要提前练好。流程一般是登录管理员账号 → 进入后台管理 → 新增一个商品分类和商品数据(配上图片上传) → 切到用户端演示首页和商品列表 → 搜索关键商品 → 进入详情页加入购物车 → 去结算,输入地址 → 模拟支付 → 回到后台看到订单状态变化并发货 → 用户端确认收货。一套流程走下来两分钟左右,把系统核心能力全部覆盖到。
老师提问的高频范围,我根据这几年的经验总结成清单:SpringBoot的自动配置原理(重点说@EnableAutoConfiguration和@Conditional注解机制);为什么用JWT而不用Session;数据库表设计时为什么不用外键;订单状态和目标状态空间如何避免状态跳变出错;MinIO对比本地存储的好处;库存扣减如何避免超卖;如果用户量增大如何优化(加分回答:Redis缓存商品热点数据、Nginx负载均衡、数据库读写分离)。
5.3 提升项目亮点的几个方向
如果时间和精力允许,给项目加一点“超出预期”的东西,答辩效果会好很多。建议从以下方向里选一个来做:接入Redis缓存商品列表数据,减少数据库压力;使用Elasticsearch做商品搜索,替代MySQL的LIKE查询;引入RabbitMQ处理下单后的异步通知,比如下单成功后异步发送站内信或短信通知;给后台管理界面做一个简单的ECharts数据可视化报表,展示商品销量排行、订单数量趋势。这些方向随意选一个,都能在系统设计的创新性上多拿分。
不过我要提醒你,追加功能前一定要先保证基础功能完全稳定,bug清干净,再去做亮点。很多同学基础功能还没做完,先想着上ES和消息队列,最后演示时连登录都有bug,得不偿失。脚踏实地永远是毕业设计通过率最高的策略。
6. 给正在做这个题目的人几句实话
我确实踩过不少坑,从选型开始到部署上线,每个环节都有过让人抓狂的时候,这里整理几条最值得你早知道的建议。
数据库表和接口的定义,一定要在动手写代码之前定下来。两个人各写各的,一个把用户ID叫userId,另一个写uid,联调时接口文档根本对不上,改起来极其痛苦。哪怕你自己只做后端或者只做前端,也要把字段命名规则固定下来以方便后期调试。后端接口返回值建议用同一种结构,前端对接时做一次统一封装,后面就能处处省心。
开发时多用日志和调试工具,不要靠猜。SpringBoot的日志级别遇到问题就调到DEBUG,SQL语句会原样打印出来,参数也会展示,数据库查询出了什么问题一眼就能看出来。前端接口出问题时,浏览器开发者工具里的Network面板是排障的第一现场,看请求是否发出、响应状态码是什么、返回体是否符合预期,比盲改代码高效得多。
虚拟机和容器技术早点熟悉有好处。虽然本地开发直接在Windows上跑MySQL和MinIO很方便,但如果你毕业设计需要交一个演示文档或给别人复现,用Docker把MySQL、MinIO这些基础服务拉起来,团队协作时能省下一大堆环境配置的时间,推荐用Docker Desktop Compose写一套基础环境的启动编排,真正用到时就知道值了。
最后,做这个题目的过程大概率比想象中耗时,也比想象中有成就感。第一次看到自己写的代码真跑起来、页面能打开、订单能正常流转的时候,你会觉得这段时间熬得值。加油,你会做出来的。