尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

SpringBoot+Vue3订单管理系统全栈开发实战解析

SpringBoot+Vue3订单管理系统全栈开发实战解析 洗衣店订单管理系统听名字是个不起眼的小业务系统但真把它做扎实了SpringBootVue3MyBatisMySQL这条前后端分离主链路里的弯弯绕绕基本都能摸一遍。我做这个项目不是为了交差而是想完整体验一次从需求梳理、数据库设计、后端接口开发到Vue3前端落地的全流程顺便把订单状态流转、动态SQL、跨域联调这些高频实战点一次讲透。这篇文章就按我实际开发的顺序来写不贴大段无用代码但关键核心的实现思路、参数选型、踩坑记录都会展开适合正在做Java全栈项目、课程设计或者想系统过一遍SpringBootVue3业务系统的人参考。1. 项目定位与全局架构梳理1.1 洗衣店订单管理到底在管什么我接触过的洗衣店大多数还停留在手写单据、微信记一笔、月底翻本子的阶段。老板最头疼的几件事不知道某件衣服现在在哪个环节顾客来取衣服找不到单子月底统计营收全靠Excel手工加。这些痛点落到系统里其实就是一个典型的订单全生命周期管理。用户下单、门店接单、衣物进入洗涤流程、状态逐步更新、顾客凭单取衣、支付结算每一步都需要记录时间、操作人和状态变化。所以核心不是增删改查四个字而是怎么把订单状态的变化过程管清楚怎么让顾客和店员都能实时看到衣服走到哪一步了。我当时的做法是先画订单的状态流转图再反推数据库表和接口设计。状态定成待取件、洗涤中、可领取、已完成、已取消外加一个异常状态用于记录洗涤损坏等情况。每个状态变更都强制写入一张订单流水表这样后续做统计、追溯、纠纷处理都有据可依。很多初学者上来就只建一张订单表改状态直接update了事等需要查昨天下午三点到四点之间哪些订单状态变了这类问题时直接抓瞎。这是我的第一个经验业务系统的核心是状态和日志不是字段。1.2 为什么选SpringBootVue3MyBatis这套组合技术选型我纠结过一段时间。先说说为什么不走传统方案JSPServlet那套太老了模板渲染和服务端Session在前后端分离的现在维护成本高SSMSpringSpringMVCMyBatis虽然经典但大量XML配置写起来很痛苦。SpringBoot把自动配置做到位之后项目启动和开发效率提升非常明显内嵌Tomcat也让部署变得简单。Vue3作为前端框架Composition API在逻辑复用和代码组织上比Options API清晰得多配合Element Plus做后台管理系统表格、表单、弹窗这些组件开箱即用。MyBatis作为持久层框架半自动SQL的灵活性在处理多条件查询、复杂关联时比JPA更可控尤其在报表统计这类需要手写SQL的场景MyBatis基本是首选。MySQL做存储开源免费业务支持度也高配合Navicat或命令行工具管理数据很顺手。要说缺点也有。SpringBoot的自动配置在遇到版本冲突时排查起来比较头疼Vue3的生态虽然成熟但很多老教程还是Vue2写法容易被带偏MyBatis的XML文件多了以后维护难度是递增的。所以这个组合适合的是中小型业务系统团队最好有人能hold住SQL调优。如果是超级复杂的领域模型Spring Data JPA可能更合适但就洗衣店订单这种偏传统结构的业务MyBatis反而更直白。1.3 功能模块划分与前后期开发节奏整个系统我拆成了七个模块客户管理、衣物管理、订单管理、收银结算、员工账号、数据看板、系统设置。客户管理解决这个顾客以前来过吗、他的联系方式是什么、有没有欠款衣物管理记录每件衣物的品类、颜色、材质和特殊洗涤要求订单管理是核心模块负责下单、状态流转和改价收银结算负责支付记录和每日营收员工账号区分店长和店员权限数据看板展示今日订单量、营收、待取件数量这些指标。开发节奏上我的建议是先做数据库设计再完成后端接口最后做前端页面。后端接口先跑通Postman再对接Vue页面这样可以避免前后端同时出问题导致定位困难。我实际开发顺序是设计表结构→搭SpringBoot骨架→完成客户和订单的基础CRUD→设计状态机接口→做Vue3列表页和表单页→联调→添加看板统计→最后统一处理权限和异常。这样的节奏保证每个阶段都有一个可验证的产出物不会出现写了一个月代码还不知道项目能不能跑起来的问题。2. 数据库设计从订单状态机到MySQL表结构2.1 订单状态机的具体定义和流转规则状态机是整个项目的地基。我在代码里用枚举定义订单状态并且把合法的状态流转配成一个Map每次更新时校验当前状态是否允许跳到目标状态。比如待取件只能流转到洗涤中或已取消洗涤中只能流转到可领取或异常可领取只能流转到已完成。这个校验逻辑虽然简单但能挡住绝大多数的脏数据操作。比如两个人同时操作一个订单A把订单从待取件改成了洗涤中B还想把订单改成已完成系统就会拦截提示当前状态不允许变更。如果完全不校验订单状态就会变成乱套的状态后续统计全部失真。洗衣店订单还有一个特殊性一个订单里可能有多件衣物而且每件衣物有不同的洗涤方式。我设计的订单主表和订单明细表分离主表存订单编号、客户ID、总金额、状态、期望取件时间明细表存每件衣物的品类、数量、单价、备注。状态控制放在主表维度因为洗护流程一般是以整单为单位推进的但如果后续需求升级需要支持部分衣物先完成那就要把状态下沉到明细表。这个我留了一个字段设计上的余地明细表里也有一个单独的status字段保留着为后续扩展做准备。2.2 核心表结构设计与MySQL字段选型细节客户表大概长这样id、姓名、手机号唯一索引、性别、会员等级、累计消费、创建时间、备注。订单表核心字段是id、order_no业务订单号唯一索引、customer_id、total_amount、status、receivable_time期望取件时间、actual_pickup_time实际取衣时间、remark、create_time、update_time。订单明细表id、order_id普通索引、clothing_type衣物品类、clothing_name具体描述、quantity、price、material材质、wash_type洗涤方式、status。支付记录表id、order_id、payment_method微信/支付宝/现金/挂账、amount、create_time。字段类型上金额一律用DECIMAL(10,2)不要用DOUBLE或FLOAT。DOUBLE在MySQL里是近似值计算金额会出现0.10.2不等于0.3这类问题这笔钱收错账可没法跟老板交代。状态字段用TINYINT还是VARCHAR我最终选了VARCHAR存的是英文枚举名比如PENDING、WASHING、READY、COMPLETED、CANCELLED。因为直接用数字枚举排查数据时还得对照文档翻译用英文可读性好很多。订单号用了LS前缀加日期加随机数比如LS202401150001。时间字段统一用datetime不要为了省事用timestamp两者虽然都能存时间datetime的可读性和范围更适合业务系统何况系统要考虑跨时区问题datetime配合应用层统一使用北京时间是最省心的方案。2.3 MyBatis动态SQL与多条件组合查询实战洗衣店后台最常用的查询是订单列表但查询条件组合非常多按客户手机号查、按状态查、按日期范围查、按订单号查甚至组合起来查。如果每个组合都写一个固定的SQL那工作量没完没了。MyBatis的where标签配合if判断是解决这个场景的利器。我在Mapper XML里写了一个动态SQL核心逻辑是条件非空才拼接到WHERE后面MyBatis会自动帮我去掉多余的AND这段代码我用到现在没有出过问题。订单列表动态查询的核心写法是这样的先用where包住所有条件再用if teststatus ! null判断状态if testcustomerPhone ! null and customerPhone ! 判断手机号日期范围的判断用if teststartTime ! null内部SQL条件是create_time #{startTime}结束时间同理。最需要注意的坑是手机号查询一定要走客户表关联我用了LEFT JOIN条件是c.phone LIKE CONCAT(%, #{customerPhone}, %)。如果用等于号客户只记得尾号四位时这个查询就废了。报表统计我写了一条按日期聚合的SQL用来做数据看板的拉取。SQL用DATE_FORMAT把create_time截取到天再按状态分组。这里踩过一个坑DATE_FORMAT会让索引失效数据量小没事但数据量大时查询会明显变慢。我的处理方式是把条件限制在最近30天避免全表扫描。如果想长期做报表推荐单独建一张日统计汇总表用定时任务或者当天订单结束时统一汇总查询时直接查汇总表效率会高很多。3. 后端业务实现SpringBoot分层与订单流转核心逻辑3.1 分层架构怎么分才能让人看得懂我的后端包结构分了controller、service、mapper、entity、dto、vo、common这几层。很多初学者把所有逻辑堆在Controller里一个接口几百行代码看着是跑通了但改一个需求要翻半天。我的习惯是Controller只做参数接收和结果返回业务逻辑全在Service层。Service层里方法按业务动作命名比如createOrder、cancelOrder、updateOrderStatus。Mapper层只负责数据访问不写业务。DTO和VO要严格区分接收前端参数的叫DTO返回给前端展示的叫VO。比如生成订单时DTO里是客户ID和衣物明细列表而返回订单详情时VO里要有订单状态的中文描述而不是PENDING这种英文枚举。之所以强调这个区分是因为我见过太多项目直接用Entity返回给前端。Entity里的createTime、updateTime这些字段全暴露出去像customer_id这类内部字段也透出到前端既不安全又不规范。用VO封装一下把前端需要看的字段组合好接口返回值就稳定了。即使后续数据库表结构调整前端也不用跟着改。这个理念在团队协作时尤其重要我不希望改一个字段影响整个前端页面。3.2 订单创建的事务处理与状态更新校验创建订单是系统里事务边界最明确的场景往订单主表插入一条数据往明细表插入多条数据如果明细插入中途失败主表数据必须回滚否则就出现订单金额和明细对不上的脏数据。我用Spring的Transactional注解处理事务默认遇到RuntimeException就会回滚。但要注意异常被Service内部catch且没有重新抛出时事务是不会回滚的这个坑必须记住。比如我在循环插入明细时如果某条数据校验失败抛了业务异常这个异常继承RuntimeException并且一路往上抛事务管理器才能感知到。状态更新的核心是一个通用的updateStatus方法参数是订单ID、目标状态、操作人ID。方法内部第一步先查当前订单第二步从配置Map里查当前状态是否允许跳到目标状态不允许直接抛异常允许则更新订单并插入一条订单流水记录。流水表里记录变更前状态、变更后状态、操作人、变更时间。这里有个小细节更新订单时我加了乐观锁SQL是UPDATE orders SET status #{targetStatus} WHERE id #{id} AND status #{currentStatus}影响行数为0说明期间状态被改过了此时抛异常提示用户刷新重试。这个写法比在应用层查询再判断更可靠把并发控制放到了数据库层。3.3 统一返回体与全局异常处理前后端分离项目必须有一套统一的接口返回格式。我定义了Result类结构是code、message、data三个字段code为200是成功500是系统异常还有业务码如40001表示参数校验失败。前端Axios拦截器统一判断code非200直接弹message。这个设计极大减少了前端的重复处理逻辑不用每个页面都写try catch了。全局异常处理是另一块关键内容。我在SpringBoot里用了RestControllerAdvice加ExceptionHandler做全局异常捕获。业务异常、参数异常、数据库异常分别映射到不同的code和message。这里有个很实用的处理参数校验我用了javax.validation的Valid注解在Controller入参上标注校验失败的异常由全局异常处理器统一返回40001。这样Controller方法不再需要每一行参数都手写if判断代码干净很多。但要注意自定义异常类必须继承RuntimeException否则全局处理器接不到。这个细节我在教别人看代码时发现很多人会写错成Exception子类导致事务无法回滚。4. Vue3前端落地从Composition API到接口联调4.1 Composition API和Options API怎么选Vue3的Composition API刚推出时争议很大我实际用过之后体会很深代码组织方式完全变了。Options API是把数据、方法、生命周期拆成data、methods、created这些固定块组件逻辑复杂时同一业务的数据分散在各个块里改起来要来回跳跃。Composition API按业务逻辑组织代码比如订单列表相关的数据、方法、计算属性全写在一个setup区域里还可以抽成自定义函数复用。我写了两个组件对比过同一个订单列表筛选分页功能Composition API的可维护性好太多。但Composition API也有门槛。ref和reactive怎么选是新手最容易懵的点。我的经验是基本类型用ref对象类型用reactive但reactive有个麻烦是解构后会丢失响应式所以从reactive解构出来的字段要用toRefs包一层。在写订单表单时表单对象我用reactive提交时直接传整个对象单独拿出来的loading状态用ref。还有就是组合式函数的抽离我把订单列表的查询逻辑抽成一个useOrderList函数返回响应式数据、刷新方法、加载状态不同页面想用同一套逻辑直接调用这个函数就行。这个模式写完以后我开始理解为什么Vue3社区推崇Composition API了。4.2 Pinia状态管理与用户登录态处理前端状态管理我选了Pinia它是Vue3官方推荐的状态库比Vuex轻不少而且TS支持友好。这个系统用状态管理的地方主要是登录状态和用户信息。用户登录成功后后端返回一个token前端存到localStoragePinia里存用户信息。Axios请求拦截器从localStorage取出token加到请求头响应拦截器发现401就跳回登录页。很多人会在Pinia里直接存token刷新页面就丢了这是大坑。因为Pinia是内存状态刷新后重新加载所以token必须持久化到localStorage或cookie里。Axios封装是我特别想分享的点。我先创建了一个request实例配置baseURL为/api这样开发环境用Vite代理转发到后端生产环境用Nginx代理。请求拦截器统一加token不做任何其他业务逻辑避免后期维护混乱。响应拦截器做统一处理code为200时直接返回data非200时用Element Plus的ElMessage弹出错误信息401时清空登录态并跳转登录页。所有页面调用接口时只关心成功的返回数据异常分支全部由拦截器兜底。这种封装模式在团队开发时特别省心新同事写页面只管发起请求不用管状态码逻辑。4.3 Element Plus表格表单与订单流转交互设计订单管理页是我前端做得最多的部分。列表用el-table渲染每一行显示订单号、客户、金额、状态描述、创建时间和操作按钮。状态用el-tag展示不同状态配不同颜色绿色是已完成蓝色是洗涤中橙色是待取件灰色是已取消。操作区用几个小按钮控制待取件状态显示开始洗涤洗涤中显示标记可取可领取显示完成取衣。按钮的显隐靠当前状态行数据判断写成函数返回布尔值。这个交互设计比较直观店员不需要培训也能上手。为了减少页面跳转我用了对话框嵌套表单的方式处理下单和编辑。点击新增订单按钮打开el-dialog里面嵌套el-form衣物明细部分用动态表格支持增删行。表单校验用了Element Plus的rules手机号必填且要匹配正则金额必须大于0。这里有个前后端联调的注意点前端表单校验只做体验优化真正的合法性校验必须在后端再做一次前端绕过太容易了。我自己测试时就发现直接Postman调接口绕过前端校验完全可行所以后端接口的Valid参数校验不能少。4.4 跨域问题与Vite代理配置跨域是前后端分离项目必踩的坑。我本地开发时Vue跑在5173端口SpringBoot跑在8080端口两个端口不同直接请求就会被浏览器的同源策略拦截。解决方案有两种后端加CORS配置或者前端用代理。我选了前端代理方案在vite.config.js里配置server.proxy把/api开头的请求转发到localhost:8080同时也要配置SpringBoot放行因为即使前端代理了某些场景下后端的CORS还是要配好。我的做法是两边都配Vite代理用于本地开发后端CORS用于万一有直接请求的场景。生产环境用Nginx统一处理代理和静态资源这就不会再有跨域问题了。5. 报表看板与系统部署实战5.1 数据看板的SQL聚合与接口设计数据看板是洗衣店老板最看重的功能我做了四个核心指标今日订单数、今日营收、待取件数量、近7天订单趋势。今日订单数和营收用一条SQL搞定SELECT COUNT(*) AND SUM(total_amount) FROM orders WHERE DATE(create_time) CURDATE()。待取件数量就是查询status为PENDING的订单数。近7天趋势我用GROUP BY DATE(create_time)把未来7天的日期先用Java生成数组再对应填充数据这样没有订单的日期也能显示0而不是空。接口返回结构我设计成一个Map包含总订单数、总营收、待取件数、趋势List前端拿到数据后直接用ECharts渲染柱状图和折线图。这里需要注意看板接口是高频查询每次都实时统计会对数据库造成压力。我在Service层加了本地缓存用的是简单的Caffeine设置5分钟过期过期后重新查库。这个方案对小业务系统够用了不需要引入复杂的Cache方案。如果洗衣店以后有多家分店看板还得加一个按店分组的维度接口设计时我把storeId作为可选参数预留了。5.2 SpringBoot项目打包与常见耗费时间的大坑后端打包我用的是Maven执行mvn clean package -DskipTests生成jar文件后直接java -jar运行。但这里有三个常见的坑要走。第一是JDK版本不对发行环境如果用的JDK8而本地开发用的JDK17那打包时maven编译插件版本得匹配目标机器上也要装相应的JDK否则报UnsupportedClassVersionError。第二是配置文件区分生产和开发环境我在application.yml里用了spring.profiles.active开发环境用application-dev.yml连接本地MySQL生产环境用application-prod.yml连接服务器MySQL数据库密码用环境变量读取避免明文写在配置文件里。第三是MySQL连接时区问题连接串必须加上serverTimezoneAsia/Shanghai否则插入时间会比北京时间晚8个小时排查这种时间错乱问题时极其折磨。前端打包相对简单npm run build生成dist目录。有两种部署方式一种是用Nginx托管dist文件并配置反向代理另一种是把dist文件复制到SpringBoot的static目录里直接由后端服务托管。对小项目来说合并部署最省心一个Java进程解决所有问题。但合并部署有个坑SpringBoot对静态资源的访问要放行我设计了一个WebMvcConfigurer把登录接口和静态资源路径加进白名单其他请求都要求登录。如果用了Spring Security这个配置会相对更复杂我的方案是没有引入Security框架只用一个简单的拦截器做的登录校验保证轻量。5.3 MySQL安装与数据库迁移的实战经验很多人在项目跑到一半时才去装MySQL遇到一堆环境问题。我自己在Windows上装MySQL 8.0时踩过密码验证组件和SSL连接错误两个坑。SSL连接错误常见于客户端连接到MySQL时校验证书失败解决方案是在连接串加useSSLfalseallowPublicKeyRetrievaltrue开发环境禁用SSL连接即可因为开发环境不涉及公网传输敏感数据生产环境再启用SSL。密码插件的问题表现为Authentication plugin caching_sha2_password cannot be loaded这个老版本客户端连MySQL 8.0常常出现要么升级驱动到8.x版本要么用ALTER USER改回mysql_native_password。我直接用了MySQL 8.0对应的JDBC驱动从根源上规避了这个问题。数据库结构迁移我用了最简单可靠的方式用Navicat的数据同步功能把开发库的表结构同步到生产库再单独导出基础数据脚本。真实的业务系统还可以用Flyway或者Liquibase来做版本化迁移但那个对单机小项目来说有点重。我更喜欢用SQL脚本记录每次表结构的变更文件命名按照日期用途比如20240115_add_order_index.sql这样整个项目的数据库演进有据可查。这个习惯是我被坑了两次之后养成的之前直接改表结构结果生产库忘了加字段接口跑起来疯狂报错。6. MyBatis核心机制与常见问题排查实录6.1 MyBatis的一级缓存与二级缓存到底怎么用这个问题也是面试高频题我在实际项目里把它摸透了。MyBatis的一级缓存是SqlSession级别的同一个SqlSession执行同样的查询会返回缓存结果但注意Spring整合MyBatis后每个Mapper方法默认是独立SqlSession的事务方法里多个查询才共用同一个SqlSession。一级缓存有个坑查询结果被缓存后如果数据库被其他系统改了缓存不会自动失效就会读到脏数据。所以我在订单状态更新这类敏感操作上避免在同一个事务里先查再改后查的写法必须在修改后调用sqlSession.clearCache()或者直接避免依赖一级缓存。二级缓存是命名空间级别的跨SqlSession生效。但在我的这个系统里二级缓存是不建议开启的。因为缓存粒度太粗订单表被频繁更新开启二级缓存反而导致缓存命中率低还可能出现数据不一致。MyBatis官方文档说二级缓存只适合查询多、修改少、对实时性要求不高的场景比如配置表、字典表。我在系统里只有衣物品类字典表开了二级缓存其他表全都没开。理解了缓存机制以后排查为什么改了数据前端不刷新这类问题就快很多了。6.2 TypeHandler在枚举和金额字段上的应用TypeHandler是MyBatis里很实用的扩展点。我的订单状态在Java里是枚举类型在数据库里是VARCHAR两者之间就需要一个转换器。虽然MyBatis对枚举有默认处理但默认存的是枚举name而我从订单流水的历史记录里读出来时希望能在代码里直接用枚举就需要自定义TypeHandler。简化操作后我在枚举字段上标注了TableField配合MyBatis-Plus的通用枚举处理如果用的是纯MyBatis那就要在Mapper XML的resultMap里指定typeHandler。还有金额字段的精度问题。Java Bean里我用BigDecimal数据库用DECIMAL(10,2)MyBatis内置的BigDecimalTypeHandler足够应付不需要自定义。但我必须注意减法运算后的setScale比如计算找零时BigDecimal.valueOf(100).subtract(totalAmount)的结果可能是53.300000000000004这种浮点尾数必须在业务里统一用setScale(2, RoundingMode.HALF_UP)。这个问题隐藏得很深不处理的话会出现金额显示的奇怪尾巴顾客扫一眼就能发现问题所以我写了工具方法专门处理金额的精度。6.3 MyBatis初始化流程与XMLConfigBuilder的作用排查MyBatis问题的时候我顺带把它的启动流程看了一遍。MyBatis的初始化入口是SqlSessionFactoryBuilder它调用XMLConfigBuilder解析mybatis-config.xml全局配置文件把environment、typeAliases、mappers这些配置逐项加载。解析mapper时XMLMapperBuilder会一个节点一个节点地解析SQL语句包括参数映射和结果映射。理解这个流程对我调试的帮助是当报Invalid bound statement (not found)错误时我第一时间会检查mapper.xml文件里的namespace是不是和Mapper接口全限定名一致然后再看SQL的id与接口方法名是否对得上最后检查target目录下有没有打包进xml文件。这个错误是我遇到频率最高的MyBatis问题十次里有八次是namespace写错或xml没被扫描到。另一个相关问题是SpringBoot整合MyBatis时MapperScan注解不生效时Mapper接口无法被代理注册启动会报找不到bean。常规检查项包括主启动类上有没有MapperScan注解包的路径对不对是否有多个数据源互相干扰。我习惯在application.yml里加mybatis.mapper-locationsclasspath:mapper/*.xml配置确保resources下的XML文件被正确加载。6.4 SpringBoot版本与依赖兼容性整理的实战记录SpringBoot版本太高也不见得是好事。我在一个旧项目遇到SpringBoot 2.7升级到3.x之后javax.servlet被替换成jakarta.servlet很多老代码直接编译不过。这个洗衣店系统我用了SpringBoot 2.7.18这是2.x系列最后一个版本相对稳定也能兼容jdk8或11。如果一上来就选最新的SpringBoot 3.2配合的JDK至少要是17MySQL驱动、MyBatis starter这些版本都要跟着匹配稍微不注意就出现NoSuchMethodError。依赖版本冲突排查我推荐一个笨办法先跑mvn dependency:tree看依赖树再用IDE的依赖分析工具交叉定位。最常见的问题是MyBatis Spring Boot Starter里的mybatis-spring版本和Spring版本相关性不匹配。网上很多教程直接给最新版本号但不同版本的特性不一样最可靠的方法是去Spring Initializr生成项目骨架然后按需添加starter这样版本组合是官方验证过的。这个习惯帮我省了很多时间。7. 完整项目实操总结与后续扩展思路7.1 一套可以直接参考的开发流程清单结合这个洗衣店项目我整理了一份业务系统开发的常规流程第一步梳理业务需求画出核心实体的状态流转图这一步决定了系统的骨架第二步设计数据表结构先定主表和明细表再定状态字段的存储类型第三步搭后端骨架配置好统一返回体、全局异常、Swagger文档第四步实现核心业务接口优先处理订单创建和状态更新这类事务边界清晰的接口第五步做前端页面按模块依次推进登录、列表、表单、看板第六步联调重点关注跨域和接口返回结构的一致性第七步打包部署区分开发和生产环境的配置文件第八步做权限和数据安全的补漏。这份清单不仅适用于洗衣店系统换成餐饮点单、健身房会员管理、宠物店预约这些业务骨架完全通用。我后来接其他项目时都是复用这套流程和部分脚手架代码效率提升非常明显。核心思路是不要接到需求就写代码先把状态流转和表结构想清楚后面所有开发都顺了。7.2 权限控制、数据备份与安全加固的经验权限控制我没有引入Spring Security用的是拦截器加角色判断。登录成功后把用户ID和角色存进Session拦截器从Session里取角色店长可以访问员工管理、查看营收报表、取消订单等接口店员只能操作订单和客户模块。这种轻量方案适合内部管理系统比引入Spring Security简单得多但也要明白它的局限没有细粒度的权限控制比如操作日志和接口权限分离做不了。如果后续向客户交付建议升级为标准的RBAC模型引入权限框架。数据备份是最容易被忽视但最要命的环节。我用mysqldump写了一个定时备份脚本每天凌晨2点导出订单库到备份目录保留最近7天的备份文件。脚本里加了--single-transaction参数保证备份过程中不影响线上业务写入。我还记得第一次部署后第三天测试环境误删了一张表因为备份脚本还没配置好只能手工通过binlog恢复折腾了大半天。从此以后我养成了习惯数据库脚本上线前先做备份备份文件先验证能不能恢复再谈其他。7.3 后续扩展多门店、小程序对接与消息提醒洗衣店订单管理系统做到这里已经能支撑单店使用了。但真实的商业场景往往是多门店连锁顾客在A店下单衣服可能送到B店洗涤用户取衣服可能在C店。这就需要在订单上增加门店维度再引入门店调拨的状态订单详情里记录每次流转的门店和时间。数据库方面要设计门店表和门店员工关系表订单表加store_id字段报表看板加门店筛选条件。客户端方向现在洗衣店基本都要配合微信小程序或公众号使用。小程序端主要负责用户自助下单、订单状态查询和取件提醒复用后端已有的接口即可。取件提醒可以用SpringBoot整合WebSocket实时推送或者接入阿里云短信服务发送模板消息。这些扩展方向都需要在系统设计之初就预留接口我在订单表里预留的status字符串和流水表就是为了这些场景服务的。项目做到这一步才算是真正从能跑变成了能用从我个人的经历看一个业务系统的价值不在于用了多牛的技术而在于是否真正解决了使用者的日常问题。我在开发这个系统的过程中最大的体会是被需求推着走的时候最忌讳一上来就写代码。花一个晚上把状态流转图和表结构想清楚后面几个星期的开发都会顺畅得多。洗衣店订单管理虽然业务简单但订单状态、金额精度、并发控制、权限管理这些细节一样不少把一个简单业务做扎实收获比做三个半成品大得多。如果你正在做类似的项目建议先把我写的第2章和第3章的核心设计思路吃透再动手写代码。就这样。
返回列表