助学云 2.0 —— 从零搭一个公益小程序(一):项目介绍与架构设计

这个系列记录我做「助学云」这个微信小程序的完整过程,共四篇。这一篇先聊聊它是什么、为什么做、以及整体架构是怎么定下来的。 “吉林市助学志愿者协会自主开发的面向志愿者的小程序志愿平台「助学云加」。汇聚爱心力量,传递助学温情,让每一份善意精准抵达需要帮助的角落。” 一、背景 > 这个小程序最开始听到家里

这个系列记录我做「助学云」这个微信小程序的完整过程,共四篇。这一篇先聊聊它是什么、为什么做、以及整体架构是怎么定下来的。

“吉林市助学志愿者协会自主开发的面向志愿者的小程序志愿平台「助学云加」。汇聚爱心力量,传递助学温情,让每一份善意精准抵达需要帮助的角落。”

一、背景

> 这个小程序最开始听到家里提出的想法的时候呢,我为此也构思了好久,因为说真的,我还从来没有自己独立写过一个小程序,能做完这个项目,也要感谢协会的支持,小程序也马上就要发布了...

> 做这个数字化管理平台,我们也是为了把这个平台做的更规模化,在这之前,爱心超市的物资整理都要靠人工统计,小志愿者们的心愿也只能口头相传到大志愿者们的耳边,有些时候完成心愿的时候连张照片都没来得及拍下,协会的志愿者们为了维护这个家,也用了很多的心血,我想真正的为这个家做些什么,于是就有了这款小程序

> 做 1.0 的时候是为了先把功能跑通,代码写得比较随意,前端页面风格也不统一。2.0 这次属于从头重构:重新梳理了业务逻辑,统一了 UI 设计语言,后端也从零写了一套相对规范的 RESTful API。

二、这个平台做什么

核心功能有四块:

爱心超市——用户通过捐赠物资或参加活动赚取爱心值(积分),然后在爱心超市超市里兑换商品。管理员负责审核捐赠、评定积分,整个流程完全线上化。

活动招募——协会发布志愿服务活动,用户报名,管理员审批,审批通过后报名人数自动同步。参与活动也会计入志愿时长档案。

心愿树——这个功能是我比较喜欢的设计。学生(或管理员代为发布)在树上挂一个「心愿气泡」,志愿者认领后负责帮助实现。认领、完成都有图片凭证上传,有完整的状态流转。

后台管理——独立的管理端,包括用户管理、积分调整、物资审核、活动管理、心愿审核、反馈处理等,七个管理页面覆盖所有核心业务。

三、技术选型

选型的时候我的出发点比较简单:尽量用我熟悉的东西,同时保证能跑起来。

前端选 uni-app,原因是目标是微信小程序,uni-app 用 Vue 3 语法来写,上手很快。更重要的是,如果以后想扩展到支付宝小程序或者 H5,改动量很小。纯原生的微信小程序开发体验在组件复用和工程化方面差得多,我不想踩那个坑。

后端选 Spring Boot + MyBatis Plus,这是 Java 生态里最常见的组合,资料多、问题好查。MyBatis Plus 对比纯 MyBatis 省去了大量的 CRUD 样板代码,内置的逻辑删除、自动填充字段、分页插件这些功能刚好都用得上。认证方案选 JWT,无状态、简单,不用管 Session。

数据库选 MySQL 8.0,没什么特别的理由,就是最熟悉的。

部署用 Docker + 1Panel,这个后面单独一篇细说。

四、整体架构

用户手机

│ HTTPS

Nginx(1Panel 反向代理)

│ HTTP / Docker 内网

Spring Boot 容器(:8080)

│ JDBC

MySQL 容器(1Panel 管理)

前端编译成微信小程序包,通过微信官方渠道分发,所有请求打到我服务器上的 Nginx,Nginx 转发给后端容器。MySQL 也跑在容器里,后端和数据库在 Docker 的私有网络里互通,不暴露到公网。

五、项目结构

后端按标准的 Spring Boot 分层组织:

com.zhuxue/

├── controller/ # 接收请求、参数校验、返回响应

├── service/ # 业务逻辑、事务管理

├── mapper/ # MyBatis Plus 数据访问

├── entity/ # 数据库实体类

├── common/ # 公共工具(Result、JWT、异常等)

└── config/ # Spring 配置(MyBatis Plus、Web 拦截器等)

前端的结构相对扁平:

frontend/src/

├── api/ # 所有 API 调用方法,按业务域分组

├── utils/ # request.js 请求封装

├── styles/ # design-system.css 设计令牌

├── pages/ # 26 个页面(7 主页 + 7 管理 + 其他)

└── static/ # 图片、图标等静态资源

六、数据库设计思路

表的设计遵循几个统一的原则:

- 主键全部用 bigint AUTO_INCREMENT,简单可靠

- 每张表都有 created_atupdated_at 两个时间戳,由 MyBatis Plus 自动填充

- 软删除字段 deleted tinyint DEFAULT 0,数据不真删,查询时由 MyBatis Plus 自动过滤

- 状态字段用 MySQL ENUM 类型约束,防止脏数据进来

核心表有 14 张,最复杂的是状态机设计。以物资捐献为例:

`

submitted(已提交)

├─ received(管理员确认收到)

│ │

│ └─ evaluated(评定积分)→ points_returned(积分已发放)

└─ rejected(直接拒绝)

心愿树的状态流转:

pending_review(待审核)

├─ pending(审核通过,待认领)

│ │

│ └─ claimed(已被认领)→ completed(已完成)

└─ rejected(审核不通过)

每个状态的变更都在 AdminService 里做了边界检查,比如从 received 才能进到 evaluated,不允许跳跃,也不允许回退。

七、一个有意思的设计:积分流水表双职能

love_pool 这张表我设计的时候挺纠结的。它既要记录每次积分变动的明细(什么时候、为什么、加了多少),又要作为「爱心池」的汇总数据来源。

最后的方案是 points 字段用正负值区分收支:正数表示流入(捐赠物资获得积分),负数表示流出(兑换商品消耗积分)。这样一张表同时满足两个需求——查明细就全查,算爱心池总量就 SUM(points)

这个方案的好处是简单,不用两张表做关联。坏处是逻辑上有点隐晦points 字段的含义需要靠注释解释。如果规模更大,可能还是应该拆成两张表。

下一篇

下篇讲前端,重点会说 uni-app 的 request 封装、设计系统的建立,以及写了 26 个页面之后的一些感受。

LICENSED UNDER CC BY-NC-SA 4.0
评论