
1. 项目概述从零到一构建一个自助洗衣店管理系统最近在帮几个计算机专业的学弟学妹看毕业设计发现“自助洗衣店管理系统”这个选题的热度一直居高不下。这也不难理解一方面自助洗衣店作为线下零售服务的一个细分领域其业务流程清晰、实体明确非常适合作为管理类系统的练手项目另一方面这个项目天然涵盖了用户端、设备端、管理后台等多个维度技术栈选择灵活能充分考察学生对Java Web全栈开发的理解。今天我就以一个过来人的视角结合我当年做项目和后来带项目的经验把这个系统的设计思路、技术选型、核心实现以及部署上线的完整过程掰开揉碎了讲清楚。无论你是正在为毕设发愁的学生还是想找个完整项目练手的Java初学者这篇文章都能给你提供一个从需求分析到代码落地的清晰路径。这个系统的核心目标是模拟一个真实的商业场景用户通过小程序或网页预约洗衣机、在线支付、启动洗衣店主则在后台管理设备、订单、营收和用户。它不是一个简单的CRUD增删改查练习而是涉及了多角色权限控制、在线支付集成、设备状态实时模拟、订单状态机、数据统计分析等多个在企业级应用中常见的模块。接下来我会按照“为什么这么设计 - 具体怎么实现 - 可能会遇到哪些坑”的逻辑带你走完全程。2. 系统整体设计与架构选型2.1 核心业务需求与功能模块拆解在做任何系统之前抛开技术先把业务逻辑理清楚是重中之重。我们站在店主和用户两个角度来思考店主后台管理员的核心诉求设备管理添加/删除洗衣机、烘干机设置其状态空闲、使用中、故障、型号、收费标准按小时或固定套餐。订单与营收管理查看所有历史订单和实时订单进行对账支持按日、周、月生成营收报表。用户管理查看注册用户处理用户反馈或投诉。运营监控一个仪表盘能一眼看到今日营收、设备使用率、热门时段等关键数据。用户小程序/网页端的核心诉求发现与选择查看附近或所有可用的洗衣机能根据型号、价格、预计等待时间筛选。预约与支付选择心仪的机器和洗衣模式快洗、标准洗、大件洗预约时间段并完成在线支付。使用与控制支付成功后在预约时间内有权限启动机器这里我们通过系统模拟并能查看剩余洗衣时间。个人中心查看自己的历史订单、消费记录管理个人信息。基于以上诉求我们可以将系统划分为三大模块后台管理模块面向店主使用Web页面功能集中且复杂。用户服务模块面向消费者优先考虑开发微信小程序用户粘性高也可兼容H5页面。核心业务与数据模块为前后端提供统一的API接口处理订单、支付、设备状态等核心逻辑。2.2 技术栈选型背后的逻辑为什么选择Java对于毕设和中小型项目Java生态的成熟、稳定以及丰富的开源库是最大优势。下面是我的技术选型清单和理由后端框架Spring Boot 2.7.x Spring MVC MyBatis-PlusSpring Boot约定大于配置能快速搭建项目内嵌Tomcat部署简单。这是目前Java后端开发的事实标准。Spring MVC成熟的MVC框架处理Web请求清晰明了。MyBatis-Plus在MyBatis基础上做了大量增强提供了通用的CRUD方法、分页插件、代码生成器能极大减少枯燥的SQL编写工作。对于毕设这种表结构相对固定的项目效率提升非常明显。为什么不选JPA/HibernateJPA的“对象-关系映射”思想很优雅但在处理复杂查询、需要精细控制SQL时学习成本和调试难度对初学者稍高。MyBatis-Plus在灵活性和效率上取得了更好的平衡。数据库MySQL 8.0关系型数据库事务支持完善社区活跃。自助洗衣店的订单、用户信息关联性强适合用关系模型来存储。表结构设计时要特别注意订单表的设计它需要关联用户ID、设备ID、支付流水号并包含订单状态待支付、已支付、进行中、已完成、已取消、金额、开始/结束时间等字段。前端后台管理Vue 3 Element PlusVue.js框架易于上手组件化开发思想清晰。Element Plus是基于Vue 3的桌面端组件库提供了丰富的后台管理UI组件表格、表单、图表等能让我们快速搭建出专业的管理界面。为什么不用JSP/Thymeleaf前后端分离是当前主流能让后端专注于API开发前端独立部署职责清晰也更利于团队协作虽然毕设可能就你一个人。前端用户端微信小程序 Uni-app可选微信小程序触达用户最方便。如果时间紧张也可以先用H5页面模拟核心是跑通业务流程。如果希望一套代码同时生成小程序和H5可以考虑Uni-app框架它基于Vue语法学习成本低。关键中间件与集成Redis用于缓存设备状态、用户会话、短信验证码。例如将“设备A当前状态”缓存在Redis中前端频繁查询时无需每次都访问数据库性能提升显著。微信支付/支付宝沙箱集成在线支付是项目的亮点。毕设环境下强烈建议使用官方沙箱环境进行模拟支付完全免费且不会产生真实资金流水既安全又能完整实现支付回调逻辑。Quartz或Spring Scheduler用于处理定时任务。例如扫描超时未支付的订单并自动取消或者模拟洗衣完成时更新订单和设备状态。注意技术选型没有绝对的对错只有适合与否。对于毕设“成熟、稳定、资料多”是首要原则。上述组合是经过大量项目验证的“全家桶”能确保你在遇到问题时能快速找到解决方案。3. 数据库设计与核心表结构解析数据库是系统的基石设计得好后续开发事半功倍。这里重点讲几个核心表的设计思路和避坑点。3.1 用户表 (sys_user)除了常规的id,username,password,phone,avatar之外需要特别注意balance(余额)用户充值后的余额可用于支付避免每次小额支付都走第三方接口。openid如果做微信小程序这是用户的唯一标识用于关联微信用户。status用户状态正常、禁用。CREATE TABLE sys_user ( id bigint NOT NULL AUTO_INCREMENT COMMENT 主键, username varchar(50) DEFAULT NULL COMMENT 用户名, phone varchar(11) NOT NULL COMMENT 手机号, password varchar(100) DEFAULT NULL COMMENT 密码后台管理员用, openid varchar(100) DEFAULT NULL COMMENT 微信openid, avatar varchar(255) DEFAULT NULL COMMENT 头像, balance decimal(10,2) DEFAULT 0.00 COMMENT 账户余额, status tinyint DEFAULT 1 COMMENT 状态1-正常0-禁用, create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, PRIMARY KEY (id), UNIQUE KEY uk_phone (phone), KEY idx_openid (openid) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表;3.2 设备表 (laundry_device)这是业务的核心实体。device_number设备编号如“A-01”具有唯一性方便线下识别。type设备类型1-洗衣机 2-烘干机。status核心字段。定义状态机0-离线/故障1-空闲2-使用中3-预约中。这个状态需要和后端逻辑、前端展示强关联。current_order_id当前正在进行的订单ID可为空。通过此字段能快速定位设备正在服务哪个订单。price_per_hour每小时单价。也可以设计一个price_ruleJSON字段来存储更复杂的计费规则如首小时价格后续每小时价格。CREATE TABLE laundry_device ( id bigint NOT NULL AUTO_INCREMENT COMMENT 主键, device_number varchar(20) NOT NULL COMMENT 设备编号, type tinyint NOT NULL COMMENT 类型1-洗衣机2-烘干机, brand varchar(50) DEFAULT NULL COMMENT 品牌, model varchar(50) DEFAULT NULL COMMENT 型号, status tinyint NOT NULL DEFAULT 1 COMMENT 状态0-故障1-空闲2-使用中3-预约中, price_per_hour decimal(10,2) NOT NULL COMMENT 每小时价格元, current_order_id bigint DEFAULT NULL COMMENT 当前订单ID, location varchar(255) DEFAULT NULL COMMENT 位置描述, create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间, PRIMARY KEY (id), UNIQUE KEY uk_device_number (device_number), KEY idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT洗衣设备表;3.3 订单表 (laundry_order)这是系统的“主动脉”记录了每一笔交易的完整生命周期。order_number订单号唯一通常由时间戳随机数生成用于对外展示和查询。status订单状态机这是业务逻辑最复杂的地方。建议定义为0-待支付1-已支付2-进行中3-已完成4-已取消。状态变更必须严谨比如只有“已支付”的订单才能变为“进行中”。pay_type支付方式微信、支付宝、余额。pay_time支付成功时间用于对账。estimated_end_time预计结束时间根据洗衣模式和设备计算得出。actual_end_time实际结束时间由系统定时任务或用户手动确认完成时更新。CREATE TABLE laundry_order ( id bigint NOT NULL AUTO_INCREMENT COMMENT 主键, order_number varchar(32) NOT NULL COMMENT 订单号, user_id bigint NOT NULL COMMENT 用户ID, device_id bigint NOT NULL COMMENT 设备ID, amount decimal(10,2) NOT NULL COMMENT 订单金额, status tinyint NOT NULL DEFAULT 0 COMMENT 状态0-待支付1-已支付2-进行中3-已完成4-已取消, pay_type tinyint DEFAULT NULL COMMENT 支付方式1-微信2-支付宝3-余额, pay_time datetime DEFAULT NULL COMMENT 支付时间, start_time datetime DEFAULT NULL COMMENT 洗衣开始时间, estimated_end_time datetime DEFAULT NULL COMMENT 预计结束时间, actual_end_time datetime DEFAULT NULL COMMENT 实际结束时间, create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 更新时间, PRIMARY KEY (id), UNIQUE KEY uk_order_number (order_number), KEY idx_user_id (user_id), KEY idx_device_id (device_id), KEY idx_status (status), KEY idx_create_time (create_time) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT洗衣订单表;3.4 设计心得与避坑指南字段注释一定要写这不仅是为了文档当你三个月后回头看代码或者答辩时老师提问清晰的注释能救命。索引不是越多越好在上述表中我对phone,openid,device_number,order_number等查询条件字段建立了唯一或普通索引。status,create_time这种常用于筛选和排序的字段也建议加索引。但不要为每个字段都加索引会影响写入性能。关于“软删除”很多教程会教你在每个表加一个is_deleted字段做逻辑删除。对于毕设我建议谨慎使用。特别是订单、支付记录这类核心业务数据物理删除风险很大。更常见的做法是使用status字段来标记数据状态如禁用或者严格限制删除权限只允许归档操作。金额字段用decimal绝对不要用float或double存储金额会有精度丢失问题。decimal(10,2)表示总共10位小数点后2位足够应付大部分场景。4. 后端核心业务逻辑实现详解有了清晰的数据模型后端开发就是“填空”。这里我挑几个最核心、最容易出错的业务逻辑来讲。4.1 订单状态机与并发控制这是系统的核心难点。用户预约、支付、启动设备、完成洗衣每一个动作都对应着订单和设备状态的变更。必须保证这些变更的原子性和一致性。场景用户A和用户B几乎同时看到洗衣机X空闲都点击了预约。错误实现后端接收到请求后查询数据库发现设备状态是“空闲”然后直接执行update device set status3 where idX。如果两个请求同时到达可能都会执行成功导致一台设备被预约两次。正确实现使用数据库乐观锁或分布式锁。方案一基于数据库版本号的乐观锁推荐用于毕设在设备表增加一个version字段版本号默认0。UPDATE laundry_device SET status 3, version version 1 WHERE id #{deviceId} AND status 1 AND version #{currentVersion}执行这条SQL后检查affected rows受影响的行数。如果为1表示更新成功抢到了设备如果为0表示条件不满足可能状态已被其他请求修改返回“设备已被占用”给用户。MyBatis-Plus的Version注解可以方便地实现乐观锁。方案二基于Redis的分布式锁在尝试预约时先尝试获取一个以设备ID为Key的Redis锁使用SETNX命令获取成功才能执行业务逻辑完成后释放锁。这更适合分布式部署环境对于单机毕设项目乐观锁更简单直接。状态流转的代码实现以支付回调后开始洗衣为例Service Transactional(rollbackFor Exception.class) // 开启事务 public class OrderService { Autowired private OrderMapper orderMapper; Autowired private DeviceMapper deviceMapper; public boolean startWashing(Long orderId) { // 1. 查询订单并锁定行for update防止其他事务同时修改 Order order orderMapper.selectOrderForUpdate(orderId); if (order null || !OrderStatus.PAID.getCode().equals(order.getStatus())) { throw new BusinessException(订单状态异常无法启动); } // 2. 查询设备并锁定行 Device device deviceMapper.selectDeviceForUpdate(order.getDeviceId()); if (device null || !DeviceStatus.RESERVED.getCode().equals(device.getStatus())) { throw new BusinessException(设备状态异常无法启动); } // 3. 更新订单状态为“进行中” order.setStatus(OrderStatus.IN_PROGRESS.getCode()); order.setStartTime(new Date()); orderMapper.updateById(order); // 4. 更新设备状态为“使用中” device.setStatus(DeviceStatus.IN_USE.getCode()); device.setCurrentOrderId(orderId); deviceMapper.updateById(device); // 5. 设置一个定时任务在“预计结束时间”触发模拟洗衣完成 // 可以使用Spring的Scheduled或Quartz这里简化为一个异步任务 scheduleOrderCompletion(orderId, order.getEstimatedDuration()); return true; } }实操心得在涉及多个表状态联动更新时务必使用Transactional注解保证事务性。对于核心资源的查询如这里的订单和设备使用SELECT ... FOR UPDATE进行悲观锁能最直接地避免并发问题但要注意锁的粒度避免长时间持有锁导致性能瓶颈。对于毕设项目这个复杂度是完全可以接受的并且是答辩时的亮点。4.2 微信支付/支付宝沙箱集成支付是另一个亮点但也是雷区。严禁在毕设中使用真实商户号和真实支付沙箱环境是官方提供的完美解决方案。以微信支付V3为例集成步骤申请沙箱商户号在微信支付商户平台有专门的沙箱环境入口可以获取沙箱商户号sandbox_mchid、API密钥sandbox_key等。引入SDK在pom.xml中添加微信支付官方Java SDK依赖。配置参数在application.yml中配置沙箱环境的参数注意与生产环境隔离。wx: pay: sandbox-mode: true # 开启沙箱模式 app-id: your_sandbox_appid mch-id: your_sandbox_mchid mch-serial-no: your_serial_no # 平台证书序列号 private-key-path: classpath:/apiclient_key.pem # 商户私钥 api-v3-key: your_sandbox_api_v3_key统一下单API后端提供一个接口接收前端传来的订单信息金额、描述等调用微信支付SDK的/v3/pay/transactions/jsapi接口生成前端调起支付所需的prepay_id和签名参数。支付回调通知这是最关键也是最容易出错的一步。微信支付成功后会异步通知你的服务器一个结果。你需要提供一个公网能访问的API本地开发可以用内网穿透工具如ngrok或cpolar。在回调接口中验证签名的合法性防止伪造通知然后处理业务逻辑更新订单状态为已支付最后返回SUCCESS给微信否则微信会反复通知。处理业务逻辑时同样要注意并发和幂等性同一笔支付可能收到多次通知要保证只处理一次。RestController RequestMapping(/api/pay) public class PayController { PostMapping(/wx-notify) public String wxPayNotify(HttpServletRequest request, RequestBody String notifyData) { // 1. 验证签名使用微信支付SDK提供的方法 if (!verifySignature(request, notifyData)) { return FAIL; } // 2. 解析通知数据 WxPayOrderNotifyResult result parseNotifyData(notifyData); // 3. 根据商户订单号out_trade_no查询本地订单 Order order orderService.getByOrderNumber(result.getOutTradeNo()); if (order null) { return FAIL; } // 4. 检查订单状态避免重复处理幂等性 if (OrderStatus.PAID.getCode().equals(order.getStatus())) { return SUCCESS; } // 5. 更新订单状态并关联设备等后续操作 boolean success orderService.handlePaidOrder(order, result); return success ? SUCCESS : FAIL; } }避坑指南沙箱环境的金额有限制如1分钱到几元钱测试时注意。回调地址必须是POST方法且不能带参数。签名验证失败是新手最常遇到的问题务必仔细核对证书路径、密钥是否正确以及时间戳是否在允许的误差范围内。4.3 定时任务模拟洗衣流程由于我们没有真实的物理洗衣机接口需要用定时任务来模拟洗衣的进行和完成。使用Spring自带的Scheduled注解Component public class LaundryScheduleTask { Autowired private OrderService orderService; // 每30秒扫描一次预计结束时间已到的“进行中”订单 Scheduled(cron */30 * * * * ?) public void scanAndCompleteOrders() { ListOrder orders orderMapper.selectExpiredInProgressOrders(); for (Order order : orders) { try { orderService.completeOrder(order.getId()); } catch (Exception e) { log.error(完成订单失败 orderId: {}, order.getId(), e); // 可以加入重试机制或告警 } } } // 每5分钟扫描一次超时未支付的“待支付”订单自动取消 Scheduled(cron 0 */5 * * * ?) public void scanAndCancelUnpaidOrders() { // ... 逻辑类似 } }在completeOrder方法中需要将订单状态更新为“已完成”释放设备状态为“空闲”并清空设备的current_order_id。同时可以给用户发送一条模板消息小程序或站内信通知洗衣已完成。注意事项Scheduled默认是单线程的如果任务执行时间过长会阻塞后续任务。如果定时任务逻辑复杂可以考虑使用Async注解使其异步执行或者使用更强大的Quartz框架。对于毕设Scheduled完全够用。5. 前端与后台管理界面构建要点5.1 后台管理Vue3 Element Plus后台管理的核心是数据展示、操作和图表。项目初始化使用Vite创建Vue3项目安装Element Plus和Axios。路由与权限使用Vue Router。根据登录用户的角色超级管理员、普通店员动态生成侧边栏菜单。可以将路由配置存储在后台前端登录后获取。API请求封装使用Axios拦截器统一处理请求头如添加Token、响应错误如401跳转登录页。典型页面实现设备管理页表格展示设备列表支持按状态、类型筛选。包含“新增”、“编辑”、“设为故障”、“恢复”等操作按钮。设备状态可以用el-tag组件不同状态配不同颜色一目了然。订单管理页这是最复杂的页面。表格需要展示大量信息订单号、用户、设备、金额、状态、时间。一定要加入分页组件。提供强大的筛选条件时间范围、订单状态、支付方式、设备编号等。可以加入“导出Excel”功能这是很实用的加分项。数据统计页使用ECharts或AntV等图表库。绘制折线图展示近7天/30天的每日营收趋势。饼图展示不同设备类型的收入占比或使用率。柱状图展示一天中不同时间段的订单量热门时段。 这些数据需要后端提供专门的统计查询接口。5.2 用户小程序端原生或Uni-app小程序端追求简洁、流畅、引导清晰。首页顶部可放轮播图活动公告中部是设备列表。每个设备卡片清晰显示编号、类型、状态标签、当前价格。状态为“空闲”的设备卡片高亮并可点击。列表支持下拉刷新和上拉加载更多。预约/下单流程点击空闲设备 - 进入设备详情页选择洗衣模式不同模式对应不同时长和价格- 确认订单页显示总价、预计时长- 调起支付。支付成功后跳转到“我的订单”详情页并显示倒计时。在这个页面可以有一个“启动洗衣”的按钮实际是通知后端更新状态。我的页面包含“我的订单”、“账户余额”、“充值”、“联系客服”等入口。订单列表同样需要清晰的状态标签和分页。状态同步用户停留在订单详情页看倒计时时如何实时获取洗衣完成状态有两种简单方案短轮询前端每10-15秒请求一次接口查询订单状态。实现简单但有一定延迟和服务器压力。WebSocket更优建立长连接后端在订单完成时主动推送消息给前端。体验更好但实现稍复杂。对于毕设短轮询完全可以接受。6. 系统部署与上线实操指南开发完成最后一步是让项目跑起来能被别人访问和测试。这里给出一个最主流的部署方案Linux服务器 Docker Nginx。6.1 环境准备与项目打包后端打包在项目根目录执行mvn clean package -DskipTests会在target目录下生成一个xxx.jar文件。这个jar包包含了所有依赖和嵌入式Tomcat。前端打包后台管理执行npm run build生成dist文件夹。小程序使用微信开发者工具上传代码提审如果只是演示真机调试即可。用户H5同样npm run build生成dist。6.2 服务器环境配置以CentOS 7为例假设你有一台云服务器学生通常有优惠。# 1. 更新系统并安装必要工具 yum update -y yum install -y vim wget net-tools # 2. 安装JDK 17Spring Boot 2.7推荐 wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.rpm rpm -ivh jdk-17_linux-x64_bin.rpm # 配置环境变量 echo export JAVA_HOME/usr/java/jdk-17 /etc/profile echo export PATH$JAVA_HOME/bin:$PATH /etc/profile source /etc/profile java -version # 验证安装 # 3. 安装Docker简化MySQL、Redis部署 curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun systemctl start docker systemctl enable docker # 4. 使用Docker运行MySQL和Redis docker run -d --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDYourStrongPassword123 \ -e MYSQL_DATABASElaundry_db \ -v /opt/mysql_data:/var/lib/mysql \ mysql:8.0 --character-set-serverutf8mb4 --collation-serverutf8mb4_unicode_ci docker run -d --name redis \ -p 6379:6379 \ -v /opt/redis_data:/data \ redis:alpine redis-server --appendonly yes6.3 应用部署与Nginx配置上传文件使用FTP工具如FileZilla或scp命令将后端的jar包和前端的dist文件夹上传到服务器例如/opt/app/目录下。运行后端cd /opt/app # 使用 nohup 在后台运行并将日志输出到文件 nohup java -jar laundry-system-1.0.0.jar --spring.profiles.activeprod app.log 21 # 使用 jps 命令查看Java进程 jps -l配置Nginx安装Nginx:yum install -y nginx编辑配置文件/etc/nginx/nginx.conf或/etc/nginx/conf.d/laundry.confserver { listen 80; server_name your-domain.com; # 你的域名或服务器IP # 后台管理前端 location /admin { alias /opt/app/admin-dist/; # 前端构建产物路径 index index.html; try_files $uri $uri/ /admin/index.html; # 支持Vue Router的history模式 } # 用户H5前端如果有 location / { alias /opt/app/h5-dist/; index index.html; try_files $uri $uri/ /index.html; } # 反向代理后端API location /api/ { proxy_pass http://127.0.0.1:8080/; # 你的Spring Boot应用地址 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } # 静态资源缓存 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires 1y; add_header Cache-Control public, immutable; } }* 检查配置并重启nginx -t nginx -s reload6.4 域名、HTTPS与持续运行域名解析在云服务商控制台将你的域名A记录解析到服务器公网IP。HTTPS非常重要使用Let‘s Encrypt免费证书。安装certbot工具一行命令即可为你的域名申请并自动配置SSL证书让网站变成安全的https://。进程守护上面的nohup方式不够健壮。生产环境建议使用systemd来管理Spring Boot应用实现开机自启、自动重启。创建服务文件/etc/systemd/system/laundry.service[Unit] DescriptionLaundry Management System Afternetwork.target [Service] Typesimple Userroot WorkingDirectory/opt/app ExecStart/usr/bin/java -jar laundry-system-1.0.0.jar --spring.profiles.activeprod SuccessExitStatus143 Restartalways RestartSec10 [Install] WantedBymulti-user.target* 然后执行systemctl daemon-reload, systemctl start laundry, systemctl enable laundry。7. 开发与部署中的常见问题排查即使按照步骤来也难免会遇到各种“坑”。这里记录几个我踩过和常见的问题问题1前端访问后端API出现CORS跨域错误。表现浏览器控制台报错Access-Control-Allow-Origin。原因前端运行在localhost:3000后端在localhost:8080端口不同浏览器出于安全策略阻止。解决在后端Spring Boot应用中添加一个全局CORS配置类。Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/api/**) // 针对所有/api开头的接口 .allowedOriginPatterns(*) // 允许所有来源生产环境应指定具体域名 .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*) .allowCredentials(true) .maxAge(3600); } }问题2MySQL连接失败提示“Public Key Retrieval is not allowed”。表现应用启动时数据库连不上。原因MySQL 8.0驱动默认要求SSL或身份验证方式问题。解决在Spring Boot的数据库连接配置application-prod.yml中增加参数spring: datasource: url: jdbc:mysql://your-server-ip:3306/laundry_db?useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue # ... 其他配置问题3部署后上传图片或文件失败。表现在管理后台上传设备图片提示成功但找不到文件。原因开发时文件可能上传到项目的static/upload目录但打包成jar后这个目录是只读的。解决永远不要将用户上传的文件放在jar包内或项目目录下应该指定一个绝对路径并确保应用有读写权限。# application-prod.yml laundry: file: upload-dir: /opt/app/upload/ # 服务器上的绝对路径在代码中使用Value(${laundry.file.upload-dir})注入该路径。同时需要在Nginx中配置该目录的静态访问让前端能通过URL访问到图片。问题4定时任务不执行。表现配置了Scheduled但日志显示从未触发。原因Spring Boot的定时任务默认是关闭的或者主类上缺少EnableScheduling注解。解决检查主启动类是否添加了EnableScheduling。同时确保任务方法所在的类是一个Spring Bean即被Component,Service等注解修饰。问题5微信支付回调通知接收不到。表现支付成功了但订单状态没变日志显示没有收到回调。排查检查回调地址确保在微信商户平台配置的回调URL是公网可访问的且是POST方法。本地开发必须用内网穿透。检查签名验证在回调处理的第一行打印接收到的所有请求头和参数与微信官方文档对照。99%的问题出在签名验证失败。检查网络与防火墙服务器是否开放了80/443端口云服务器的安全组规则是否允许外网访问该端口检查日志在回调方法开始和结束处打日志看请求是否进来处理逻辑是否走到。做这个项目的过程中最大的体会是把一个想法变成可运行的代码再把代码变成线上服务每一个环节都需要严谨的思考和大量的细节处理。从数据库字段类型的选择到支付回调的幂等性设计再到部署时的一个Nginx配置项任何一个疏忽都可能导致功能异常。对于计算机专业的同学来说完成这样一个涵盖分析、设计、开发、部署全流程的项目其价值远超过仅仅实现几个算法。它让你第一次系统地感知到一个软件产品是如何诞生的这份经验无论是对于毕业答辩还是对于未来的求职面试都是一块分量十足的敲门砖。最后在真正动手前建议先用纸笔或工具如Draw.io把系统的核心流程、表结构关系图画出来思路清晰了编码就会顺利很多。