1. 项目概述与需求分析
1.1 核心需求解析
打开这个标题,第一反应是:寺庙捐赠系统,本质上是一个带有公益属性的移动端应用。很多人一听"捐赠"就觉得是单纯的付款功能,实际上这类项目在毕业设计里要比普通的商城类、新闻类APP复杂得多,因为它既要处理资金流,又要兼顾宗教文化场景下的用户体验,还有一套完整的管理后台。
"五台山寺庙捐赠系统"这个定位很有意思,它不是泛泛的"寺庙管理系统",而是聚焦在捐赠场景上。这意味着系统设计时要考虑:游客/信众能浏览寺庙信息、查看功德项目、在线完成捐赠、获得捐赠凭证;寺庙管理员能发布功德项目、查看捐赠记录、统计善款;系统管理员则要维护用户、寺庙、项目等基础数据。
从毕设答辩的角度看,这个题目有个天然优势:业务场景清晰,功能边界明确,评委一眼就能知道这个系统是干什么的。不像那种"智能XX平台"听着高大上但说不清业务闭环的题目,捐赠系统的需求是能一条条列出来的。我把这类项目拆解过不少,做得好不好,关键就看功德项目、捐赠流程、记录管理这三条主线是否闭环。只要这三条线走通,功能上基本就能站住脚。
1.2 目标用户与核心功能池
既然定位是毕业设计,首先要考虑的是"这个系统做出来给谁用"。我建议从三个角色出发:
- 游客/信众(APP端用户):注册登录、浏览寺庙信息、查看功德项目(如供奉香油、修缮殿堂、助印经书等)、在线捐赠、查看个人捐赠记录、获取电子捐赠凭证。
- 寺庙管理员(Web端或APP端):管理本寺庙的基本信息、发布功德项目、查看本寺庙捐赠流水、导出统计报表、处理捐赠订单状态。
- 系统管理员:管理寺庙入驻申请、审核功德项目、管理平台用户、查看全平台捐赠汇总数据。
这里要说一个很多毕设新手容易犯的错:一上来就把用户端和管理端全部塞进同一个APP里。对于这个项目,我强烈建议APP端只做用户侧功能,管理端用Web页面实现(比如用Vue写一个独立后台),或者至少把管理功能和用户功能在APP内用不同入口严格隔开。原因后面会在技术选型里细说。
核心功能池梳理下来大概是这样的表:
| 功能模块 | 子功能 | 实现要点 |
|---|---|---|
| 用户中心 | 注册、登录、个人信息维护 | 手机号+验证码或账号密码,Token鉴权 |
| 寺庙展示 | 寺庙列表、寺庙详情、图文介绍 | 列表分页加载,详情页图片轮播 |
| 功德项目 | 项目列表、项目详情 | 捐赠目标金额、已捐金额进度条展示 |
| 在线捐赠 | 金额输入、支付方式选择、捐赠确认 | 捐赠单生成、支付成功后回调更新 |
| 订单管理 | 我的捐赠、捐赠详情、电子凭证 | 以订单状态为核心,关联支付流水 |
| 管理后台 | 寺庙管理、项目管理、用户管理、数据统计 | 独立管理页面,权限控制 |
这张表基本就是系统的功能骨架了。我在做方案设计时,习惯先画这样一张表给团队或者答辩老师看,比一上来就贴代码高效得多。
2. 技术选型与系统架构
2.1 为什么选Android原生而非小程序
这里有个非常现实的考量:毕设项目要的是"功能完整、技术有亮点、能落地演示"。微信小程序确实开发快,但很多学校对毕设的"APP"有硬性要求,而且小程序在支付环节需要企业资质,个人开发者根本走不通真实的支付流程。如果你还在选型阶段,我的建议是优先考虑Android原生,理由有三个:
第一,Android原生App在课堂演示和答辩环节效果最好——你可以直接把APK安装文件装到模拟器或真机上,打开就是独立的应用环境,不用依赖微信开发者工具,评委看到的是一个完整的应用形态。第二,Android开发涉及Activity、Fragment、网络请求、数据库缓存等知识,技术覆盖面广,符合毕设对"技术含量"的评分要求。第三,支付环节你可以对接支付宝沙箱环境或者模拟支付流程,不需要真实商户资质,数据闭环照样能打通。
如果是iOS端,发布证书、开发者账号这些门槛对在校生不友好,而且Windows电脑没法直接跑Xcode,实验室和机房环境很难统一。所以结论很明确:技术栈用Android原生(Java或Kotlin) + Spring Boot后端 + MySQL数据库,这个组合最稳。
2.2 整体架构与通信链路
系统整体采用前后端分离的结构。Android端通过网络请求访问后端接口,后端连接MySQL数据库读写数据。通信协议用RESTful风格的JSON,后端框架我用的是Spring Boot,它内置了Tomcat,打包成jar直接就能跑,不需要额外配置外部服务器。
数据库端我习惯用MyBatis-Plus作为ORM框架,它对单表操作的封装很友好,毕设阶段不用写复杂的XML映射,BaseMapper里已经自带增删改查。如果数据库使用MySQL 8.x版本,记得Connector/J驱动要配对应的,这是新手经常踩的坑。
架构上建议再加一层Redis做缓存,但如果你对Redis还不熟,这一层也可以先不引入。我从实际经验出发,毕设阶段把Android + Spring Boot + MySQL这条路彻底打通就很能打了,Redis属于加分项,时间充裕再加。
2.3 源码包结构规划
拿到源码后,首先看清目录结构。一套规范的毕设源码应该是这种分部方式:
FiveTerracesDonation/ ├── android-app/ # Android客户端工程 │ ├── app/ │ │ ├── src/main/java/com/example/donation/ │ │ │ ├── activity/ # Activity页面 │ │ │ ├── adapter/ # RecyclerView适配器 │ │ │ ├── entity/ # 实体类 │ │ │ ├── network/ # 网络请求封装 │ │ │ └── utils/ # 工具类 │ │ └── src/main/res/ # 布局与资源文件 ├── server/ # 后端服务工程 │ ├── src/main/java/com/example/donation/ │ │ ├── controller/ # 接口控制层 │ │ ├── service/ # 业务逻辑层 │ │ ├── mapper/ # 数据库映射层 │ │ └── entity/ # 数据库实体 │ ├── src/main/resources/ │ │ ├── application.yml │ │ └── mapper/ # MyBatis的XML文件 │ └── pom.xml ├── database/ # SQL脚本 │ └── five_donations.sql └── README.md # 部署说明文档拿到源码后第一件事不是急着运行,而是先打开README和SQL脚本,看清数据库初始化和启动步骤。很多源码不好跑起来,不是因为代码错了,而是环境版本对不上,这个我后面会详细说。
3. 数据库设计与核心模块实现
3.1 数据表设计与关系梳理
对于捐赠系统,数据库设计是整个项目的基座。表少了业务撑不起来,表多了又显得冗余。我设计的核心表一共六张:
用户表(t_user):字段包括user_id(主键)、username、password(记得存MD5或BCrypt加密后的密文,千万别存明文)、phone、avatar、create_time。用户表是整个系统的入口,捐赠订单要关联它。
寺庙表(t_temple):temple_id、temple_name、description、location、cover_image、status(0下架/1上架)。寺庙管理员创建账号时绑定temple_id,这样他只能管理自己的寺庙。
功德项目表(t_project):project_id、temple_id(关联寺庙)、project_name、description、target_amount、donated_amount、status。这里有个关键字段是donated_amount,每次捐赠成功要更新这个累计值,前端通过它计算进度百分比。
捐赠订单表(t_donation):donation_id、order_no(生成唯一订单号)、user_id、project_id、amount、status(0待支付/1已支付/2已取消)、pay_time、create_time。订单表是整个系统的核心表,所有资金相关的查询都围绕它展开。
捐赠凭证表(t_certificate):certificate_id、donation_id(关联订单)、certificate_no、create_time。用户支付完成后系统生成一张电子凭证,包含证书编号、捐赠人、金额、项目信息。
管理员表(t_admin):admin_id、username、password、temple_id(关联寺庙,系统管理员此字段为空)、role(0系统管理员/1寺庙管理员)。
表之间关系用一句话概括:用户对订单是一对多,寺庙对功德项目是一对多,项目和订单是一对多,订单和凭证是一对一。这六张表把业务闭环完整串起来了。SQL脚本里除了建表语句,建议把外键关系也写明,答辩时老师如果问起数据完整性,可以直接演示。
3.2 捐赠流程的状态机设计
在线捐赠是系统最核心的流程,它的状态流转一定要清晰。我这里的捐赠流程是这样设计的:
用户浏览项目详情页,点击"我要捐赠"按钮,输入金额后点击确认支付。此时后端先生成一个待支付状态的订单,订单号用时间戳加随机数生成,确保唯一。然后APP端调起支付页面——毕设阶段有两种做法,一种对接支付宝沙箱,一种直接做一个模拟支付的弹窗。我建议新手直接用模拟支付,因为支付宝沙箱需要下载单独的钱包APP,在模拟器上不一定方便演示,反而会卡住。
模拟支付页面里放一个"确认支付"按钮,点击后调用后端"模拟支付成功"的接口。这个接口做的事包括:把订单状态改成已支付、更新项目的donated_amount字段、生成一条捐赠凭证记录、返回用户一个凭证编号。到这里,一条完整的捐赠链路就走通了。
这里需要强调一个细节:为什么订单要先生成再支付,而不是支付成功后再生成订单?这是实际项目里防重逻辑的经典设计。如果只生成订单不支付,用户大可以取消,状态可控;如果先把钱扣了再生成订单,万一订单生成失败,钱就"飞"了。先订单后支付,后面的状态全靠订单状态字段驱动,即使用户支付到一半退出,订单也只是一个待支付状态,过段时间过期即可。
3.3 核心接口清单
后端接口是Android端和Web管理端共同调用的桥梁。我整理一下这个系统需要提供的主要接口:
| 接口路径 | 方法 | 说明 | 请求参数 |
|---|---|---|---|
| /api/user/register | POST | 用户注册 | username, password, phone |
| /api/user/login | POST | 用户登录,返回Token | username, password |
| /api/temple/list | GET | 寺庙列表(分页) | page, size |
| /api/temple/detail | GET | 寺庙详情 | templeId |
| /api/project/list | GET | 功德项目列表 | templeId, page, size |
| /api/project/detail | GET | 项目详情 | projectId |
| /api/donation/create | POST | 创建捐赠订单 | userId, projectId, amount |
| /api/donation/pay | POST | 模拟支付成功 | orderNo |
| /api/donation/my | GET | 我的捐赠记录 | userId |
| /api/certificate/detail | GET | 凭证详情 | certificateNo |
| /api/admin/project/add | POST | 发布功德项目 | templeId, projectName... |
| /api/admin/donation/list | GET | 本寺庙捐赠流水 | templeId, page |
接口列表列出来后,前后端开发就可以并行推进了。Android端用自己的Mock数据或者直接调后端的Swagger调试页面,管理端也可以同步开发,互不阻塞。Spring Boot引入springfox-swagger2依赖后,启动项目访问/swagger-ui.html就能看到接口文档,建议加上,答辩时直接演示接口调试也是加分项。
4. 实操过程与关键功能实现
4.1 Android端——从页面搭建到数据填充
Android端我采用的是经典的MVC模式:Activity负责页面交互,Adapter负责列表数据绑定,网络层用OkHttp封装工具类。页面结构按底部导航拆成四个Tab:首页、寺庙、功德、我的。
首页放轮播图和推荐寺庙,数据从/temple/list接口拉取,可以用一个横向滑动的RecyclerView来展示。寺庙页是一个纵向列表,每个item展示寺庙封面图、名称、简介,点击进入寺庙详情页,详情页下方会展示这个寺庙下的功德项目列表。功德页是所有上架项目的聚合流,这个页面直接面向捐赠入口,卡片设计上要突出进度条和"已捐XX元",让用户一眼看出参与度。我的页包含个人资料入口、我的捐赠列表、我的凭证。
这里要提一下网络请求封装。建议用OkHttp加Retrofit的组合,或者只用OkHttp自己封装一个简单的工具类,核心是把baseUrl和Token请求头统一管理。Token从登录接口拿回来后存SharedPreferences,后续所有请求都在拦截器里自动带上。如果只用OkHttp不用Retrofit,接口解析JSON的工作量会大一点,但好处是你能看到每一步底层原理,答辩时被问到底层实现也不慌。
页面状态管理也要注意:列表页要有一个加载中状态、空状态、失败重试状态。很多毕设APP一进入页面就是白屏直到数据出来,体验很不好。我通常会在布局里加一个ViewStub或者用MultiStateView这样的开源库来管理,简单点说就是数据没回来时显示一个ProgressBar,返回空列表时显示"暂无数据",请求失败时显示"加载失败,点击重试"。
4.2 后端核心代码——捐赠接口的实现逻辑
后端接口的编写顺序也很重要。先搭好Spring Boot项目骨架,引入Web、MyBatis-Plus、MySQL驱动、Lombok依赖。然后按"实体类 → Mapper → Service → Controller"的顺序一层层写。这里我把创建捐赠订单的核心Service代码逻辑讲一下,这段代码是整个系统的心脏。
创建订单时要做三步:校验项目是否存在且上架、校验金额是否在合理范围(比如大于0且小于单笔限额)、生成订单号并插入数据库。订单号我用的规则是:时间戳(14位)+ 用户ID后四位 + 四位随机数,这样既保证了唯一性,排查问题时也能从订单号里反推出用户和大致时间。
模拟支付成功接口的逻辑是事务性的:从数据库查出待支付订单,把状态改为已支付,同步更新项目表里的donated_amount字段,插入一条凭证记录。这几步操作必须在同一个事务里,否则就会出现"订单已支付但项目金额没变"这种数据不一致问题。Spring Boot里只要在Service方法上标注@Transactional注解就搞定。
代码层面的提示:MyBatis-Plus的UpdateWrapper在更新donated_amount时要用数学表达式setSql("donated_amount = donated_amount + " + amount),不要在Java端先查出来加完再写回。原因很简单:如果并发下两个请求同时读到同一个捐赠额,各加各的,后写回的会覆盖先写回的,数据就丢了。用SQL自带的加法在数据库层面执行才是安全的。
4.3 管理后台——数据看板的简易实现
管理后台不需要做得很花哨,但必须功能直观。我用Vue Element-UI搭的独立页面,主要三个模块:
项目管理:寺庙管理员登录后进入项目列表,支持新增功德项目、编辑项目信息、上架/下架操作。新增项目时要填名称、目标金额、项目说明,封面图上传到服务器本地目录,数据库存图片URL。这里有个小坑:图片上传接口要通过MultipartFile接收文件,Spring Boot的spring.servlet.multipart.max-file-size默认只有1MB,毕设项目传几张寺庙照片很容易超限,要在application.yml里把这个值调大,比如10MB。
捐赠记录:按时间倒序展示本寺庙全部捐赠订单,支持按状态筛选(全部/已支付/待支付),支持按日期范围查询。这条列表查询SQL会用到大屏统计的基础数据。导出功能建议直接用POI写一个简单的Excel导出接口,答辩时点一下"导出报表"生成一个Excel文件,比口头解释有说服力得多。
数据统计:展示捐赠总金额、今日新增捐赠、热门项目TOP5、最近7天捐赠趋势。趋势图可以引入ECharts的折线图组件,数据接口按天聚合返回"日期+总额"的JSON数组。这块虽然实现不难,但整体对视觉观感提升极大。
4.4 部署演示环境准备
为了让答辩演示不出幺蛾子,环境准备有几点实操经验:
后端直接打成jar包运行。Windows环境装JDK1.8或11,MySQL装5.7或8.0,启动时把jar包在命令行里跑起来就行。需要注意的是端口冲突问题,Spring Boot默认8080端口,如果你的机器上其他项目占用了,在application.yml里改掉就行。数据库连接URL里的时区参数要配serverTimezone=Asia/Shanghai,否则报错"Unknown Time Zone"。
Android端用Android Studio打开工程,同步Gradle依赖后,修改network包里的baseUrl,把你电脑的局域网IP填进去,比如http://192.168.1.100:8080。这里有个大坑:模拟器访问宿主机不能用localhost,Android模拟器里localhost指向的是模拟器自己,要用10.0.2.2代替;真机调试则必须用电脑的局域网IP。很多同学Demo连不上后端,八成就是栽在这个地址问题上。另外用了HTTP明文请求的话,Android 9及以上默认禁止,需要在AndroidManifest.xml里配置android:usesCleartextTraffic="true"。
5. 常见问题与排查技巧实录
5.1 启动报错速查表
毕设做完了不代表就万事大吉,从代码到演示还有一段路要走。我把带过的学生和自己在开发中踩过的坑整理成一张速查表,你遇到问题时直接按图索骥:
| 症状 | 可能原因 | 解决方案 |
|---|---|---|
| 前端请求后端超时 | baseUrl填了localhost | 模拟器改10.0.2.2,真机改局域网IP |
| 后端启动报时区错误 | MySQL连接串未配时区 | URL加serverTimezone=Asia/Shanghai |
| Android请求被拒绝 | 9.0+禁止明文HTTP | Manifest配置usesCleartextTraffic="true" |
| 图片上传失败 | Spring Boot上传大小限制 | yml里将multipart max-file-size调大 |
| 数据库中文乱码 | 字符集未统一 | 建库时用utf8mb4,连接串加characterEncoding=utf8 |
| 列表数据刷新不出来 | RecyclerView未调用notifyDataSetChanged | 数据返回后需主动刷新适配器 |
| 捐赠后金额没变 | 更新语句未在事务内执行 | Service方法加@Transactional注解 |
| 端口被占用 | 其他进程占了8080 | 改用其他端口或在yml中修改 |
5.2 线上演示的三条铁律
最后说一说答辩演示时最容易翻车的三个操作点,这些是我经历过或亲眼见过的教训。
第一,演示前先启动后端,再打开APP。很多同学喜欢在评委面前打开Android Studio运行,此时Gradle编译往往要卡两分钟,现场气氛冷掉一大半。正确的做法是:提前把后端jar包在后台跑起来,把APP装到真机或模拟器上,一切就绪后让APP处于登录前的首页状态,评委来了直接开始演示。
第二,备一个纯数据演示账号。提前注册一个"演示用户",里面放几条捐赠记录、一张已支付的凭证、几个项目数据。否则现场从注册开始演示,又要输验证码(如果接了短信平台)又要跳转,任何一个环节出问题都会很尴尬。用已有账号直接打开"我的捐赠"页面,一屏截图就能把核心功能全展示完。
第三,支付环节用明确的"模拟支付"字样。虽然大家心知肚明是毕设,但如果你在演示时把这个说成"真实支付宝支付",懂行的评委追问商户资质、回调签名验证、风控逻辑,你就没法接话了。坦白说"这里对接的是沙箱环境/模拟支付流程,核心的订单状态流转是完整的",反而显得你清楚边界、知道真实生产环境的复杂度。这种坦诚在答辩中是加分行为。
5.3 可以继续扩展的方向
这个系统的完整度作为毕设来说已经足够,但如果你想让项目更有竞争力,还有三个方向可以参考。
第一个是增加捐赠证书分享功能。支付完成后生成一张带有寺庙水印的图片分享卡片,用户保存到相册或分享到社交平台。这在实际产品中是很常见的一环,也顺手把系统的传播性体现出来了。实现上就是Canvas画图加文字,不算难。
第二个是引入微信小程序端。现在很多寺庙的实际场景里,信众扫二维码就能随手供养,微信小程序反而是更真实的形态。Android端做完整功能,小程序端做轻量捐赠入口,一套后端两套前端,这个搭配在简历上很有说服力。
第三个是对接真实微信支付/支付宝支付。毕设阶段不强制,但如果想真正上线体验一把,可以用个人资质申请当面付接口或者沙箱环境走通完整流程。注意这一步需要企业资质的是核心接口,个人申请受限,所以很多时候只能走沙箱,能做到也够写在简历上了。
我自己在做这类有公益属性的系统时最大的体会是:业务逻辑一定要闭环,哪怕技术再简单,只要"注册 → 浏览 → 捐赠 → 凭证 → 查看记录"这一条链路是通顺的,这个项目就是完整的。反而很多同学想加各种花哨功能,最后链路断裂,每个模块都是半成品。先保证主轴顺畅,再考虑延展,这才是做项目的正确顺序。这套"寺庙捐赠系统"的整体思路,换到公益募捐、乡村助学、校友捐赠等场景也完全适用,思路是共通的。