资讯动态

Spring Boot+微信小程序宠物领养平台全栈开发实战解析

发布时间:2026/10/19 16:15:53 来源:尧图企业网站定制
宠物领养平台这个题目在 Java 全栈项目里算是出现频率很高的类型了。我前后带过好几个版本从最早的 PC 端后台到后面配合微信小程序做前后端分离踩过的坑不算少。今天这篇文章就按最近一版“Java Spring Boot 微信小程序”的宠物领养平台为主线把从需求拆分、数据库设计、后端接口到小程序端联调、管理后台落地的完整思路讲透。如果你是正在做毕业设计或者想找个完整项目练手的开发者这篇建议花十分钟读完。先说说这个系统到底解决了什么问题。线下宠物领养的信息基本靠朋友圈转发、救助站门口贴告示信息分散领养人找靠谱渠道很费劲。宠物领养平台就是把宠物信息、领养申请、审核记录、留言沟通这几件事统一放到线上管理员发布待领养宠物用户刷宠物列表、看详情、提交领养申请管理员审核申请并更新宠物状态。流程不复杂但涉及多端、多角色、权限控制和状态流转作为全栈入门项目非常合适。1. 项目整体设计与方案选型1.1 先拆需求这个系统到底要做什么动手写代码之前一定要先想清楚系统里有谁、每个角色能干什么。宠物领养平台的核心角色就两个普通用户和管理员。用户端需要支持浏览宠物列表按分类、关键词筛选。查看宠物详情包括图片、年龄、性别、健康情况、救助故事。填写领养申请提交后可以在“我的申请”里看审核进度。收藏喜欢的宠物方便后面再回来看。在宠物详情页留言咨询。管理员端需要支持发布宠物信息包括上传图片、填写基础资料、上下架宠物。审核用户提交的领养申请通过或拒绝。维护用户列表必要时禁用异常账号。发布平台公告比如领养须知、回访通知。简单统计待领养数量、本月新增申请数等。这些功能拆完之后其实就是一个标准的资源管理型应用。宠物是核心资源用户围绕宠物做操作管理员对操作结果做审核。1.2 为什么选 Spring Boot 微信小程序这个组合是目前这类系统最主流的技术选型不是没有道理的。先说说为什么前端选微信小程序而不是 H5 或 App。领养这个场景非常依赖信任。小程序的入口在微信里用户扫码就能用不需要额外装 App对救助站来说传播成本最低。朋友圈、群聊、公众号文章里放一个小程序码用户点开就能看到待领养宠物这比让用户去应用商店下载一个 App 现实得多。另外微信小程序有官方的登录体系用户授权后就能拿到 openid不需要单独做手机号注册流程开发成本也低不少。后端选 Spring Boot主要看中它生态成熟、上手快。内置 Tomcat配合 MyBatis-Plus 之后基础 CRUD 几乎不用写 SQL而且单体部署非常省事本地一个 jar 包就能跑上服务器也只是把端口放出来。对于宠物领养平台这个体量的项目完全不需要引入 Spring Cloud 那套微服务架构单体应用加合理的模块划分就足够了。1.3 方案选型的几个注意点我见过不少人在技术选型上纠结这里直接给结论。小程序端用原生写还是用 uni-app如果项目只是跑在微信上原生小程序就够了逻辑清晰、文档多、出问题好排查。uni-app 的优势是一次编写多端发布但领养平台的用户群就在微信里没有多端需求引入 uni-app 反而是负担。后端要不要引入 Spring Security不要。微信小程序登录后后端只需要生成一个 token 返回给前端前端后续请求带上这个 token后端用一个拦截器校验就足够了。Spring Security 在这种场景下配置成本大于收益反而会把项目复杂度拉高。做这类项目的关键是逻辑清晰不是技术堆叠。数据库选择 MySQL 5.7 或 8.0 都行注意 8.0 的驱动名和 5.7 不同项目文档里会写清楚。2. 数据库设计与核心表结构2.1 实体关系先理清楚数据库是整个系统最底层的部分结构设计不好后面写代码会非常痛苦。宠物领养平台的实体关系可以这样梳理用户和领养申请是 1 对 N一个用户可以提交多条领养申请。宠物和领养申请是 1 对 N一只宠物可以被多条申请记录关联但只有一条申请会最终通过。用户和宠物通过收藏表构成多对多关系一个用户能收藏多只宠物一只宠物也能被多个用户收藏。用户和宠物通过留言表也构成多对多关系留言本质上是用户对宠物产生的行为记录。核心表就是用户表、宠物表、领养申请表、收藏表、留言表外加一个公告表。2.2 核心表结构设计建表语句按实际项目里的写法来我直接贴常用的版本。CREATE TABLE user ( id bigint(20) NOT NULL AUTO_INCREMENT, openid varchar(64) NOT NULL COMMENT 微信openid, nickname varchar(50) DEFAULT NULL COMMENT 昵称, avatar varchar(255) DEFAULT NULL COMMENT 头像, phone varchar(20) DEFAULT NULL COMMENT 手机号, status tinyint(4) DEFAULT 0 COMMENT 0正常 1禁用, create_time datetime DEFAULT NULL, PRIMARY KEY (id), UNIQUE KEY uk_openid (openid) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;用户表最关键的是 openid 字段它由微信官方生成一个微信号对应一个 openid是天然的唯一标识。手机号字段不是必填的可以在用户提交领养申请时再补充避免一进来就弹授权框被用户反感。CREATE TABLE pet ( id bigint(20) NOT NULL AUTO_INCREMENT, name varchar(50) DEFAULT NULL COMMENT 宠物昵称, category_id bigint(20) DEFAULT NULL COMMENT 分类id, breed varchar(50) DEFAULT NULL COMMENT 品种, age varchar(20) DEFAULT NULL COMMENT 年龄描述, gender tinyint(4) DEFAULT 0 COMMENT 0未知 1公 2母, health varchar(255) DEFAULT NULL COMMENT 健康状况, description text COMMENT 宠物描述, images varchar(1000) DEFAULT NULL COMMENT 图片地址逗号分隔, status tinyint(4) DEFAULT 0 COMMENT 0待领养 1申请中 2已领养 3下架, create_time datetime DEFAULT NULL, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;宠物表里有个 status 字段这个设计要重点说。很多第一次做的人会把宠物状态直接交给领养申请来判断比如查一下有没有通过的申请有就说明已领养。但这样每次展示宠物列表都要关联子查询性能差不说逻辑也绕。直接在宠物表维护一个状态值展示的时候取这个字段就够了状态流转放在事务里保证一致性。CREATE TABLE adoption ( id bigint(20) NOT NULL AUTO_INCREMENT, pet_id bigint(20) NOT NULL, user_id bigint(20) NOT NULL, apply_reason varchar(500) DEFAULT NULL COMMENT 申请理由, status tinyint(4) DEFAULT 0 COMMENT 0审核中 1已通过 2已拒绝 3已取消, remark varchar(255) DEFAULT NULL COMMENT 审核备注, create_time datetime DEFAULT NULL, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;申请表的 status 是审核流的核心。管理员驳回时可以在 remark 里写原因用户端能看到。收藏表和留言表结构就简单了。CREATE TABLE favorite ( id bigint(20) NOT NULL AUTO_INCREMENT, user_id bigint(20) NOT NULL, pet_id bigint(20) NOT NULL, create_time datetime DEFAULT NULL, PRIMARY KEY (id), UNIQUE KEY uk_user_pet (user_id, pet_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;收藏表要加唯一索引这样数据库层面就保证了一个用户只能收藏一只宠物一次代码里不需要额外查重。2.3 表设计的实操心得宠物图片用逗号分隔存字符串这是个偷懒但有效的做法。图片数量有限一般三五张不用为此单独建一张宠物图片表。取出来之后按逗号 split 成年数组小程序端轮播图直接绑定。所有表统一用 utf8mb4 编码不要用 utf8。utf8mb4 能存 emoji用户昵称和宠物描述里经常会出现用 utf8 会报 Incorrect string value 错误这个坑我踩过不止一次。公告表字段就标题、内容、创建时间不需要额外设计。3. 后端核心接口设计与实现3.1 项目分层与统一返回结构后端代码结构按 controller、service、mapper、entity、config、common 这几层分。controller 只做参数接收和结果返回业务逻辑全放 servicemapper 层用 MyBatis-Plus 的 BaseMapper 提交流程后基础 CRUD 不用写 SQL。统一返回结果这一步一定要做。不要每个接口自己拼 Map 返回不然前端对接的时候每个人拿到的结构都不一样联调效率极低。我习惯用这种方式public class ResultT { private Integer code; private String message; private T data; public static T ResultT success(T data) { ResultT result new Result(); result.setCode(200); result.setMessage(success); result.setData(data); return result; } public static T ResultT error(String message) { ResultT result new Result(); result.setCode(500); result.setMessage(message); return result; } }code 表示业务状态200 成功500 失败。前端统一先判断 code 再取 data逻辑一目了然。如果涉及未登录要加一个 401 的 code拦截器抛出后全局异常处理器转成 Result 返回。3.2 登录接口与 token 鉴权微信小程序登录流程是这样的小程序端调用 wx.login 拿到临时 code把 code 发给后端后端拿 code 加上 appid、secret 去微信接口换 openid。拿到 openid 之后查用户表没有就自动注册有就正常登录。最后后端生成一个 token 返回小程序小程序保存到本地 storage后续所有请求带上这个 token。后端生成 token 我用的是 UUID 加用户 id 拼接然后存到数据库的 token 表或 Redis 里。如果项目没有引入 Redis直接存一张 token 表也能用。不过我更建议用 Redis简单设置过期时间。生成逻辑大概这样String token UUID.randomUUID().toString().replace(-, ); redisTemplate.opsForValue().set(token: token, user.getId().toString(), 7, TimeUnit.DAYS);小程序请求头里带 token后端写一个拦截器统一校验。校验方式就是从请求头拿到 token去 Redis 查用户 id查不到就返回 401查到了把用户信息放到 ThreadLocal 里方便 service 层直接获取当前登录用户。这里有一个细节拦截器要放行登录接口和宠物列表、宠物详情这类公开接口只拦截领养申请、收藏、留言等需要登录的接口。放行列表在拦截器里写死或者配在配置文件里都行。3.3 宠物列表分页查询接口宠物列表是所有接口里最核心的一个。前端需要支持分类筛选、关键词搜索、分页加载。接口设计成这样的参数GET /api/pet/list?page1size10categoryId1keyword猫Service 层用 LambdaQueryWrapper 拼条件LambdaQueryWrapperPet wrapper new LambdaQueryWrapper(); if (categoryId ! null) { wrapper.eq(Pet::getCategoryId, categoryId); } if (StringUtils.hasText(keyword)) { wrapper.like(Pet::getName, keyword).or().like(Pet::getBreed, keyword); } wrapper.eq(Pet::getStatus, 0).orderByDesc(Pet::getCreateTime); PagePet page petMapper.selectPage(new Page(pageNum, pageSize), wrapper);注意 keyword 的匹配不要加在 status 条件后面用 and 连着因为 keyword 可能匹配 name 也可能匹配 breed需要用小括号把两个 like 括起来。LambdaQueryWrapper 里用 and 嵌套或者直接链式写多条件要注意这一点。分页返回要包含总条数和当前页数据列表前端做触底加载时自己判断还有没有下一页。MyBatis-Plus 的分页插件记得在 config 里配置不然 selectPage 不会真正分页这个坑很多新手会踩。3.4 领养申请与审核状态流转用户提交领养申请时后端要做两件事插入一条申请记录同时把宠物状态改成“申请中”。这两个操作必须在同一个事务里否则会出现申请记录有了但宠物状态没变用户重复提交的情况。Transactional public void applyAdoption(Long petId, String reason) { Pet pet petMapper.selectById(petId); if (pet null || pet.getStatus() ! 0) { throw new BusinessException(该宠物暂不可申请领养); } Adoption adoption new Adoption(); adoption.setPetId(petId); adoption.setUserId(currentUserId()); adoption.setApplyReason(reason); adoption.setStatus(0); adoptionMapper.insert(adoption); Pet update new Pet(); update.setId(petId); update.setStatus(1); petMapper.updateById(update); }管理员审核时也是两个操作更新申请状态、更新宠物状态。通过时申请变 1宠物变 2拒绝时申请变 2宠物变 0。同样要加事务。这块代码的核心是状态机的控制。不要在 controller 里随手改状态所有状态变更都走 service 层统一校验前置状态否则多人同时操作时数据会乱掉。4. 小程序端实现要点4.1 页面架构与导航设计小程序端的页面结构按照功能和 tabBar 来规划。底部导航一般是三个 tab首页、分类、我的。首页用来展示宠物列表和公告轮播分类页按宠物种类筛选我的页面放用户信息和功能入口。宠物详情页、领养申请页、我的申请列表、申请进度详情是二级页面从对应入口跳过去。app.json 里配置 tabBar 时图标可以用项目自带的图片也可以不配、只配文字都不会影响功能。页面文件的路径要注册准确这是小程序新手最常见的报错来源。4.2 微信登录与 token 管理小程序端登录逻辑我一般放在首页 onLoad 时触发。wx.login 拿 code然后 wx.request 把 code 发给后端登录接口。后端返回 token 之后wx.setStorageSync(token, token) 存起来。后续请求从 storage 里取 token 放到 header 的 Authorization 字段。wx.login({ success: (res) { wx.request({ url: http://localhost:8080/api/user/login, method: POST, data: { code: res.code }, success: (response) { if (response.data.code 200) { wx.setStorageSync(token, response.data.data.token); } } }); } });写这几个接口时我建议把 wx.request 封装成一个公共方法。统一处理请求头、token 过期跳转、错误提示。不然每个页面都写一遍 wx.request代码会非常冗余。封装之后页面里的调用就简单了。4.3 列表加载与下拉刷新宠物列表要考虑用户刷新的场景。下拉刷新用页面自带的 enablePullDownRefresh触底加载用 onReachBottom 生命周期。加载的逻辑就是维护一个 pageNum第一次加载是 1触底时 pageNum 加 1请求下一页。服务端返回的数据里如果没有 more 字段就停止加载。首页列表请求要带分类参数和关键词参数。用户点击分类 tab 或者搜索时重置 pageNum 为 1清空数组再加载。交互上要给一个空的提示不然用户看到白屏会怀疑出 bug 了。4.4 领养申请表单与状态回显领养申请页就是一个表单字段包括联系人、手机号、住址、申请理由、是否养过宠物。表单提交前要做非空校验手机号要验证 11 位。提交成功后跳转到“我的申请”页面。“我的申请”页面展示当前用户提交的所有申请记录每条记录显示宠物名称、申请时间、审核状态。审核状态用文字显示比用数字好后端返回的是 0、1、2前端映射成“审核中”“已通过”“已拒绝”。这里有个体验细节用户在提交申请后会想反复确认“到底通过没有”。所以在详情页可以加一个状态刷新按钮或者简单点下拉刷新页面时重新请求接口就行。5. 管理后台的功能落地5.1 后台技术选型管理后台我用的方案是服务端模板渲染HTML 加 CSS 框架加 jQuery。为什么不用 Vue 再做一套前后端分离因为领养平台后台只有管理员一个人用功能也就是增删改查用模板渲染开发效率最高不需要额外搭建前端工程。常见的 admin 模板选一个就行重点是把功能做完整不是把架构做得花哨。后台和用户端共用同一个后端服务。后台接口直接用传统的方式管理员登录后把用户信息存在 session 里访问后台页面时用拦截器判断是否有 session。这个方法虽然老但在这种小规模后台里是最好用的。5.2 宠物管理与图片上传后台的宠物管理页面是核心。表格展示宠物列表提供新增、编辑、删除、上下架操作。新增和编辑共用同一个表单页面按 id 判断是新增还是修改。图片上传这块有几个容易出问题的地方。后台表单里用了文件选择框提交时用 multipart 格式上传。后端接收后把文件保存到服务器的一个目录里同时做静态资源映射让图片可以通过 URL 直接访问。文件名一定要重命名用 UUID 加后缀不然两个用户上传相同名字的图片时后一个会覆盖前一个。String originalFilename file.getOriginalFilename(); String ext originalFilename.substring(originalFilename.lastIndexOf(.)); String filename UUID.randomUUID().toString().replace(-, ) ext; file.transferTo(new File(uploadDir filename));上传后返回的文件访问地址要拼接完整路径。这里有一个常见坑本地开发时图片访问地址是 localhost小程序端调试时可以访问但上线后小程序必须用 HTTPS 域名图片地址也得跟着变成线上域名。5.3 领养审核操作后台的领养审核页面展示所有申请记录列表里要关联查询出宠物名称和申请人昵称方便管理员快速判断。每条记录后面放“通过”和“拒绝”两个按钮。点击通过时请求审核接口传入申请 id 和审核结果。拒绝时弹一个输入框让管理员填拒绝理由这个理由用户端会看到。审核列表的查询要配置分页申请记录多了之后不分页页面会卡。状态可以筛选默认显示待审核的记录管理员处理完一条就换下一条操作效率是最高的。6. 运行部署与常见问题排查6.1 本地运行完整流程拿到源码后本地跑起来的步骤如下创建数据库导入项目里的 sql 文件。修改 application.yml 里的数据库用户名密码。启动后端 Spring Boot 的 main 方法。用微信开发者工具导入小程序项目修改 request 请求域名配置。后端端口和管理后台页面的访问地址按文档配置。这里第一天跑项目的同学最容易卡在第 4 步。本地调试时小程序必须在开发者工具的“详情-本地设置”里勾选“不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书”否则请求 http://localhost 会被拦截报 request:fail。6.2 常见报错排查速查表我整理了一份高频问题排查表都是实际项目中遇到过的现象可能原因解决办法小程序请求报 request:fail没有勾选不校验合法域名本地设置里勾选或用 HTTPS 域名后端接口返回 404请求路径不对或服务未启动检查控制台日志确认路径和端口图片显示不出来静态资源映射没配置检查资源映射目录和文件是否存在登录后 token 失效Redis 里 key 过期或 token 没存检查 Redis 配置检查 storage key数据库连接失败密码错误或 MySQL 未启动检查配置文件在命令行测试连接中文乱码数据库连接串缺编码参数在 JDBC URL 加 characterEncodingutf8其中图片不显示这个问题值得多说一句。后端做了静态资源映射后访问路径一般是 /upload/xxx.jpg。如果通过浏览器直接访问这个地址能显示但小程序里不显示大概率是用了 HTTP 协议而微信开发者工具的正常校验模式下限制非 HTTPS 请求。本地调试时可以勾选不校验解决上线时用 HTTPS 域名解决。6.3 上线部署的几个注意事项项目部署到云服务器时有几个事情要提前想好。首先是 HTTPS微信小程序的正式环境要求所有请求域名必须是 HTTPS并且要在小程序后台配置合法域名。没有 HTTPS 的小程序接口是调不通的。其次是图片存储的位置。本地磁盘存储对小项目够用但要注意磁盘空间和备份。更推荐的做法是使用云存储服务后端把图片上传后拿到 URL 存储。如果你用的是本地磁盘记得把上传目录挂在服务器的数据盘上避免系统盘被写满导致服务异常。最后一个容易忽略的是 Nginx 反向代理。后端服务建议只监听内网端口对外统一走 Nginx 的 HTTPS 端口然后用 location 规则把 /api 开头的请求转发给 Spring Boot/upload 开头的请求映射到图片目录。这样安全很多也不会把后端端口直接暴露到公网上。我个人在项目实操里还有一个体会宠物领养平台的业务逻辑不复杂但状态一致性很容易写崩。申请领养和审核这两块一定要记得加事务最好再加一个乐观锁或者数据库层面的状态校验防止两个管理员同时操作同一只宠物导致数据错乱。多做几次并发请求测试比后期上线后发现问题再修要省心得多。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑