ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于Spring Boot的助农商城系统设计与开发实践

基于Spring Boot的助农商城系统设计与开发实践 1. 从选题到落地这个助农商城系统到底在解决什么问题提起Spring Boot项目很多人第一反应是又一个CRUD后台管理系统助农商城听起来也像把普通电商平台换了个皮肤。但真正动手做过之后你会发现农产品产地直供这个场景和标准B2C电商的差异远比想象中大。我在做这个基于Java的助农商城毕业设计时最深刻的体会就是技术难点不在增删改查而在业务链路的设计——农户、消费者、平台管理员三类角色怎么协作商品如何从产地直达用户手中订单状态怎样在各环节之间流转且不出错。说起来这个项目的起源很典型。学校要求做毕业设计选型的核心诉求是三个技术栈要主流、工作量要可控、业务上要有可讲的亮点。Spring Boot作为Java生态里目前最主流的快速开发框架几乎是唯一选择了。而助农商城这个方向既贴合乡村振兴的大背景又能把电商平台最核心的商品、购物车、订单、支付模拟、后台管理全部串起来属于看起来有做头、做起来有内容、答辩时能讲故事的题目。整个项目我采用前后端分离的思路后端用Spring Boot提供RESTful API前端用Vue搭建商城页面和管理后台数据层用MyBatis Plus操作MySQL数据库。系统最终实现了用户注册登录、农产品分类浏览、关键字检索、购物车、下单、模拟支付、订单状态跟踪、农户入驻发布商品、管理员审核与订单管理、数据统计等核心功能。整套代码跑下来覆盖面足够撑起一篇规范的毕业设计论文也能完整演示给老师看。这篇博文就是把整个开发过程重新复盘一遍我会把需求拆解、表结构设计、核心接口实现、订单状态流转、以及我实际踩过的坑都写清楚。不管是做毕设还是想快速搭一套类似的电商学习项目这篇文章都能当一份实操参考。2. 系统需求拆解与功能清单别一上来就写代码我见过太多人做毕设的姿势是打开IDEA新建Spring Initializr项目然后开始对着数据库写CRUD。等写到订单模块时发现业务关系理不清再回头改表结构一来二去时间全浪费了。需求拆解这一步绝对不能省尤其是电商项目先画清楚角色和状态流转再谈代码实现。2.1 三类核心用户的角色矩阵助农商城不是简单的用户买、管理员卖。我的系统里设计了三个角色每种角色看到的界面和能做的事情完全不同。角色核心诉求主要功能消费者买家快速找到想要的农产品下单购买跟踪订单注册登录、浏览搜索商品、加入购物车、下单支付、查看订单状态、确认收货、评价农户/商家卖家发布农产品、管理商品上下架、处理发货商家入驻申请、商品发布与编辑、订单发货、查看自己店铺的销售情况平台管理员把控平台内容与交易秩序做运营统计用户管理、农户入驻审核、商品审核与上下架、订单管理、退款处理、销售数据统计这里有个容易被忽略的设计点农户在入驻前也是普通用户所以用户表里要有角色标识字段入驻申请通过后账号从普通用户升级为商家角色。如果前期没想明白后面经常会出现用户既是买家又是卖家却不知道用哪个身份登录的尴尬。2.2 前台商城的功能明细前台面向消费者功能设计参照主流电商的轻量版。我的清单如下用户模块注册、登录、退出、个人信息修改、收货地址管理。商品模块首页轮播图推荐位、商品分类导航蔬菜、水果、粮油、禽蛋等、商品列表分页、按名称关键字搜索、商品详情展示图片、价格、库存、描述、产地。购物车模块加入购物车、修改数量、删除、批量结算。订单模块确认订单页选择收货地址、提交订单、模拟支付微信/支付宝风格二维码页、订单列表、取消订单、确认收货。评价模块订单完成后可对商品打分并填写评价内容。2.3 后台管理功能清单后台是管理员和商家共用的登录后根据角色显示不同菜单。管理员端用户管理查看用户列表、启用/禁用账号。商家审核查看农户入驻申请通过或驳回。商品审核控制商品上架违规商品可下架处理。订单管理查看全平台订单处理异常退款。数据统计按天统计销售额、订单量按月汇总热销商品Top10。商家端商品管理发布新商品、编辑价格库存、上下架。订单管理查看自己店铺的订单点击发货并填写物流单号。数据看板展示自己商品的销量与销售额。2.4 订单状态流转设计订单状态是整个系统里最容易出错的地方我提前把状态机画清楚再写代码。流程是这样待支付 → 待发货 → 待收货 → 已完成中间允许待支付订单取消特定场景允许退款。状态用整型数字存储比字符串可读性差一点但查询效率高。我的映射如下订单状态0待支付订单状态1待发货已支付订单状态2待收货已发货订单状态3已完成确认收货订单状态4已取消订单状态5退款中 / 已退款这个映射在代码里用一个常量类统一管理禁止在Service层写魔法数字。状态流转做成了统一方法每个状态切换都校验前置状态避免出现未支付直接发货这种逻辑漏洞。3. 技术选型为什么是Spring Boot MyBatis Plus这套组合技术选型这件事我见过不少人纠结到失眠。其实对毕设和中小型实战项目来说选技术栈的底层逻辑只有一个团队或自己最熟的技术体系加上能最快实现需求且坑最少的框架组合。这里顺便回答一个热搜里经常出现的问题springboot配置到底怎么搞、版本怎么选我放在后面避坑章节细说。3.1 后端框架选型的现实考量Spring Boot现在已经是Java后端开发的默认选项几乎不用讨论要不要用关键是版本。我选的是Spring Boot 2.7.18这是2.x分支的最终版本稳定、资料多、兼容性好尤其对JDK 1.8的支持非常成熟。很多同学一上来就选了Spring Boot 3.x结果发现JDK必须升到17MyBatis Plus的旧版方言不兼容一大堆老教程也失效了卡在环境配置上就浪费了两三天。如果你想省事2.7.x JDK 1.8的组合是最稳的。持久层我用了MyBatis Plus而不是原生MyBatis理由很简单单表CRUD不需要手写SQLBaseMapper帮我们省掉大部分重复代码。复杂查询比如订单分页、条件筛选、统计报表用LambdaQueryWrapper也足够灵活。不少人讨论过MyBatis还是JPA我的经验是国内Java生态里MyBatis系的使用率和中文资料都更丰富遇到问题好排查。3.2 前端页面方案的取舍前端我最终用了前后端分离的方式Vue 2 Element UI Axios。为什么不用Thymeleaf服务端渲染做商城这种交互频繁的项目前后端分离之后的接口调试体验、页面局部刷新体验都更好。Vue 2虽然在2023年停止维护了但Element UI的组件生态成熟网上各种后台模板多对毕设来说开发效率最高。如果你对前端不熟也不想折腾Node.js构建流程可以退一步用Thymeleaf Bootstrap做服务端渲染代码是一个整体部署也简单。但如果你选了这个方案面试或答辩时被问到前后端分离相关问题时需要早点准备说辞。我个人更推荐Vue因为电商系统的购物车、分类筛选、订单状态切换这些交互用组件化开发更顺手。3.3 关键依赖与版本说明一览我在pom.xml里加了这些核心依赖提供一个明确的版本组合供参考依赖/工具版本用途JDK1.8基础运行环境Spring Boot2.7.18后端框架MyBatis Plus3.5.3ORM框架MySQL5.7 / 8.0数据库Druid1.2.20数据库连接池Lombok1.18.30简化实体类代码Hutool5.8.25工具类库日期、随机数等Vue2.6.14前端框架Element UI2.15.14前端组件库Axios1.6.0HTTP请求库这套组合的优点是全部有长期稳定的版本不存在依赖冲突问题。另一个容易踩的坑是Druid和Spring Boot 2.x的starter版本号一定要对应推荐直接用官方文档里的最新稳定版本别硬凑。4. 数据库设计农产品订单系统的表结构核心数据库设计几乎是整个项目的灵魂后续写代码快不快、业务扩展难不难这会儿就定了。我总共设计了9张业务表它们之间的关系不算复杂但对初学者来说每张表想清楚字段就不容易。4.1 核心表结构与关系说明系统设计的表如下用户表user用户ID、用户名、密码MD5加盐存储、昵称、手机号、头像、角色标识、状态、注册时间。收货地址表address地址ID、用户ID、收货人、电话、省市区、详细地址、是否默认地址。商品分类表category分类ID、分类名称、排序号。商品表product商品ID、分类ID、商家ID、商品名称、主图、详情图、单价、库存、销量、产地、描述、上架状态、审核状态、创建时间。购物车表cart购物车ID、用户ID、商品ID、购买数量。订单表orders订单ID、订单编号、用户ID、商家ID、收货地址快照、商品总金额、运费、实付金额、订单状态、支付时间、发货时间、完成时间、创建时间。订单明细表order_item明细ID、订单ID、商品ID、商品名称快照、商品图片快照、商品单价快照、购买数量、小计金额。商家入驻申请表merchant_apply申请ID、用户ID、真实姓名、店铺名称、身份证号演示用可做脱敏、联系方式、申请状态、申请时间。评价表comment评价ID、订单明细ID、商品ID、用户ID、评分、评价内容、评价时间。4.2 订单设计里藏着两个关键思想很多人第一次设计订单表时直接在订单表里写用户下单的商品名称和价格这样做后期查历史订单会出大问题——商品改价、改图、下架后历史订单显示的内容就跟着变了。我的方案是引入地址快照和商品快照订单表和订单明细表里存下单那一刻的地址、商品名、图片、单价而不是关联查询实时数据。这是一个实战经验做电商项目必须养成关键业务数据快照的意识。第二个关键点是订单表和订单明细表的拆分。一个订单包含多个商品一对多关系。如果直接把多个商品塞到一个字段里存JSON查询统计时会痛不欲生。所以下单时在一个事务里同时向订单表和明细表插入数据并通过订单编号关联。4.3 金额用BigDecimal时间是Datetime别偷懒这里是新手最容易忽略的地方。网上支付相关项目中价格字段必须用BigDecimal禁止用double或float。我见过有人用double存价格结果下单后对账差了几分钱排查半天才发现是浮点精度问题。比如0.1 0.2在浮点运算里不等于0.3这在精度敏感的金融交易里是致命的。时间字段统一用datetimeJava实体类用LocalDateTime数据库用DATETIME避免用TIMESTAMP在2038年出问题虽然有点远但规范点没坏处。4.4 部分核心建表SQL参考这里给出订单表核心建表SQL其他表逻辑类似CREATE TABLE orders ( id bigint(20) NOT NULL AUTO_INCREMENT, order_no varchar(32) NOT NULL COMMENT 订单编号, user_id bigint(20) NOT NULL COMMENT 下单用户ID, merchant_id bigint(20) NOT NULL COMMENT 商家用户ID, receiver_name varchar(50) NOT NULL COMMENT 收货人姓名(快照), receiver_phone varchar(20) NOT NULL COMMENT 收货人电话(快照), receiver_address varchar(200) NOT NULL COMMENT 收货地址(快照), total_amount decimal(10,2) NOT NULL COMMENT 商品总金额, freight_amount decimal(10,2) DEFAULT 0.00 COMMENT 运费, pay_amount decimal(10,2) NOT NULL COMMENT 实付金额, status tinyint(4) NOT NULL DEFAULT 0 COMMENT 订单状态 0待支付 1待发货 2待收货 3已完成 4已取消 5已退款, pay_time datetime DEFAULT NULL COMMENT 支付时间, delivery_time datetime DEFAULT NULL COMMENT 发货时间, finish_time datetime DEFAULT NULL COMMENT 完成时间, create_time datetime NOT NULL COMMENT 创建时间, PRIMARY KEY (id), UNIQUE KEY uk_order_no (order_no), KEY idx_user_id (user_id), KEY idx_merchant_id (merchant_id) ) ENGINEInnoDB AUTO_INCREMENT1 DEFAULT CHARSETutf8mb4 COMMENT订单表;订单明细表在商品字段时加快照注释是为了提醒自己这些字段存的是下单时的商品信息不随商品表变动。5. 核心后端功能实现从登录鉴权到订单流转数据库设计好了后端开发就有了地图。这一部分我把核心功能的实现思路和关键代码逻辑展开讲尽量做到照着思路就能写出自己的版本。5.1 登录鉴权方案JWT还是Session毕设项目里最常见的登录方案有两种传统Session和JWT。Session配合Cookie简单直接但前后端分离时跨域配置要小心JWT无状态、移动端友好、面试也爱聊。我最终选了JWT方案用Interceptor统一拦截请求校验令牌把用户信息放到ThreadLocal里供后续代码使用。具体流程是用户登录成功后后端用userId和用户角色生成Token时效设置为24小时。前端把Token存在localStorage里每次请求在Header里带上Authorization: Bearer 令牌。拦截器放行登录接口和商品浏览接口其他接口必须校验Token合法才放行。这里要提醒的是JWT刷新和续期逻辑容易绕晕毕设阶段做固定过期时间就够了别给自己加戏。public class LoginInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 放行预检请求 if (OPTIONS.equalsIgnoreCase(request.getMethod())) { return true; } String token request.getHeader(Authorization); if (StringUtils.hasText(token) token.startsWith(Bearer )) { token token.substring(7); Claims claims JwtUtil.parseToken(token); if (claims ! null) { LoginUserHolder.set(claims); return true; } } response.setStatus(401); return false; } }注意每次响应后要清理ThreadLocal否则Tomcat线程池复用时会串用户数据这是一个人踩过之后印象深刻的坑。5.2 商品浏览与检索实现商品列表用MyBatis Plus的分页插件配合LambdaQueryWrapper拼条件。分类、关键字、价格区间、上架状态四个筛选条件封装到查询参数对象里。展示的商品必须同时满足审核通过和上架状态1这是和普通后台管理系统的差别。public PageResultProductVO pageProduct(ProductQuery query) { PageProduct page new Page(query.getPageNum(), query.getPageSize()); LambdaQueryWrapperProduct wrapper new LambdaQueryWrapper(); wrapper.eq(Product::getAuditStatus, 1) .eq(Product::getPublishStatus, 1) .eq(query.getCategoryId() ! null, Product::getCategoryId, query.getCategoryId()) .like(StringUtils.hasText(query.getKeyword()), Product::getName, query.getKeyword()) .ge(query.getMinPrice() ! null, Product::getPrice, query.getMinPrice()) .le(query.getMaxPrice() ! null, Product::getPrice, query.getMaxPrice()) .orderByDesc(Product::getCreateTime); PageProduct result productMapper.selectPage(page, wrapper); // 转换为VO并返回 }分页插件用法很简单但要注意只对selectPage等方法生效自定义大SQL要手动传IPage参数这一点我放在后面的坑里细讲。5.3 购物车与下单事务为什么下单必须加事务购物车逻辑不复杂加入购物车、改数量、删除、清空。订单提交是整个系统核心我在Service层加了Transactional注解在同一个事务里完成五件事校验商品是否在售、库存是否足够。扣减商品库存。创建订单主表记录生成唯一订单编号。批量插入订单明细。清空购物车中已结算的商品。为什么必须加事务因为如果扣库存成功了订单创建失败商品会凭空少一件如果订单创建了库存没扣超卖问题就会出现。只有把这些操作绑在一个事务里要么全部成功要么全部回滚数据才可靠。订单编号生成选了简单可靠的方案时间戳加用户ID再加随机数或者用Hutool的IdUtil.getSnowflakeNextIdStr()。雪花算法生成的ID有序、唯一对分库分表友好这里用它是合适的。Transactional(rollbackFor Exception.class) public Long createOrder(OrderCreateDTO dto, Long userId) { // 1. 查询购物车选中商品 // 2. 计算总金额 // 3. 扣减库存 // 4. 插入订单 // 5. 插入订单明细 // 6. 清空已购买购物车项 }下单接口要注意幂等性。用户连续点两次提交按钮会生成两笔相同的订单。我的简单处理是前端按钮提交后立即置灰后端再通过用户ID商品ID购物车ID做一次重复校验保证同一个购物车记录不会被同时结算两次。5.4 模拟支付的实现细节接入真实支付宝或微信支付需要商户资质和回调地址毕设环境显然不具备。我的做法是做一个模拟支付用户提交订单后跳转到支付页面展示一个二维码样式的图片可以生成静态图也可以用Hutool的二维码工具生成一段支付链接的二维码用户点击我已支付按钮后端直接跳转订单状态到待发货并记录支付时间。支付成功接口要加一个简单的Token校验避免用户伪造请求直接改订单状态。我在支付页URL里拼一个临时支付Token设置5分钟有效只有Token合法才能完成支付。虽然和真实的支付回调、验签逻辑差得很远但至少把状态安全流转这个意识带出来了。5.5 后台订单管理与统计后台订单列表需要联表查询用户昵称、商家店铺名和商品信息。MyBatis Plus的单表QueryWrapper搞不定我写了分页SQL用LEFT JOIN关联订单明细表同时按订单状态筛选。商家只能看到自己店铺的订单所以SQL里必须强制带上merchant_id否则会出现数据越权——这也是毕设答辩时容易被问到的一点你怎么控制商家只能看到自己的订单统计模块我做了两个接口管理员端查全平台每天的销售总额和订单量商家端查自己店铺近7天的商品销量排行。统计SQL用了MySQL的日期函数和GROUP BY返回给前端用ECharts画折线图展示效果很好答辩时有一个有数据的图表页会加分不少。6. 我在开发中踩过的大坑Spring Boot版本、分页插件和其他这部分我认为是整个项目最值钱的干货。很多教程只讲怎么做不讲坑在哪等到自己踩了才发现网络上的经验贴都被踩烂了但没人说出来。6.1 Spring Boot版本太高导致的JDK兼容问题热搜词里那些Java: 警告: 源发行版 17 需要目标发行版 17、idea不能创建springboot项目不能使用jdk1.8基本都是同一个问题Spring Boot 3.x强制要求JDK 17如果本机装的是JDK 8IDEA里创建项目时直接就是灰的或者编译报错。我的建议是毕设项目不要盲目追新。Spring Boot 3.x引入Jakarta EE命名空间javax.*变成jakarta.*很多老教程的代码直接复制过来会报包不存在。我最终用的是Spring Boot 2.7.18 JDK 1.8所有主流资料都能用上遇到问题能搜到答案这是项目能按时交付的最大保障。6.2 MyBatis分页插件的用法与常见翻车MyBatis Plus的分页插件官方文档说了要先配置MybatisPlusInterceptor很多人忘了注册内部分页拦截器结果selectPage查询出来全是同一页数据还以为是插件版本问题。Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }第二个坑是自定义SQL分页不生效。我写后台订单统计时直接在Mapper里写了一句带LIMIT的SQL结果发现分页功能失效。正确做法是自定义SQL分页时把Page对象作为第一个参数传给Mapper方法插件会自动拦截生成count查询和limit语句。但要注意如果SQL里有GROUP BY自动生成的count语句可能报语法错误这种情况需要手动写count查询。6.3 文件上传与XSS过滤的取舍商品图片上传我用了本地存储在服务器磁盘数据库只存url路径。有个小细节需要处理的是Spring Boot的静态资源映射默认只覆盖classpath:/static/外部磁盘的图片路径要手动加一个WebMvcConfigurer映射。图片上传最好限制文件类型和大小我用Spring自带的MultipartFile拿到原始文件名通过后缀白名单判断是否是合法图片格式。千万不能直接用用户上传的原文件名保存到服务器这既是实战习惯也是一种基础安全习惯。另外商品描述、评价这些字段建议做个基础过滤防止用户提交带恶意脚本的内容。我在全局加了一个过滤器对表单参数里的script等危险标签做转义处理。这里要注意的是如果项目需要正常提交富文本HTML比如商品详情里要嵌入图片标签全局过滤会误伤合法内容。我的取舍是商品描述字段走单独的富文本接口不过滤HTML标签只去掉脚本和事件属性其他普通输入字段统一转义。这个思路比一刀切的全滤更合理。6.4 金额与时间字段的处理方式金额用BigDecimal这一点前面说过了这里专门讲下它和前端交互的坑。BigDecimal序列化成JSON后默认可能有科学计数法或者精度不对我在项目里做了全局配置把BigDecimal统一转成字符串返回给前端前端展示“¥123.00”提交时再转回BigDecimal。这个做法可以避免前端JS浮点精度问题。时间字段我统一用LocalDateTime配置了Jackson的yyyy-MM-dd HH:mm:ss格式。前后端时间传输建议都用字符串格式避免时区转换成八小时偏差的问题。后端接收前端的日期参数也要在application.yml里配置spring.jackson.date-format和time-zone否则数据库里的时间和页面上的时间可能对不上。7. 从能跑到能用接口测试、部署上线与演示准备代码写完后距离可以交给老师看还有最后一段路。这部分是很多同学忽略的但恰恰是让项目看起来专业的关键。7.1 接口测试怎么快速验证我用Postman做完接口的冒烟测试重点是订单主流程注册用户 → 登录拿Token → 添加购物车 → 提交订单 → 模拟支付 → 商家发货 → 用户确认收货。这条链路全部走通项目核心功能基本就没问题了。除了主流程还要测一些边界情况库存不足时下单必须报错、未登录访问购物车接口必须返回401、商家不能查看他人订单等等。这些用例可以在答辩时展示说明你考虑了数据安全和业务边界比单纯展示功能更有说服力。7.2 打包部署方案后端用Maven打包成可执行jar包部署到云服务器上跑很简单。我用的命令是mvn clean package -DskipTests nohup java -jar target/farm-mall.jar --server.port8080 app.log 21 前端Vue项目执行npm run build后会在dist目录生成静态文件我把它放到Nginx的web目录下并做反向代理把/api路径转发到后端8080端口。server { listen 80; server_name your-domain-or-ip; root /usr/share/nginx/html; index index.html; location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location / { try_files $uri $uri/ /index.html; } }这里两个关键点Vue Router用history模式时Nginx必须配置try_files回退到index.html否则刷新页面就404接口代理必须带上/api前缀转发否则前后端分离部署就断开连接了。7.3 演示数据准备比想象中重要到了快交付的阶段我意识到一件容易被忽略的事情往数据库里塞一套好看又合理的演示数据。包括五种以上的商品分类、每种分类下5种左右商品、不同状态的订单、几个用户账号和商家账号、几天内的销售数据用来出统计图表。演示数据看起来是小事但直接影响答辩效果。老师打开前台页面时看到商品丰富、图片整齐、数据统计有起伏第一印象就会好不少。我往商品描述里写了真实的产地信息价格设定也贴合农产品行情图片用无版权图库里的实拍图整体上给老师的观感是这个学生真的有认真做系统。8. 收尾时我做过的事情和踩过的最后几个坑按理说功能完成、部署上线就算结束了但有几个收尾的细节我是在最后阶段才补上或者改掉的这里一并分享出来。数据库字符集一定要用utf8mb4而不是utf8。商品名称里可能带个emoji或者生僻地名用utf8会存不进去开发阶段根本发现不了直到测试数据带特殊字符时才突然报错。我后来把所有表的字符集都改成了utf8mb4一些表直接ALTER TABLE转换。密码加密不能存明文。我用的MD5加盐虽然学术界更建议BCrypt但对毕设项目来说MD5加盐配合回答时能说清楚原理也足够。如果想让项目更亮眼直接用BCryptPasswordEncoder也不难Spring Security里现成的工具类比MD5更安全答辩时也可以多一个可讲的点。还有一个实操坑是IDEA运行项目时控制台中文乱码。解决方案是设置-Dfile.encodingUTF-8的JVM参数或者检查数据库连接URL里是否加了characterEncodingutf8。这个小问题不会让功能出错但看日志时满屏幕乱码很影响调试心情建议提前处理。最后就是我把整个项目的历史commit整理了一遍提交信息写得规范一点。这虽然不直接算功能但演示给老师看代码管理能力或者以后放进简历项目描述里都会显得专业很多。看起来不起眼但和堆满update、fix的commit信息比起来整洁的提交记录就是加分项。做完这个项目之后我个人最大的体会是做毕设最重要的是别把项目能跑起来当作终点。能跑只是及格跑得稳定、数据合理、流程完整、边界情况处理得当这些才是一个软件工程专业学生该展示给老师的东西。如果你也准备做一个类似的Spring Boot电商平台我建议你从订单状态设计开始把数据表关系画清楚再动手中间遇到问题先想业务流程再想技术实现路会顺很多。希望这篇复盘能帮你少踩几个我踩过的坑做出一个能安心参加答辩的项目。
返回列表