1. 助农商城的核心需求与设计思路
1.1 这个系统到底在解决什么问题
先别急着写代码,做毕业设计或者接这种助农商城项目的时候,很多人上来就开SpringBoot工程,结果做着做着就发现需求边界撑不住。农产品电商平台听起来就是个商城,但和普通电商比,它有几个很不一样的地方。
农产品的核心痛点就三个:一是信息不对称,农户种出来的东西找不到合适的销路,消费者想买又找不到靠谱的产地直供渠道,中间商层层加价,两边都不讨好。二是品控问题,蔬菜水果生鲜这类东西不像工业品规格统一,同一批次的果子大小、甜度都可能有差异,所以平台必须支持批次管理、溯源信息录入。三是信任问题,消费者凭什么相信你卖的是"助农"产品?产地证明、农户认证、政府背书这些信息在页面上要能直观展示。
所以这个系统在功能层面剥开来看,就是一个标准的B2C电商模式:用户注册登录、浏览商品、加购物车、下订单、在线支付、后台管理订单和商品。但在业务细节上,要加入农户/合作社的角色管理、商品溯源字段、助农专区活动配置。把这些想清楚了,后续表设计和接口设计才不会跑偏。
这个项目适合三类人参考:第一是计算机相关专业做毕业设计的学生,第二是刚学完SpringBoot想找个完整项目练手的人,第三是真的想帮本地农户做个小电商平台的开发者。技术难度上属于中规中矩的CRUD加业务逻辑,我没有采用过于复杂的分布式架构,单体应用足够承载这类平台的初期业务量。
1.2 角色划分与业务流程梳理
我习惯把整个平台拆成三个端来看:买家端、卖家端(含农户)、管理后台。角色划分决定权限设计,权限设计决定接口风格,这一步理不顺后面肯定返工。
买家端流程是最直观的:注册登录,按分类浏览商品,搜关键词,看详情页,加购物车,结算下单,在线支付,然后等收货,确认收货之后可以评价。这里有个容易被忽视的点——下单的时候商品价格必须快照到订单明细里,不能下单之后还去关联商品表的实时价格,不然商家改价会导致历史订单金额跟着漂移。
卖家端主要是农户或者合作社操作的,核心动作是商品发布、库存管理、订单发货、查看销售统计。商品发布比普通电商多几个字段:产地、采摘日期、质检报告编号,这些是后面做溯源展示的数据来源。农产品还有季节性,所以下架逻辑不能做成永久删除,我建议用状态字段控制上下架,保留历史数据。
管理后台承担审核和运营职责:审核农户入驻资质,审核商品信息是否合规,管理商品分类,配置轮播图和助农专区活动,处理用户纠纷和退款申请。后台权限可以做成基于角色的访问控制,用Spring Security配合自定义拦截器就能搞定,没必要引入特别重的权限框架。
从业务闭环来看,核心链路是:农户发布商品,管理员审核通过,买家浏览下单,支付成功后农户发货,买家确认收货,资金结算给农户。整个链路里,订单状态是关键纽带,状态机想清楚,代码就顺畅。
1.3 为什么选SpringBoot这套技术栈
这个项目最稳妥的方案就是SpringBoot单体架构加Vue前后端分离。不用微服务,不是因为不会,而是因为没必要。毕业设计答辩的时候老师问你为什么不用Dubbo,你要能答上来:单体架构在这个业务规模下部署简单、运维成本低、开发效率高,微服务的服务发现、配置中心、链路追踪这些组件在这个项目里全是过度设计。
后端技术栈我推荐:SpringBoot 2.7.x + MyBatis-Plus + MySQL 8.x + Redis + JWT。Spring Boot天然省去了大量XML配置,内嵌Tomcat让部署变成一个命令的事。MyBatis-Plus的通用Mapper和分页插件能砍掉至少三分之一的重复代码,BaseMapper里常用的增删改查都给你写好了,你只需要专注业务SQL。Redis用来做验证码缓存和购物车缓存,JWT做无状态登录认证,避免Session在多端场景下的麻烦。
前端推荐Vue3 + Element Plus + Axios + Vue Router + Pinia。Vite构建速度明显快过Webpack。有同学问要不要用Vue2,我的建议是别用,新项目直接上Vue3,组合式API写起来逻辑复用更方便,而且Element Plus的组件颜值和交互都比Element UI好。
Java版本用JDK 8还是17?SpringBoot 2.7配JDK 8最稳,如果你想用SpringBoot 3.x那就要JDK 17起步。毕设项目求稳,用2.7 + JDK 8这套组合,网上遇到的坑都有人踩过了,你搜解决方案能搜出一大片。开发工具就用IDEA社区版加Navicat,没有授权问题。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 数据模型设计:农产品的表结构这样建才不返工
2.1 标准项目结构与初始化配置
很多同学创建SpringBoot项目的时候喜欢一个Controller包一个大类,全部塞进去。我建议按模块分包,虽然前期多建几个包,但后面维护的时候你会感谢自己。标准结构是这样的:
bash复制com.agri.mall
├── controller # 控制层
│ ├── admin # 后台管理接口
│ ├── buyer # 买家端接口
│ └── seller # 卖家端接口
├── service # 业务层
│ └── impl
├── mapper # MyBatis-Plus Mapper接口
├── entity # 数据库实体
├── dto # 前端交互对象
├── vo # 视图返回对象
├── config # 配置类
├── common # 通用类(Result、异常、常量)
├── utils # 工具类
└── interceptor # 拦截器
application.yml里几个关键配置我单独说下。数据源配置不多讲,MyBatis-Plus的逻辑删除配置要加上,不然删除用户的时候真的会把记录抹掉。还有驼峰命名映射要开,数据库字段用下划线,实体类用驼峰,自动映射省心省力。
yaml复制spring:
datasource:
url: jdbc:mysql://localhost:3306/agri_mall?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: root
redis:
host: localhost
port: 6379
mybatis-plus:
mapper-locations: classpath:mapper/*.xml
global-config:
db-config:
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
configuration:
map-underscore-to-camel-case: true
跨域配置一定要做,否则Vue开发环境访问后端接口会一直被浏览器拦截。前后端分离的项目里这算是头号拦路虎。我写了一个CorsConfig类,实现WebMvcConfigurer接口,重写addCorsMappings方法,允许所有来源、所有请求头、所有方法,开发阶段先全放开,上线之后再收紧。
2.2 核心表结构设计
数据库我建议起名agri_mall,字符集utf8mb4,排序规则utf8mb4_general_ci。utf8mb4能存emoji表情和特殊字符,农产品评价里用户可能发个图标。
用户表是角色模型的根基。我不用单表加role字段的方式,而是拆成user表加role字段,值有BUYER、SELLER、ADMIN三种。因为前端不同角色渲染的菜单和路由完全不同,后端接口也需要按角色做权限校验。字段大致是:id、username、password(BCrypt加密)、phone、role、avatar、status、real_name、id_card、create_time、update_time、deleted。这里sellter类型的用户其实是农户或合作社代表,所以额外关联一个farm表,存农场名称、产地地址、营业执照图片、资质审核状态。审核状态值有PENDING、APPROVED、REJECTED,管理员没审核之前,卖家登录进去是发布不了商品的。
商品表是整个系统的核心,字段设计要兼顾展示和溯源:
sql复制CREATE TABLE product (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
seller_id BIGINT COMMENT '卖家ID',
category_id BIGINT COMMENT '分类ID',
name VARCHAR(100) NOT NULL,
subtitle VARCHAR(200),
main_image VARCHAR(500) COMMENT '主图URL',
detail TEXT COMMENT '富文本详情',
price DECIMAL(10,2) NOT NULL,
stock INT NOT NULL DEFAULT 0,
unit VARCHAR(20) COMMENT '计价单位:斤/箱/个',
origin VARCHAR(100) COMMENT '产地',
harvest_date DATE COMMENT '采摘日期',
quality_report VARCHAR(500) COMMENT '质检报告图片',
sales INT DEFAULT 0 COMMENT '销量',
status TINYINT DEFAULT 0 COMMENT '0下架 1上架 2待审核',
create_time DATETIME,
update_time DATETIME
);
classify表就是商品分类,可以设计成父子级支持两级分类,比如"新鲜水果"下面挂"苹果"、"香蕉"。用parent_id关联就能实现树形结构,前端菜单递归渲染一下。
订单相关表是三张:orders、order_item、cart。orders表存订单主信息:order_no(唯一编号)、buyer_id、seller_id、total_amount、freight_amount、pay_amount、pay_type、status、address_snapshot(地址快照,JSON格式)、remark。订单编号我建议用时间戳加随机数生成,比如yyyyMMddHHmmss加6位随机数,避免用户猜单号。
order_item存订单明细:order_id、product_id、product_name、product_image、price(下单时快照,和product表无关)、quantity、subtotal。购物车表cart字段简单:buyer_id、product_id、quantity,加个唯一索引(buyer_id, product_id),重复添加时直接update数量,不需要insert新记录。
地址表address不用做太复杂,省市区三级联动是前端做的事,后端存province、city、district、detail、receiver_name、receiver_phone、is_default这几个字段就够了。
为了让答辩有亮点,我建议加一张visit_log表,记录用户的浏览足迹,然后做个"猜你喜欢"推荐接口——按分类统计用户历史浏览最多的分类,把同类商品按销量排序推给他。逻辑很简单,但说出来就是"基于用户行为的商品推荐",加分项这不就来了。
2.3 统一返回体与全局异常处理
这是所有SpringBoot项目都必须做的规范,但我见过太多人忽略它,接口返回值五花八门,前端联调的时候恨不得顺着网线来砍人。统一返回体我用一个Result类来定义。
java复制@Data
public class Result<T> {
private Integer code;
private String message;
private T data;
public static <T> Result<T> success(T data) {
Result<T> result = new Result<>();
result.setCode(200);
result.setMessage("操作成功");
result.setData(data);
return result;
}
public static <T> Result<T> error(Integer code, String message) {
Result<T> result = new Result<>();
result.setCode(code);
result.setMessage(message);
return result;
}
}
约定code为200是成功,400参数错误,401未登录,403无权限,500系统异常,404资源不存在。前端axios封装里根据code做统一处理,401就跳登录页。
全局异常处理用@RestControllerAdvice加@ExceptionHandler,这个注解组合能把Controller层抛出的异常统一拦截并包装成Result返回。我定义了BizException作为业务异常,在Service层需要中断操作时直接throw new BizException("库存不足"),异常处理器捕获后返回对应的错误码和提示信息。这样Controller代码里就不用到处try-catch,看起来干净很多。
注意异常处理里有个坑:你要拦截MethodArgumentNotValidException来处理@Validated参数校验失败的情况,不然前端拿到的是Spring默认的异常格式,还得自己去解析,联调效率很低。这个我后面详细说。
3. 核心模块实战:从登录到下单
3.1 JWT认证与双角色权限控制
登录认证这块我用的方案是Spring Security加JWT。但说实话,毕设项目里Spring Security配置起来比较繁琐,如果对源码不太熟,可以考虑用拦截器加JWT的简化方案。我更推荐后者,代码可控性更强,答辩时讲得清楚。
简单方案就是自己写一个JwtUtil工具类,用jjwt库生成和解析Token。用户登录成功时,服务端根据userId、username、role生成Token,过期时间设置为24小时。客户端每次请求在Header里带Authorization: Bearer token,拦截器解析Token并往ThreadLocal里放用户信息,Controller里从ThreadLocal\获取当前用户就能实现"谁在操作"。
权限校验逻辑这样设计:写一个AuthInterceptor实现HandlerInterceptor接口,preHandle方法里先放行登录接口和公共接口(比如首页轮播、商品列表),然后从Redis里查Token,查到就把用户信息放入ThreadLocal,查不到就返回401。
角色控制再加一个@RequireRole注解,标注在需要的Controller方法上,拦截器里判断当前用户角色是否匹配,不匹配就返回403。这样做的好处是权限逻辑都在一处,业务代码里不用反复写if (role != ADMIN)这种判断。
我从实际使用中得到的经验是,Token过期时间不要设置太长,24小时比较合适。用户长期不操作,前端应该在axios响应拦截器里捕获401状态并自动跳转登录页重新登录。有个细节容易被忽略:前端登录成功后要同时存Token和用户角色到localStorage,刷新页面之后动态路由要根据角色重新生成,不然刷新就白屏。
3.2 商品模块:分类、搜索与上下架
商品是电商门面,买家端第一屏就是商品列表,体验好不好就看这里的查询效率。我建议商品列表用MyBatis-Plus的分页插件实现,Page对象传入当前页和每页大小,返回的记录和总数都在Page里,前端只需要去解析。
分类筛选的逻辑是:买家先选一级分类,前端请求 /api/category/{parentId}/children 拿二级分类,再选二级分类,商品列表接口带上category_id参数。SQL就是where category_id = #{categoryId} and status = 1 order by sales desc。如果要同时匹配一级分类下的所有商品,得用IN子查询把二级分类id全查出来。这个逻辑在Mapper XML里写清晰。
搜索功能建议直接做LIKE模糊查询,毕设阶段不用上Elasticsearch,那是给自己找罪受。name like '%keyword%'虽然性能不算最优,但数据量几万条完全无压力。如果以后要优化,可以加个商品名称前缀索引或者引入全文索引,这只是个思路延伸。
卖家端发布商品的流程我建议带审核:卖家提交商品后状态是PENDING,管理员在后台能看到"待审核"列表,点击通过后状态变上架,不通过就填写拒绝原因。审核逻辑用最简单的事务实现:update product set status = #{targetStatus} where id = #{id},加一个前置状态判断,防止商品处于上架状态又被重复审核。
商品上下架还有一个业务细节:卖家下架商品时,要检查这个商品有没有待发货的订单。如果有,不能直接下架,得提示卖家先处理完未发货订单。这个检查逻辑很容易被漏掉,但确实是在实际运营中真实会碰到的场景。
3.3 购物车与订单状态机
购物车没什么黑科技,但Redis缓存购物车这个方案比较有意思。以buyerId为key,商品ID为field,数量为value存到Redis的Hash结构里。为什么不用MySQL存?一是购物车操作频率极高,读多写多,放Redis性能好;二是购物车本身不要求持久化,用户清空购物车、修改数量这些操作都是临时行为,等真正提交订单的时候再落库。
但Redis购物车有个问题:用户刷新页面后购物车数据还在不在?取决于Redis持久化配置。我建议开发环境用默认RDB持久化就行,体验上基本不会有问题。
下单流程是整个系统最核心的一条链路,涉及多张表多个步骤,必须用@Transactional事务来保证一致性。下单伪代码如下:
- 校验购物车是否为空,取出商品ID和数量
- 循环商品ID,查询商品并检查状态,判断库存是否充足
- 生成订单主记录(orders),状态为待支付
- 生成订单明细记录(order_item)
- 扣减库存:update product set stock = stock - #{quantity} where id = #{id} and stock >= #
- 清空相关购物车记录
- 返回订单号,前端跳转支付页
第5步这个SQL我特意用了乐观锁思想,where条件里带上stock >= quantity,如果库存不足,受影响行数为0,事务回滚。这就是经典的防超卖方案,用MySQL自身的行锁保证并发安全,不用分布式锁也能顶住初期业务量。
订单状态我用一个状态字段管理,值对应这样的流转过程:
| 状态值 | 含义 | 可执行操作 |
|---|---|---|
| 0 | 待支付 | 取消订单、支付 |
| 1 | 待发货 | 买家无操作,卖家发货 |
| 2 | 待收货 | 买家确认收货 |
| 3 | 已完成 | 评价、申请售后 |
| 4 | 已取消 | 无 |
| 5 | 退款中 | 协商退款 |
| 6 | 已退款 | 无 |
状态变更我建议写一个OrderStatusService,把所有状态流转逻辑集中管理,用Map定义合法流转路径,非法流转直接抛异常。这样代码意图清晰,比在每个方法里散落状态判断强太多。
3.4 支付模块:沙箱对接与回调处理
支付这块我对毕设项目的建议是:对接支付宝沙箱环境,不用自己真实收款。支付宝沙箱提供了完整的模拟支付流程,你在沙箱环境里用一个"买家账户"完成付款,体验和真实支付几乎一样,答辩演示的时候比写死"模拟支付"高大上很多。
对接步骤是:先去支付宝开放平台创建应用,申请沙箱环境,配置RSA2密钥,把应用公钥、应用私钥、支付宝公钥填到项目的application.yml里。后端引入alipay-sdk-java依赖,创建AlipayClient,调用支付接口时会生成一段支付表单字符串返回给前端,前端把这段字符串渲染成表单自动提交,就跳转到支付宝收银台了。
订单支付流程需要异步通知机制:支付宝支付成功后会向你的notify_url POST一条通知数据,后台拿到通知后要验签,确认是支付宝发来的,然后修改订单状态为待发货,再更新商品的销量字段。这里注意幂等处理,相同通知可能推送多次,订单状态必须判断当前状态为待支付才允许改成待发货,防止重复处理。
说明一点:本地开发时支付宝异步通知是访问不到你本机的,你需要用内网穿透工具把本地端口暴露到公网。但如果你不想折腾,也可以用轮询方案:前端支付成功后,每隔2秒向后端查一次订单状态,查到待发货就跳转订单详情页。这个方案演示效果也够用,实现还简单。
退款逻辑同理:买家申请退款,管理员同意后调用支付宝退款接口,退款成功后订单状态改为已退款。注意退款金额不能超过支付金额,这个校验在后端做死。
4. 助农特色模块的设计与落地
4.1 助农专区和农产品溯源展示
做助农商城不能真的做成一个普通淘宝,得有平台特色。我在系统里加了两个特色模块。第一个是"助农专区":运营后台可以配置一个专区页面,选择一批商品挂上去,设置专区标题和标语,前端首页渲染成带氛围图的板块。这样既方便运营集中推广,又能在视觉上突出平台的公益属性。
专区的技术实现很简单,就是一张config表存配置信息,字段有:type区分轮播图还是专区、title、image_urls(JSON数组)、product_ids(JSON数组)、status。管理员配置时勾选商品,保存后前端根据product_ids查询商品列表渲染出来就可以了,不用做特别复杂的结构。
第二个是"溯源信息"展示。农产品详情页除了常规的参数规格,我还放了一个溯源模块。数据来自product表里的几个字段:产地、采摘日期、质检报告。等到用户下单购买后,在订单详情页能查看这些信息,相当于给每个订单一个"产地直采"的信任背书。配合农户入驻时的资质信息一起展示,这是一个很有说服力的信任设计。
4.2 农户入驻与资质审核
农户入驻是一个完整的子流程。注册的时候选择"我是农户",除了填基础账号信息,还要提交农场名称、所在地区、主营品类、营业执照照片。这些信息进入farm表和seller_apply表,状态是待审核。
管理员在后台看到入驻申请列表,点进去看农户提交的资料,审核通过后农户的账号角色自动升级为SELLER,登录系统就能进入卖家端。审核拒绝的时候必须填写理由,否则前端没法提示农户到底缺什么材料,这是细节体验问题。
还有一点,农户发布商品时,我在后端做了校验:如果农户的审核状态不是APPROVED,就抛出"请先完成资质审核"异常。虽然前端已经隐藏了发布按钮,但接口层面的数据,保护后端要有,防止有人绕过前端直接调接口,这是我踩过坑之后总结出来的。
5. 踩坑记录:所有问题都曾是拦路虎
5.1 并发超卖让我意外发现的问题
库存扣减我前面讲了用乐观锁方案,但有一个问题是在测试时发现的:直接执行update product set stock = stock - 1 where id = 1 and stock > 0这个SQL,在高并发下很依赖数据库隔离级别。MySQL默认的可重复读隔离级别下,两条并发update语句会串行执行,后执行的因为stock条件不满足而更新0行。但如果写成了先查询stock再在Java代码里判断是否大于0再去update,就会出现超卖,因为两个请求可能都查到了stock=1,然后都去update减一,最终库存变成0了,但都生成了订单。所以业务层也别做"先查出再判断"这种gaffe,就在SQL里一把锁死。
测试并发我建议用JMeter或者Apifox的并发功能,模拟100个用户同时下单同一个商品。之前跑出来的结果是库存还有50个,100个请求成功了80个,剩下20个提示库存不足,数据库里库存正确变成0,说明乐观锁生效了。这个测试报告写进论文里,说服力很强。
5.2 图片上传的路径与访问冲突
农产品展示离不开图片,图片上传功能是每个项目都会踩坑的地方。最经典的问题是:前端上传图片到后端,后端存在本地磁盘的一个upload目录,但浏览器直接通过URL无法访问这个目录。原因是SpringBoot默认的静态资源映射路径是classpath:/static/,不包含磁盘上的自定义目录。
解决方案是在WebMvcConfigurer里加一个addResourceHandlers,把 /upload/** 映射到本地磁盘路径:
java复制@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/upload/**")
.addResourceHandler("file:" + uploadPath + "/");
}
如果项目部署在Linux服务器上,uploadPath要配成绝对路径比如/home/ubuntu/agri/upload,Windows开发环境配成相对路径或者C盘路径都行,用yml配置区分环境即可。
图片存储可以考虑用OSS,但毕设项目免费体验的那种小额度其实不够用,本地存储完全能应付答辩演示。后续真要上线再换七牛云或者阿里云OSS,更换逻辑在Service层封装,调用方不用感知。
5.3 Vue联调时绕不开的跨域与动态路由问题
前端开发服务器默认跑在5173端口(Vite)或者8080(Webpack),后端跑在8080,端口不同就会产生跨域请求。虽然后端加了CorsConfig,但前端这边还是建议在Vite配置里加一个代理,这样开发环境下前端请求的URL是相对路径,不会有跨域问题:
javascript复制// vite.config.js
export default defineConfig({
server: {
port: 5173,
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true
}
}
}
})
前端所有请求都加/api前缀,后端Controller统一加@RequestMapping("/api"),生产环境就用Nginx把/api反向代理到后端服务,一套逻辑开发生产都通。
动态路由是我踩过的另一个坑。因为系统有三种角色,前端路由不能所有人都一样。核心思路是:登录成功后根据角色返回对应的路由表,用router.addRoute动态添加到Vue Router。Vue3里这个API和Vue2的Router.addRoutes不太一样,不能一次性添加数组,得循环单个添加。而且刷新页面后路由会清空,需要在全局守卫里判断是否有路由数据,没有就重新拉取再放行。这个坑我调试了整整一个晚上才理清楚。
6. 项目部署与验收清单
6.1 本地开发与生产打包流程
开发环境怎么跑起来很多人已经会了,我重点讲生产部署。后端我用Maven打包成jar包,在pom.xml里配置了打包插件,要注意SpringBoot的repackage配置,否则打出来的jar不能直接跑。命令就一行:
bash复制mvn clean package -DskipTests
打包完成后在target目录下生成jar文件,放到服务器上用java -jar agri-mall.jar启动。不过我更推荐用Docker部署,写一个Dockerfile:
dockerfile复制FROM openjdk:8-jre-alpine
COPY target/agri-mall.jar /app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app.jar"]
构建镜像之前,先写一个docker-compose.yml把MySQL、Redis、应用三个服务编排起来,一条docker-compose up -d就能把整套环境起起来。这对答辩演示太有用了,评委老师想看环境复现你随时能搭一个。
前端打包是npm run build生成dist目录,我在Nginx配置里做了动静分离:静态文件root指向dist目录,/api开头的请求proxy_pass到后端的8080端口。这里有个细节,前端用了Vue Router的history模式,Nginx要配置try_files重定向到index.html,否则刷新页面就404了。
nginx复制server {
listen 80;
server_name localhost;
root /var/www/agri/dist;
location / {
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
6.2 功能验收清单与答辩加分技巧
最后列一个我在交付项目时用的验收清单,你可以直接抄去测试自己的系统:
- 注册登录:新用户注册、密码加密存储、登录后Token返回、过期后接口拒绝
- 农户入驻:提交资质、管理员审核、审核通过前无法发布商品
- 商品管理:卖家发布商品、图片上传、上下架、库存编辑
- 买家流程:浏览商品、分类筛选、关键词搜索、购物车增减、提交订单、模拟支付
- 订单管理:买家查看订单列表、卖家发货、买家确认收货、取消订单、退款申请
- 后台管理:用户管理、商品审核、分类管理、订单管理、销售统计
答辩的时候不要光演示页面,讲清楚几个关键设计点比啥都强。我建议你重点准备这四块:一是防超卖的乐观锁方案和并发测试数据,二是JWT无状态认证与角色权限控制,三是订单状态机怎么防止状态错乱,四是支付宝沙箱支付的异步通知幂等处理逻辑。这四个点每个都能展开聊几分钟,评委一听就知道你不是只会CRUD。
数据库设计里加一张系统日志表记录管理员关键操作,展示的时候说这是"操作审计模块",又是一个亮点。前端页面稍微加点CSS动画,首页做个渐变banner,答辩观感完全不同。
我个人在实际项目里体会最深的一点是:做这种毕业设计项目,图的是把整个链路的细节都吃透,特别是并发控制、事务一致性和权限安全这些问题,光会调用框架是不够的。你真正把每个环节的边界条件都想到位了,答辩现场无论老师从哪个角度追问,你都能接得上话。数据能跑通只是及格线,逻辑经得起追问才是优秀线。
