十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

基于微信小程序和SSM框架的宠物寄养平台设计与实现

基于微信小程序和SSM框架的宠物寄养平台设计与实现 1. 宠物寄养平台的业务场景与核心需求盘点做了这么多年开发我接手过不少类似的项目先说一个比较反直觉的观察宠物寄养平台的项目难点从来不在技术本身而在需求拆解这一步。很多同学一上来就急着建表、写接口结果做到一半发现角色权限没想清楚订单状态流转卡住了甚至不知道商家端该给谁用。所以这篇博文里我会把整个项目从需求分析、技术选型到核心代码、部署排错完整过一遍围绕微信小程序 SSM这条主线把这个宠物寄养平台的设计与实现讲透。先说这个平台要解决的业务问题。养宠物的人都有过这样的时刻出差、旅游、逢年过节回老家宠物不能带又不能天天找朋友帮忙这时候就需要一个靠谱的寄养渠道。但传统的线下宠物店寄养存在信息不透明、预约不方便、价格不清晰等问题。宠物寄养平台就是把宠物主人找寄养服务这件事从线下搬到线上主人打开微信小程序筛选附近的寄养点查看商家资质、环境照片、寄养价格、用户评价在线提交预约商家接单完成后互相评价形成一个完整的交易闭环。我听下来这个项目的核心需求可以拆成三个角色来理解宠物主人用户端注册登录、维护宠物档案、浏览寄养点、提交预约订单、支付或到店付款、订单跟踪、评价管理。寄养商家/个人商家端入驻申请、管理寄养服务信息价格、房型、可接数量、接单/拒单、确认宠物入住、确认离店、查看收益记录。平台运营管理后台审核商家入驻、管理用户和商家、发布公告、处理投诉、统计平台数据。从业务流上看核心链路就是找店 - 提交预约 - 商家接单 - 送宠入住 - 离店结算 - 双方评价。这条链路看似简单却是整个系统设计和数据库表结构设计的主心骨。我这里特别强调一下很多毕设项目的评分高低不取决于功能多花哨而在于这条主链路是否完整闭合、状态是否可追溯、异常情况比如商家拒单、用户取消是否被处理了。能做到这一点项目拿高分基本没问题。1.1 需求清单与功能模块划分把上面三个角色的需求进一步细化就得出一份可以指导开发的功能清单。做毕设项目时功能不是越多越好而是要做到关键功能完整、非关键功能适度精简。我给出的推荐清单如下角色核心功能扩展功能可选用户端微信登录、宠物档案、寄养点列表与搜索、寄养点详情、提交预约、订单列表、取消订单、评价收藏寄养点、消息通知商家端入驻资料提交、服务信息维护、接单/拒单、订单状态更新、收入查看服务日历、价格策略管理后台商家审核、用户管理、订单管理、公告管理数据看板、投诉处理我第一次做这类项目时犯过一个典型的错误把大量精力放在用户端的界面美化上结果商家端和管理后台简陋得不像话答辩时老师一问商家怎么接单后台怎么审核就卡住了。所以这里给大家提个醒三个端的功能要均衡宁可每端少做两个功能也不能让某一端没法用。1.2 需求分析中最容易被忽视的三件事第一件是订单状态的定义。很多同学表中只放一个status字段但没有明确每一状态之间的流转条件代码写起来就各种 if 嵌套最后自己也绕晕了。这个项目里合理的状态设计应该是待接单 - 已接单/已拒单 - 宠物已送达 - 寄养中 - 已离店 - 已完成 - 已取消。其中用户只能在待接单状态取消商家只能在寄养中结束前接单这些规则必须在前端按钮显示和后端接口校验里同时落地。第二件是地图与定位的需求边界。很多同学看到“寄养平台”就想着要高德地图、LBS定位、距离排序结果 SDK 接入、key 申请、坐标转换搞了一周核心业务反而没时间做。事实上对毕设项目而言用省市区三级地区选择 寄养点地址文本描述就足够了。如果实在想加分可以接入腾讯地图的逆地址解析但也要量力而行。第三件是支付环节的取舍。微信支付需要商户号、需要企业资质个人开发者基本无法直接接入真实支付。这个项目的合理做法是用“提交预约时生成订单状态到店支付后由商家在订单中确认收款”这种线下支付方式同时在订单中记录支付状态字段模拟完整的支付流程。答辩时明确说明这一点老师是认可的因为你展示了业务思考而不是乱接一个用不了的支付 SDK。把这些理清楚之后数据库设计和接口设计才有依据不然很容易翻工。2. 技术选型的底层逻辑为什么是微信小程序SSM技术选型这块我不想只是列一堆技术名词而是想和大家聊聊选这套组合拳的底层逻辑。你在答辩时一定会被问为什么用微信小程序不用原生App或H5为什么后端用SSM不用SpringBoot这些问题看似简单但很多人答不好因为只停留在大家都这么用的层面。2.1 微信小程序端的四个决定性优势这个项目我不用原生App最直接的理由是分发成本。用户不会为了订一次宠物寄养专门去应用商店下载App但微信小程序通过扫一扫、搜索、分享卡片就能打开几乎零门槛。这一点对于低频、区域性、小体量的生活服务类产品来说是非常关键的。第二个优势是开发成本和认证成本。个人开发者注册小程序账号只需要简单的身份认证就能拿到完整的开发工具链不需要像App那样准备软著、各种资质、上架审核对毕设项目的时间安排极度友好。第三个优势是微信生态的身份即服务。wx.login获取临时code后端拿code向微信服务器换取openid就能唯一标识用户。这省掉了手机号验证码、邮箱注册、密码找回这一整套账号体系对项目开发量来说是个不小的减负。第四个优势是模板消息与订阅消息。订单状态变更时通过微信的订阅消息能力推送给用户不需要额外做短信系统或站内信系统这又是一个很实用的能力。我会在后面的章节专门展开wx.login和后端 Session 建立的具体代码实现因为这是每次微信小程序后端项目里大家都绕不开的一个点。2.2 SSM框架的职责边界与选择理由后端选SSMSpring SpringMVC MyBatis在当下看起来确实有点复古但它在毕设项目里的地位依然稳固原因有三。第一SSM的三层架构抽象非常清晰。Controller接口层负责接收请求和返回结果Service业务层负责业务逻辑和事务控制Mapper持久层负责数据库操作。这种分层会让代码的可读性和可维护性非常高评审老师打开你的项目看到包结构就能判断你有没有工程化思维。第二MyBatis的SQL可控性更适合业务型系统。Spring Data JPA虽然开发快但对动态SQL的支持和SQL语句的可读性在这个多条件查询按城市搜、按服务类型筛、按价格排序较多的场景里MyBatis的动态SQL明显更好用。第三SSM的知识体系对校招和考研复试都有价值。Spring的IOC/AOP思想、SpringMVC的请求处理流程、MyBatis的ORM映射这些经典框架的原理面试官是必问的。用SSM做毕设相当于一边做项目一边复习了主流框架的核心理论。那么为什么不推荐SpringBoot呢不是说不能而是如果指导老师熟悉SSM或者代码模板、参考文档都是基于SSM的用SpringBoot反而要自己绕一些配置增加额外成本。技术选型的首要原则永远是选你最有把握快速跑通的组合而不是选最新最热的组合。2.3 前端小程序与后端SSM的协作方式这个项目在架构上有一个需要提前想清楚的问题前端小程序和后端SSM是不是前后端分离的我的建议是按照前后端分离的思想开发但在部署形态上保持简单。小程序端是一个独立工程使用wx.request请求后端接口接口返回JSON数据这是天然的前后端分离。后端SSM只提供RESTful风格的JSON接口不返回视图页面。开发时两边并行推进联调时通过开发者工具的不校验合法域名开关轻松对接。这样做的好处是项目演示的时候可以现场打开小程序不需要启动任何前端devServer整个链路简单可靠不容易在答辩现场翻车。同时这种逻辑分离、部署简单的风格也符合现在企业里很多中小型项目的实际情况。3. 数据库与接口设计项目能不能跑通的胜负手数据表设计是这类项目里面最容易出彩也是最容易拉胯的部分。我见过太多项目功能代码写得很快一查数据库全是坑字段含义不清晰、没有外键逻辑关联、状态字段设计不合理、时间字段没有默认值。这些问题在自测阶段不明显一到联调阶段或者答辩演示多用户并发操作时就会原形毕露。3.1 核心数据模型与建表思路宠物寄养平台的核心表我建议至少设计这么几张用户表user用户ID、微信openid、昵称、头像、手机号、角色类型用户/商家/管理员、创建时间。宠物档案表pet宠物ID、所属用户ID、宠物名称、品种、年龄、性别、体重、是否绝育、疫苗情况、性格备注、宠物照片。寄养点/商家表foster_shop商家ID、关联用户ID、店铺名称、营业执照号、店铺地址、所在城市、服务类型全托/日托、宠物笼位数量、可接收宠物类型、环境照片、评分。服务项目表service_item服务ID、关联商家ID、服务类型小笼/中笼/大笼/独立单间、价格/天、可接数量、已订数量、描述。订单表order订单ID、订单编号、用户ID、宠物ID、商家ID、服务项目ID、预约开始日期、预约结束日期、总金额、状态、下单时间、更新时间。评价表review评价ID、订单ID、用户ID、商家ID、评分1~5、内容、创建时间。公告表notice公告ID、标题、内容、创建时间。这里分享一个我之前踩过的坑订单表里一定要冗余一份商品/服务名称、数量和价格快照。什么意思呢比如订单关联了服务项目service_item但商家后来改了价格如果订单只存service_item_id查历史订单金额就会发现对不上因为关联记录已经被更新了。正确的做法是在订单表里冗余service_name、unit_price等字段下单时就锁定当时的信息。这种细节是数据库设计里用空间换可靠性的典型思路。再补充一个字段规范上的建议所有表都加上create_time和update_time使用datetime类型并设置默认值状态字段用tinyint或int在Java代码里用枚举或常量类维护含义不要用字符串直接存已接单这种中文值否则后期所有统计SQL都会写得很痛苦。3.2 接口设计的RESTful约定与返回格式前后端通过JSON交互最怕的就是接口风格不统一。这个项目里我强烈建议统一使用以下约定基础路径/api/模块名/操作例如/api/pet/list、/api/order/create。请求方法语义化查询用GET新增用POST更新用PUT删除用DELETE。统一返回体后端所有接口返回一个统一的Result对象结构为{ code: 200, message: success, data: {...} }。前端在wx.request的success回调里先判断code是否为200再做后续逻辑避免每个接口写一套错误处理。分页参数统一为pageNum、pageSize分页结果统一为{ total, list }。统一返回体的写法看起来简单但对联调效率的提升是非常明显的。前端再也不需要关心某个接口成功时返回什么结构、失败时又返回什么结构所有异常在message里都给清楚了。我在这个项目里还会在Result里增加一个setResult重载方法方便业务层快速返回带数据的成功结果或错误提示。3.3 微信登录态与接口鉴权方案这是整个项目里最容易出错的地方。很多同学做微信小程序后端以为拿到openid就完事了结果接口谁都能调数据没有任何保护。其实正确的做法是这样的用户打开小程序后前端调用wx.login()拿到临时code后端拿到code后用小程序的appid和secret调用微信接口code2Session换取openid和session_key。后端拿openid去用户表查找找不到就自动注册一个新用户找到就直接复用。然后后端生成一个自定义的登录态token可以用UUID以token - userId的映射关系存到服务端可以存在Redis也可以暂时存在内存Map或数据库表中返回给前端。前端后续所有请求都在请求头里带上token后端通过拦截器Interceptor校验token是否有效并从中获取当前用户ID。下面这段是核心代码的骨架我用SpringMVC的拦截器来实现登录态校验public class LoginInterceptor implements HandlerInterceptor { Autowired private TokenService tokenService; Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token request.getHeader(token); if (StringUtils.isBlank(token) || !tokenService.checkToken(token)) { response.setStatus(401); response.setContentType(application/json;charsetUTF-8); response.getWriter().write({\code\:401,\message\:\未登录或登录已过期\}); return false; } Integer userId tokenService.getUserId(token); request.setAttribute(currentUserId, userId); return true; } }有了这个拦截器Controller里就可以非常方便地获取当前登录用户ID来处理业务。这个设计在答辩时也非常加分因为体现了你对接口安全性的考虑而不是把所有接口都裸奔在公网。4. 核心功能模块的实现思路与关键代码功能模块的实现我挑几个最能体现项目水平的模块来具体讲。我不会把每个CURD都列一遍那样没有意义而是选择那些涉及业务状态、有技术含量、容易出彩的模块。4.1 宠物档案管理文件上传与Oss方案宠物档案模块核心功能是维护一个宠物列表每只宠物会有照片上传的需求。这里要面临一个问题图片传到哪里如果直接把图片以Base64的方式存到数据库里系统很快会卡到怀疑人生而且数据库体积会变得很夸张。比较合理的方案是后端提供一个文件上传接口将文件保存到服务器某个静态目录比如/upload/pet/同时把访问路径返回给前端前端只把路径字符串保存到数据库的photo字段。后端用SpringMVC实现文件上传核心代码如下PostMapping(/api/upload/image) public Result uploadImage(RequestParam(file) MultipartFile file) { if (file.isEmpty()) { return Result.error(请选择文件); } String originalFilename file.getOriginalFilename(); String ext originalFilename.substring(originalFilename.lastIndexOf(.)); String fileName System.currentTimeMillis() _ UUID.randomUUID().toString().replace(-, ) ext; String uploadDir D:/upload/pet/; // 实际项目中建议配置到properties File dir new File(uploadDir); if (!dir.exists()) { dir.mkdirs(); } try { file.transferTo(new File(uploadDir fileName)); } catch (IOException e) { e.printStackTrace(); return Result.error(文件上传失败); } return Result.success(/upload/pet/ fileName); }前端小程序端用wx.chooseMedia选择图片再用wx.uploadFile调用上传接口wx.chooseMedia({ count: 1, mediaType: [image], sourceType: [album, camera], success(res) { const tempFilePath res.tempFiles[0].tempFilePath; wx.uploadFile({ url: http://localhost:8080/api/upload/image, filePath: tempFilePath, name: file, success(uploadRes) { const data JSON.parse(uploadRes.data); if (data.code 200) { // data.data 就是上传后的图片访问路径 } } }); } });这里有一个容易被忽略的重点上传图片之前一定要对文件类型做限制。当前端是一个Formidable/Apache工具提交时没有太大关系但如果是真实环境任意文件上传是一个高危漏洞攻击者可以直接上传JSP或恶意脚本到服务器。所以后端一定要校验扩展名只允许jpg、png、gif、webp这几种图片格式并且要对文件大小做限制比如不超过5MB。4.2 寄养预约流程订单状态机的实现预约模块是整个项目的核心。前端用户选择好寄养点和宠物后点击提交预约后端创建一个状态为待接单的订单。商家在小程序商家端看到待接单列表点击接单后订单状态变为已接单用户会收到订阅消息通知。这里最难的是状态流转控制我的做法是在OrderService里写一个专门的状态流转方法public Result updateOrderStatus(Integer orderId, Integer targetStatus, Integer operatorId) { Order order orderMapper.selectById(orderId); if (order null) { return Result.error(订单不存在); } // 校验操作者身份与当前状态 if (order.getStatus() 0 targetStatus 1 shopMapper.checkShopOwner(order.getShopId(), operatorId)) { // 待接单 - 已接单只有该寄养点商家才有权限操作 order.setStatus(1); orderMapper.updateStatus(orderId, 1); return Result.success(接单成功); } if (order.getStatus() 0 targetStatus 5 order.getUserId().equals(operatorId)) { // 待接单 - 已取消只有下单用户才有权限取消 order.setStatus(5); orderMapper.updateStatus(orderId, 5); return Result.success(订单已取消); } // 其他状态流转... return Result.error(当前订单状态不支持该操作); }这种写法的好处是所有状态变更都经过同一个方法校验不会出现前端隐藏了按钮但接口还能调的逻辑漏洞。状态机的设计不仅体现在代码层也体现在前端页面用户端的订单列表根据状态显示不同的操作按钮。比如status0用户按钮是取消预约商家按钮是接单/拒单status2宠物已送达商家可以点击确认入住把状态推送到寄养中status3等预约结束日期到了商家操作确认离店到已完成。为了方便看板统计我还会在订单表里增加一个start_date和end_date字段用于计算寄养天数与营业额统计。这样管理后台就能很容易地按日期维度做订单收益分析。4.3 评价模块订单完成后的双向评价评价模块看上去简单但它非常考验对业务关系的理解。一个订单只能评价一次不能刷分不能重复评价这是必须保证的约束。我采用的是评价记录表 订单状态校验双重保障用户对已完成订单发起评价时后端先检查订单是否属于该用户再查评价表是否已有记录最后再做插入操作。由于评价表和订单表是多对一关系需要把order_id设置为唯一索引从根本上杜绝重复评价。评分字段我用tinyint类型取值范围限制在1到5。商家在查询自己的评分时通过AVG(score)实时计算即可。数据量大了以后再考虑加一个shop_score冗余字段做定时更新不过毕设阶段实时算就够了。4.4 商家入驻与管理后台审核商家端注册并不需要管理员手动开账号而是用户在小程序里申请成为寄养商家填写店铺名称、地址、联系方式、服务介绍和营业执照信息。这个申请记录先进入shop表的status0待审核状态管理员在后台看到后点击审核通过这个用户就自动拥有了商家角色同时可以把对应的服务项目数据补录进去。这里要说的一个细节是角色不是一个单独的字段就完了而是需要做权限控制的粒度区分。我的做法是用户表设计role字段1-普通用户2-商家3-管理员后端在Controller中通过角色拦截的方式控制接口访问。比如新增服务项目接口只允许role2的用户调用审核接口只允许role3的管理员调用。可以用自定义注解RequireRole(2)配合拦截器做简单且优雅。5. 部署上线与真机调试中常见的坑代码写完了本地自测没问题但并不代表项目就成功了。微信小程序有一个非常特殊的环节就是真机预览和部署这里的坑如果不提前知晓轻则演示时页面白屏重则直接被答辩老师看成无法运行的项目。5.1 合法域名的大坑与开发模式规避微信小程序的网络请求有一个严格的合法域名限制在真机预览和线上版本中wx.request的url必须配置在小程序后台的request合法域名中而且该域名必须是ICP备案过的HTTPS域名。这就意味着如果你只是本地起了个Tomcat拿http://localhost:8080或者http://192.168.x.x:8080接口地址在手机上跑请求会被直接拦截。解决方式有两种。第一种是开发模式下的临时方案在微信开发者工具右上角详情-本地设置勾选不校验合法域名、web-view业务域名、TLS版本以及HTTPS证书。这个方案只适用于开发者工具调试如果要在手机上真机预览也需要在真机调试模式下打开开发调试开关。第二种是正式方案买一台有公网IP的云服务器和域名注册备案后用Nginx做HTTPS反向代理把后端接口转发到Tomcat的8080端口并在小程序后台配置request合法域名。我建议毕设阶段优先使用第一种方案提前在本地把项目跑通、录好演示视频避免线上部署踩坑消耗大量时间。5.2 真机联调时的IP指向问题如果你确实需要在手机上真机预览用局域网IP访问后端接口还有另一个坑在代码里写死http://localhost:8080是最常见的错误。真机上localhost指向的是手机自身而不是电脑。正确写法是把后端接口地址写成电脑的局域网IP比如http://192.168.1.100:8080。同时后端Tomcat默认只监听了localhost需要修改server.xml中的Host配置或者直接把Connector的address设置为0.0.0.0才能允许局域网内其他设备访问。另外手机和电脑需要在同一WiFi下且Windows防火墙需要放行8080端口否则真机请求会超时。我之前遇到过项目代码完全没问题但一直连不上排查了半天发现是防火墙把入站规则拦了。5.3 数据库编码与Tomcat启动时的坑如果在环境配置阶段发现插入中文乱码第一反应应该是检查三处编码是否一致数据库连接URL比如jdbc:mysql://localhost:3306/pet_foster?useUnicodetruecharacterEncodingutf8数据库表本身的utf8mb4字符集以及Tomcat的server.xml中 Connector 配置URIEncodingUTF-8。这三处对齐了中文乱码基本不会出现。还有一个容易忽略的问题是MySQL8.x和旧版驱动类名的变化。MySQL5.x用的是com.mysql.jdbc.DriverMySQL8.x必须用com.mysql.cj.jdbc.Driver同时连接URL还需要加serverTimezoneAsia/Shanghai否则启动时报时区错误。很多同学从网上复制一段老教程的配置放到新环境里跑不通就是这个原因。5.4 一套稳妥的部署启动流程这里我整理一套看到很多次后总结的最稳妥的部署启动顺序初始化数据库用Navicat或命令行执行项目的init.sql确认所有表创建成功。启动MySQL服务并确认端口3306可以被连接。修改项目里的数据库连接配置文件jdbc.properties确认账号密码正确。将后端打成的war包放到Tomcat的webapps目录启动Tomcat。访问后端接口的Swagger/Knife4j文档地址如果有的话确认接口可访问。用微信开发者工具导入前端项目把接口地址改成实际后端地址勾选不校验合法域名。编译成功后可点击预览在手机上扫码体验。这套流程每一步都可以单独验证万一哪一步出问题排查范围能被缩到最小。很多人喜欢一次性把所有东西启动起来再挨个试这样一旦报错根本不知道是数据库、后端还是前端的问题效率反而更低。6. 项目做完之后还能往哪些方向扩展和深化如果核心功能已经稳定跑通还有富余时间我对这个项目还有几个方向的建议。这些方向不一定要全部实现但可以挑一两个来提升项目的加分感。第一个可选方向是引入Redis缓存。把寄养点的热门列表、公告信息等不经常变化的数据缓存到Redis后端接口响应速度会有明显提升。更重要的是这能体现出你对互联网高并发场景的理解哪怕项目本身没有高并发压力答辩时说说如果用户量涨上来哪些接口需要加缓存、哪些热点数据适合缓存也是一个很好的加分点。第二个方向是订阅消息推送。微信小程序支持主动给用户发送订阅消息前提是用户授权过该类型的订阅。在实际场景里订单状态变更商家接单、宠物入住、离店提醒是非常合适的推送时机。实现时把wx.requestSubscribeMessage的授权时机放在用户提交订单之前后端在状态变更时调用微信接口发送模板消息即可。这个功能体验感和技术含量都很不错。第三个方向是数据可视化统计。管理后台如果能把每日订单量、营业额、各类宠物寄养比例做成柱状图或饼状图项目整体观感会上升一个档次。前端可以用echarts的微信小程序版本后端写几个统计SQL数据量不大时性能完全够。第四个方向是多商户结算与佣金抽成。如果把这个寄养平台当作一个真正的商业产品商家入驻后平台方收取一定比例的中介佣金就需要设计一套结算账单体系。这个方向的复杂度会明显上升但在设计层面能体现你对业务闭环的思考深度。不过我也要提醒一句这些扩展方向的前提都是核心流程已经足够健壮。如果订单状态流转还会出现重复提交、取消后仍然被商家接单这类bug先把核心代码修稳再谈扩展。这个项目做到最后我最大的体会其实是宠物寄养平台表面上是一个典型的业务管理系统但真正让人头疼的往往不是某个单独的功能而是多个角色之间复杂的权限关系与状态流转。把需求分析表、状态机、接口约定这三样东西做好后端代码写起来会非常顺手。最后的最后一个建议就是一定要给自己留出至少三天时间做完整的联调、边界测试和演示流程演练因为真正让项目立住的从来不是某一个炫技的功能而是整个链路稳定、清晰、可复现。
返回列表