ARTICLE DETAIL

资讯详情

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

基于SSM+微信小程序的家庭记账本系统:从数据库设计到前后端联调实战

基于SSM+微信小程序的家庭记账本系统:从数据库设计到前后端联调实战 简介这是一套面向计算机专业本科生的高分毕业设计级家庭记账系统融合Java后端开发与微信小程序前端解决家庭财务数字化管理痛点适用于毕设答辩、课程设计及期末大作业实战。资源包共775个文件涵盖90个Java核心业务类、123个Vue与WXML/WXSS小程序页面组件、75个JS交互逻辑、40个JSON配置及1个完整MySQL建库脚本SQL辅以SVG图标、PNG素材与Bootstrap等UI资源整体压缩包68.44MB结构清晰、模块分明含install/run/build三步部署脚本及详细文档。已有93人学习下载提供开箱即用的完整工程前后端源码、可一键导入的数据库、论文文档、Navicat与IDEA环境配置说明所有功能经严格调试——从用户注册登录、收支录入查询到数据统计图表与PDF报表生成均能稳定运行无需二次修改即可部署演示。1. 项目概述与核心价值最近几年身边不少学弟学妹和转行的朋友都在为毕业设计或者第一个能拿得出手的实战项目发愁。大家的需求很明确技术栈要主流、功能要完整、业务要贴近生活、代码结构要清晰最好还能直接运行起来作为面试时的谈资。翻看很多开源项目要么过于简单像个玩具要么架构复杂得像座迷宫新手根本无从下手。而这个“家庭记账本系统”恰恰踩中了这些痛点。它不是一个冷冰冰的“学生信息管理系统”或者“图书管理系统”而是每个人、每个家庭都可能真实使用的工具业务逻辑亲切理解成本低。更重要的是它采用了非常经典且市场需求旺盛的技术组合Java后端、SSM框架、MySQL数据库以及前端当红炸子鸡——微信小程序。这套组合拳打下来不仅覆盖了企业级应用开发的核心技术点还紧跟了移动互联网的应用形态可以说是一个为“高分毕业设计”和“技能入门实战”量身定做的样板工程。这个项目的核心价值在于它的“完整性”和“教学性”。它不仅仅是一堆源码的压缩包更是一个完整的、可运行的系统案例。从后端的MVC分层、数据库表设计、接口编写到前端的页面布局、组件交互、数据绑定再到前后端如何通过JSON进行通信整个开发链路清晰可见。对于学习者而言研究这样一个项目远比孤立地学习某个框架或语法有效得多。你能看到Spring如何管理BeanMyBatis如何优雅地进行数据库操作微信小程序如何发起网络请求并渲染数据这些知识在真实的项目上下文中被串联起来形成了深刻的理解。接下来我将为你深度拆解这个项目的设计思路、技术实现细节以及那些在开发中容易踩坑的地方希望能为你复现或借鉴这个项目提供一份清晰的“地图”。2. 技术栈选型与架构设计解析2.1 为什么是JavaSSMMySQL微信小程序选择一套技术栈背后是成本、效率、生态和未来扩展性的综合考量。这个项目的选型可以说是经过市场检验的“黄金组合”。后端Java SSM框架Java作为企业级开发的中流砥柱其稳定性、跨平台性和庞大的生态圈是无可替代的。对于毕业设计或中小型项目SpringSpringMVCMyBatisSSM框架组合是绝佳选择。Spring的核心是IoC控制反转和AOP面向切面编程它像一个超级粘合剂管理着项目中所有的对象Bean和它们之间的依赖关系。这意味着你的代码耦合度更低更容易测试和维护。SpringMVC则优雅地处理了Web请求的分发、参数绑定和视图解析让控制器Controller的编写变得清晰规整。MyBatis是一个半自动化的ORM框架它没有Hibernate那样全自动映射的“厚重感”却给了开发者对SQL极大的控制权。你可以编写高度优化的SQL语句同时又能享受到将结果集自动映射到Java对象的便利。这种“平衡感”对于需要精细控制数据库操作的项目如涉及复杂统计查询的记账系统尤为重要。数据库MySQLMySQL是开源关系型数据库的标杆其安装简单、使用广泛、社区活跃并且完全免费。对于家庭记账这类数据关系明确用户、账户、账单、分类等、事务性要求强的应用关系型数据库是天然的选择。MySQL的性能足以支撑个人乃至家庭级别的数据量其ACID特性保证了记账数据如转账、消费记录的准确性和一致性。此外像phpMyAdmin这样的图形化管理工具也让数据库的日常维护和调试变得非常友好。前端微信小程序微信小程序的优势在于其巨大的用户入口和便捷的体验。用户无需下载安装扫一扫或搜一下即可打开应用这极大地降低了使用门槛非常适合记账这种高频、轻量级的工具型应用。小程序的开发框架如WXML、WXSS、JavaScript学习曲线相对平缓且提供了丰富的原生组件和API如网络请求、本地存储、用户授权等能快速构建出体验良好的界面。对于开发者而言一次开发可以覆盖微信内的海量用户其传播和分享的便利性也是原生App难以比拟的。这套架构形成了一个典型的前后端分离模式微信小程序作为客户端负责UI展示和用户交互Java后端作为服务端提供RESTful API处理业务逻辑和数据持久化MySQL作为数据存储层。它们之间通过HTTP/HTTPS协议进行JSON格式的数据交换职责清晰便于独立开发和部署。2.2 系统核心模块与功能设计思路一个完整的家庭记账本远不止是“记一笔账”那么简单。它需要围绕“家庭”这个核心场景设计出一套贴合实际使用习惯的功能体系。通常系统会包含以下几个核心模块用户与家庭管理模块这是系统的基础。支持微信一键登录获取用户唯一标识OpenID。一个用户可以创建或加入一个家庭一个家庭包含多个成员。这里涉及到家庭邀请码、成员角色如管理员、普通成员等设计。账本与账户管理模块家庭下可以创建多个账本例如“日常开销账本”、“旅行专用账本”、“装修账本”。每个账本关联多个资金账户如“微信零钱”、“支付宝”、“建设银行储蓄卡”、“现金钱包”等。账户需要记录初始余额和当前余额。收支记录核心模块这是系统的灵魂。每一笔记录应包含金额、类型收入/支出、分类餐饮、交通、购物、工资等、账户从哪个账户支出或收入到哪个账户、时间、备注、关联成员谁花的钱、图片凭证可上传小票照片等。支出和收入会实时影响对应账户的余额。统计与分析模块记账的最终目的是为了分析。系统需要提供多维度的数据可视化按日/周/月/年的收支趋势图按分类的消费占比饼图家庭成员的消费排行预算与实际支出的对比等。这部分对后端的数据聚合查询能力SQL和前端的图表库如微信小程序的ec-canvas或F2要求较高。预算与提醒模块可以设置月度总预算或分类预算当消费接近或超出预算时通过小程序模板消息提醒家庭成员。还可以设置周期性账单如房贷、房租的自动记账提醒。设计时要特别注意数据的“聚合”与“权限”。例如统计家庭总支出时需要聚合所有成员的记录而个人视角下可能只想看自己的消费。在查询和展示时需要根据当前用户的角色和权限动态过滤数据。3. 数据库设计与关键表结构详解数据库设计是系统的基石设计的好坏直接影响到后期业务的复杂度和系统性能。对于家庭记账系统核心是围绕“流水”来构建模型。3.1 核心表结构设计以下是我根据常见需求推导出的核心表结构你的源码中应该会有类似实现用户表 (user)CREATE TABLE user ( id int(11) NOT NULL AUTO_INCREMENT COMMENT 主键ID, open_id varchar(100) NOT NULL COMMENT 微信OpenID唯一标识, nick_name varchar(100) DEFAULT NULL COMMENT 微信昵称, avatar_url varchar(500) DEFAULT NULL COMMENT 微信头像, create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, PRIMARY KEY (id), UNIQUE KEY uk_openid (open_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表;注意open_id是关键它是小程序用户在当前小程序内的唯一标识用于关联所有业务数据。切勿存储用户的微信敏感信息。家庭表 (family)CREATE TABLE family ( id int(11) NOT NULL AUTO_INCREMENT COMMENT 家庭ID, family_name varchar(50) NOT NULL COMMENT 家庭名称, invite_code varchar(10) NOT NULL COMMENT 家庭邀请码, creator_id int(11) NOT NULL COMMENT 创建者用户ID, create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, PRIMARY KEY (id), UNIQUE KEY uk_invite_code (invite_code), KEY idx_creator (creator_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT家庭表;实操心得invite_code可以设计成一个6-8位的随机数字字母组合并确保唯一。生成后可以长期有效方便家庭成员随时加入。家庭-成员关系表 (family_member)CREATE TABLE family_member ( id int(11) NOT NULL AUTO_INCREMENT, family_id int(11) NOT NULL COMMENT 家庭ID, user_id int(11) NOT NULL COMMENT 用户ID, role tinyint(4) NOT NULL DEFAULT 1 COMMENT 角色0-管理员1-普通成员, join_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 加入时间, PRIMARY KEY (id), UNIQUE KEY uk_family_user (family_id,user_id), -- 防止重复加入 KEY idx_user (user_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT家庭成员关系表;这张表解决了多对多关系一个家庭有多个成员一个用户可以属于多个家庭通常设计为一个用户只属于一个家庭此处按主流设计。role字段用于权限控制例如只有管理员可以删除账本或移除成员。账户表 (account)CREATE TABLE account ( id int(11) NOT NULL AUTO_INCREMENT, family_id int(11) NOT NULL COMMENT 所属家庭ID, account_name varchar(50) NOT NULL COMMENT 账户名称如招商银行卡, account_type tinyint(4) NOT NULL COMMENT 账户类型1-现金2-储蓄卡3-信用卡4-数字钱包, balance decimal(12,2) NOT NULL DEFAULT 0.00 COMMENT 当前余额, initial_balance decimal(12,2) NOT NULL DEFAULT 0.00 COMMENT 初始余额, is_active tinyint(1) NOT NULL DEFAULT 1 COMMENT 是否激活, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_family (family_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT资金账户表;关键点解析balance当前余额是一个衍生数据它应该由所有相关的收支记录计算得来而不是单纯地通过UPDATE语句修改。为了保证数据一致性任何一笔涉及该账户的收支记录插入时都必须同步更新对应账户的balance。这通常在一个事务内完成。收支分类表 (category)CREATE TABLE category ( id int(11) NOT NULL AUTO_INCREMENT, family_id int(11) NOT NULL COMMENT 家庭ID0表示系统默认分类, name varchar(20) NOT NULL COMMENT 分类名称如餐饮、交通, type tinyint(4) NOT NULL COMMENT 类型1-支出2-收入, icon varchar(100) DEFAULT NULL COMMENT 图标标识, sort int(11) DEFAULT 0 COMMENT 排序, PRIMARY KEY (id), KEY idx_family_type (family_id,type) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT收支分类表;这里的设计允许每个家庭自定义自己的分类family_id 0同时也提供一套系统默认分类family_id 0供新家庭直接使用提升了用户体验。收支记录表 (bill) - 核心表CREATE TABLE bill ( id int(11) NOT NULL AUTO_INCREMENT, family_id int(11) NOT NULL COMMENT 家庭ID, account_id int(11) NOT NULL COMMENT 关联账户ID, category_id int(11) NOT NULL COMMENT 分类ID, type tinyint(4) NOT NULL COMMENT 记录类型1-支出2-收入, amount decimal(12,2) NOT NULL COMMENT 金额, transaction_time datetime NOT NULL COMMENT 交易时间, description varchar(200) DEFAULT NULL COMMENT 备注描述, creator_id int(11) NOT NULL COMMENT 记录创建者用户ID, image_url varchar(500) DEFAULT NULL COMMENT 凭证图片URL, create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 记录创建时间, PRIMARY KEY (id), KEY idx_family_time (family_id,transaction_time), -- 按家庭和时间查询是最高频操作 KEY idx_account (account_id), KEY idx_category (category_id), KEY idx_creator (creator_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT收支记录表;这是系统的核心表数据量会随时间快速增长。索引设计至关重要。idx_family_time复合索引能高效支持“查看某家庭某时间段内账单”这个最核心的查询场景。3.2 表关系与事务一致性保障上述表通过外键逻辑上关联在一起。例如一条bill记录关联一个account、一个category、一个creator(user)并归属于一个family。最关键的事务场景新增一笔支出记录向bill表插入一条新记录。更新对应account表的balance字段balance balance - amount。这两个操作必须在同一个数据库事务中完成。在Spring中可以通过Transactional注解来声明事务边界确保原子性要么都成功要么都失败回滚防止出现“记了账但余额没变”的脏数据。Service public class BillService { Autowired private BillMapper billMapper; Autowired private AccountMapper accountMapper; Transactional // 声明事务 public void addExpense(Bill bill) { // 1. 插入账单记录 billMapper.insert(bill); // 2. 更新账户余额减少 accountMapper.decreaseBalance(bill.getAccountId(), bill.getAmount()); // 如果此处或之前发生异常整个操作将回滚 } }4. 后端SSM框架整合与核心业务实现4.1 项目结构与环境搭建一个标准的SSM项目结构如下family-account-book/ ├── src/main/java/ │ └── com.example.accountbook/ │ ├── controller/ # 控制层接收请求调用Service返回JSON │ ├── service/ # 业务逻辑层接口与实现分离 │ │ ├── impl/ │ ├── dao/ # 数据访问层即Mapper接口对应MyBatis │ ├── entity/ # 实体类与数据库表对应 │ ├── dto/ # 数据传输对象用于接口传参和返回 │ ├── vo/ # 视图对象用于前端展示的复杂对象 │ └── config/ # 配置类Spring, MyBatis, 拦截器等 ├── src/main/resources/ │ ├── mapper/ # MyBatis的XML映射文件 │ ├── static/ # 静态资源 │ ├── templates/ # 模板文件本项目可能不用 │ └── application.yml # 主配置文件数据库、端口等 └── pom.xml # Maven依赖管理关键依赖 (pom.xml):Spring Boot Starter: 简化SSM整合推荐使用Spring Boot。MyBatis Spring Boot Starter: 集成MyBatis。MySQL Connector: 数据库驱动。Jackson: JSON处理。Lombok: 简化实体类编写可选但推荐。配置文件 (application.yml):server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/family_account?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: yourpassword mybatis: mapper-locations: classpath:mapper/*.xml # 指定MyBatis映射文件位置 configuration: map-underscore-to-camel-case: true # 自动将下划线字段映射为驼峰属性4.2 核心业务逻辑层Service实现剖析以“新增账单”这个最复杂的业务为例我们来看Service层如何组织1. 参数校验与业务规则检查在Service方法入口首先要进行严格的参数校验。金额不能为负数或零账户必须存在且属于当前家庭分类必须有效等。这些校验可以放在Service中也可以使用Spring Validation注解在Controller层做初步校验。2. 事务管理如前所述涉及多个表写操作如bill插入和account更新必须放在Transactional事务中。3. 关联数据组装与更新账单记录中可能只存了分类ID但返回给前端时前端需要分类名称和图标。这通常有两种做法多次查询在Service中先插入账单再根据ID查询出完整的账单信息包含关联的分类、账户名称等。这种方式简单但会产生多次数据库查询。业务逻辑组装插入后通过一次联表查询MyBatis的association获取完整数据。或者在插入前就将所需信息如分类名称查好放入DTO中插入后直接返回这个DTO。后者效率更高。4. 代码示例BillServiceService Slf4j public class BillServiceImpl implements BillService { Autowired private BillMapper billMapper; Autowired private AccountMapper accountMapper; Autowired private CategoryMapper categoryMapper; Override Transactional(rollbackFor Exception.class) public BillVO addBill(BillCreateDTO createDTO, Integer currentUserId) { // 1. 基础校验 if (createDTO.getAmount() null || createDTO.getAmount().compareTo(BigDecimal.ZERO) 0) { throw new BusinessException(金额必须大于0); } // 校验账户是否存在且属于当前用户家庭此处省略家庭权限校验逻辑 Account account accountMapper.selectById(createDTO.getAccountId()); if (account null || !account.getFamilyId().equals(currentUserFamilyId)) { throw new BusinessException(账户不存在或无权限); } // 2. 构建实体并插入 Bill bill new Bill(); BeanUtils.copyProperties(createDTO, bill); // 使用Spring工具类拷贝属性 bill.setFamilyId(currentUserFamilyId); bill.setCreatorId(currentUserId); bill.setCreateTime(new Date()); billMapper.insert(bill); // 3. 更新账户余额 BigDecimal newBalance; if (createDTO.getType() 1) { // 支出 newBalance account.getBalance().subtract(createDTO.getAmount()); } else { // 收入 newBalance account.getBalance().add(createDTO.getAmount()); } // 乐观锁更新防止并发问题 int updateCount accountMapper.updateBalance(account.getId(), newBalance, account.getBalance()); if (updateCount 0) { log.error(更新账户余额失败可能存在并发操作。账户ID: {}, account.getId()); throw new BusinessException(系统繁忙请重试); } // 4. 查询并组装返回给前端的VO对象 BillVO billVO billMapper.selectBillDetailById(bill.getId()); return billVO; } }注意事项上面的updateBalance方法使用了乐观锁通过对比更新前的余额来确保在并发环境下数据的一致性。这是金融类操作中非常重要的细节。4.3 数据访问层MyBatis Mapper与复杂查询MyBatis的威力在复杂查询时最能体现。例如我们需要查询某个家庭在某个月份的消费统计并按分类分组。Mapper接口public interface BillMapper extends BaseMapperBill { // 假设使用了MyBatis-Plus // 自定义复杂查询方法 ListCategoryStatVO getCategoryStat(Param(familyId) Integer familyId, Param(startDate) Date startDate, Param(endDate) Date endDate, Param(type) Integer type); }XML映射文件 (BillMapper.xml):?xml version1.0 encodingUTF-8? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.example.accountbook.dao.BillMapper select idgetCategoryStat resultTypecom.example.accountbook.vo.CategoryStatVO SELECT c.id AS categoryId, c.name AS categoryName, c.icon AS icon, SUM(b.amount) AS totalAmount, COUNT(b.id) AS recordCount FROM bill b INNER JOIN category c ON b.category_id c.id WHERE b.family_id #{familyId} AND b.type #{type} AND b.transaction_time BETWEEN #{startDate} AND #{endDate} GROUP BY c.id, c.name, c.icon ORDER BY totalAmount DESC /select !-- 关联查询账单详情 -- select idselectBillDetailById resultMapBillDetailMap SELECT b.*, a.account_name, c.name as category_name, c.icon as category_icon, u.nick_name as creator_name FROM bill b LEFT JOIN account a ON b.account_id a.id LEFT JOIN category c ON b.category_id c.id LEFT JOIN user u ON b.creator_id u.id WHERE b.id #{id} /select resultMap idBillDetailMap typecom.example.accountbook.vo.BillVO id propertyid columnid/ !-- 映射基本字段 -- result propertyamount columnamount/ result propertydescription columndescription/ !-- 映射关联对象 -- result propertyaccountName columnaccount_name/ result propertycategoryName columncategory_name/ result propertycategoryIcon columncategory_icon/ result propertycreatorName columncreator_name/ /resultMap /mapper这种灵活的SQL编写能力使得实现复杂的报表统计变得清晰而高效。5. 微信小程序前端开发关键点5.1 项目结构与页面规划小程序标准目录结构如下miniprogram/ ├── pages/ # 所有页面 │ ├── index/ # 首页账单列表/统计概览 │ ├── add-bill/ # 新增账单页 │ ├── statistics/ # 统计报表页 │ ├── account-manage/ # 账户管理页 │ └── my/ # 我的个人/家庭设置 ├── components/ # 自定义组件如分类选择器、日期选择器 ├── utils/ # 工具函数如网络请求封装、日期格式化 ├── app.js # 小程序入口全局逻辑 ├── app.json # 全局配置页面路径、窗口样式等 ├── app.wxss # 全局样式 └── project.config.json # 项目配置在app.json中注册页面和设置底部tabBar是第一步{ pages: [ pages/index/index, pages/add-bill/add-bill, pages/statistics/statistics, pages/my/my ], tabBar: { list: [ { pagePath: pages/index/index, text: 首页, iconPath: images/tab-home.png, selectedIconPath: images/tab-home-active.png }, { pagePath: pages/statistics/statistics, text: 统计, iconPath: images/tab-chart.png, selectedIconPath: images/tab-chart-active.png }, { pagePath: pages/my/my, text: 我的, iconPath: images/tab-my.png, selectedIconPath: images/tab-my-active.png } ] }, // ... 其他窗口样式配置 }5.2 用户登录与身份标识小程序获取用户身份是一个特殊流程不依赖传统的用户名密码。调用wx.login()获取临时登录凭证code。将code发送到你的Java后端服务器。后端服务器用appid、secret和code调用微信接口服务https://api.weixin.qq.com/sns/jscode2session换取用户的openid和session_key。后端将openid作为用户唯一标识生成一个自定义的登录态例如一个Token返回给小程序。小程序将Token存储在本地wx.setStorageSync并在后续请求的Header中携带如Authorization: Bearer token。关键点session_key用于解密用户敏感数据如手机号应妥善保存在服务端绝不能传到前端。Token的有效期管理、续期机制也需要设计。5.3 页面交互与数据绑定以“新增账单页”(add-bill.wxml)为例展示如何与后端交互!-- add-bill.wxml -- view classcontainer picker modeselector range{{typeList}} range-keyname value{{typeIndex}} bindchangeonTypeChange view classpicker类型{{typeList[typeIndex].name}}/view /picker input typedigit placeholder请输入金额 bindinputonAmountInput value{{amount}}/ picker modeselector range{{categoryList}} range-keyname value{{categoryIndex}} bindchangeonCategoryChange view classpicker分类{{categoryList[categoryIndex].name}}/view /picker !-- 账户选择、时间选择等类似 -- textarea placeholder备注可选 bindinputonDescInput value{{description}}/ button typeprimary bindtaponSubmit loading{{loading}}记一笔/button /view// add-bill.js Page({ data: { typeList: [{name: 支出, value: 1}, {name: 收入, value: 2}], typeIndex: 0, categoryList: [], amount: , loading: false }, onLoad() { // 页面加载时从后端获取当前家庭的分类列表和账户列表 this.loadCategoriesAndAccounts(); }, onAmountInput(e) { this.setData({ amount: e.detail.value }); }, async onSubmit() { if (!this.data.amount || this.data.amount 0) { wx.showToast({ title: 请输入有效金额, icon: none }); return; } this.setData({ loading: true }); try { const res await wx.request({ url: https://your-domain.com/api/bill/add, method: POST, header: { Authorization: Bearer ${wx.getStorageSync(token)}, Content-Type: application/json }, data: { type: this.data.typeList[this.data.typeIndex].value, amount: parseFloat(this.data.amount), categoryId: this.data.categoryList[this.data.categoryIndex].id, accountId: this.data.accountId, transactionTime: this.data.time, description: this.data.description } }); if (res.statusCode 200 res.data.code 0) { wx.showToast({ title: 记录成功 }); // 记录成功后可以返回上一页或清空表单 setTimeout(() wx.navigateBack(), 1500); } else { wx.showToast({ title: res.data.msg || 记录失败, icon: none }); } } catch (err) { wx.showToast({ title: 网络错误, icon: none }); } finally { this.setData({ loading: false }); } } })实操心得网络请求务必做好加载状态管理loading和错误处理try-catch。金额输入框使用typedigit可以调起数字键盘提升体验。所有用户输入的数据在后端必须再次进行校验和防注入处理。5.4 数据可视化与图表绘制统计页面是展示价值的核心。微信小程序原生不支持SVG或Canvas图表需要借助第三方组件库。ec-canvasECharts小程序版和F2AntV是两大主流选择。使用ec-canvas绘制月度消费趋势图步骤在项目根目录通过npm安装echarts-for-weixin或直接下载组件源码。在statistics.json中引入组件。在statistics.wxml中放置ec-canvas组件。在statistics.js中从后端获取按日聚合的消费数据。初始化ECharts实例并配置optionx轴为日期y轴为金额系列为折线图。将配置好的option通过setOption方法传递给图表实例。图表的数据通常需要后端提供聚合接口例如/api/statistics/daily?familyIdxxmonth2023-10type1返回一个日期和金额的数组。6. 前后端联调与部署上线6.1 接口设计与联调前后端分离开发接口契约是沟通的桥梁。建议使用RESTful风格设计API并统一响应格式。统一的响应体格式{ code: 0, // 业务状态码0成功非0失败 msg: success, // 提示信息 data: {} // 响应数据 }示例接口文档GET /api/bill/list?page1size20startDateendDate获取账单列表分页筛选POST /api/bill/add新增账单GET /api/statistics/category?month2023-10获取分类统计GET /api/account/list获取账户列表联调时后端开发人员可以使用Swagger或Knife4j自动生成接口文档前端通过文档进行对接。小程序开发者工具可以设置不校验合法域名方便本地开发调试。关键是要确保后端服务开启CORS跨域资源共享或通过Nginx进行代理。6.2 项目部署与上线后端部署打包使用Maven执行mvn clean package生成可执行的JAR包Spring Boot项目或WAR包。服务器准备购买一台云服务器如阿里云ECS安装JDK版本需与开发环境一致和MySQL。数据库初始化在服务器MySQL中创建数据库并执行项目的SQL脚本建表、初始化数据。上传与运行将JAR包上传至服务器使用nohup java -jar your-app.jar 命令在后台运行。更推荐使用systemd或Docker容器化部署便于管理和监控。域名与HTTPS为服务器IP绑定域名并申请SSL证书小程序要求后端API必须为HTTPS。可以使用Nginx作为反向代理配置SSL并转发请求到后端Java应用。小程序部署修改配置在小程序项目的配置文件中将请求的后端域名改为你部署好的HTTPS地址。上传代码在微信开发者工具中点击“上传”将代码提交到微信后台。提交审核在微信公众平台小程序管理后台提交版本进行审核。发布审核通过后即可发布上线。重要提醒小程序后台的“开发管理”-“开发设置”中必须将你的后端服务器域名添加到“request合法域名”列表中否则线上版本无法请求你的接口。7. 常见问题排查与性能优化实录在实际开发和运行中你一定会遇到各种问题。这里记录几个典型场景和解决思路。7.1 常见问题速查表问题现象可能原因排查步骤与解决方案小程序无法登录后端获取openid失败1.appid和secret配置错误。2. 服务器网络无法访问微信API。3.code被重复使用或过期。1. 检查后端配置的appid和secret是否与小程序后台一致。2. 在后端服务器上使用curl测试是否能访问api.weixin.qq.com。3. 确保每个code只用于一次jscode2session调用。新增账单成功但账户余额没变事务未生效或更新语句有误。1. 检查Service方法是否添加了Transactional注解。2. 检查数据库事务隔离级别确认更新语句是否执行成功。3. 在MyBatis的XML映射文件的更新语句后添加SELECT ROW_COUNT();并在代码中打印影响行数。统计查询速度慢页面卡顿1. 数据量增大。2. 缺少有效索引。3. SQL语句未优化。1. 使用EXPLAIN分析慢查询SQL确认是否走了索引。2. 为bill表的family_id,transaction_time,type等查询条件字段建立复合索引。3. 考虑对历史冷数据进行分表或归档。小程序预览/真机调试正常但上线后白屏或请求失败1. 未配置合法域名。2. 后端服务器HTTPS证书问题。3. 线上环境代码或配置有差异。1. 确认小程序后台“request合法域名”已正确配置且已生效需重新打包上传。2. 检查后端HTTPS证书是否有效、是否被信任。3. 对比开发环境和线上环境的配置文件如数据库地址。并发记账导致余额不准多个请求同时更新同一账户余额后覆盖前。采用乐观锁机制。在account表增加version字段或使用balance作为版本条件。更新时UPDATE account SET balance new_balance WHERE id ? AND balance old_balance。7.2 性能优化建议数据库层面索引是王道除了主键在bill表的(family_id, transaction_time)上建立复合索引对account_id,category_id等外键建立单列索引。避免SELECT *在MyBatis查询中明确写出需要查询的字段减少网络传输和内存占用。分页查询账单列表务必使用分页如LIMIT offset, size避免一次性拉取大量数据。可以使用基于create_time的游标分页性能优于传统的LIMIT分页。后端层面接口缓存对于变化不频繁的数据如系统默认分类、用户基本信息可以使用Redis进行缓存设置合理的过期时间。异步处理对于非实时性要求高的操作如发送记账提醒的模板消息、生成月度统计报告可以放入消息队列如RabbitMQ异步处理提升主接口响应速度。连接池优化在application.yml中合理配置Druid或HikariCP数据库连接池参数如最大连接数、最小空闲连接等。小程序层面图片优化凭证图片上传前可使用小程序API进行压缩。列表页展示缩略图详情页再加载原图。数据本地缓存将家庭信息、分类列表、账户列表等不常变的数据在首次加载后存入wx.setStorageSync减少不必要的网络请求。防抖与节流在搜索框输入、页面滚动加载更多等场景使用防抖或节流函数避免频繁触发回调。这个项目从技术选型到业务实现涵盖了一个完整Web应用的核心要素。把它吃透不仅能让你轻松应对毕业设计更能为你叩开Java后端或全栈开发的大门打下坚实的实战基础。开发过程中多思考“为什么这样设计”多动手“遇到问题自己查”你会收获远比代码本身更多的东西。如果在复现过程中遇到具体的技术难题不妨带着问题去查阅官方文档或社区那将是成长的快车道。本文还有配套的精品资源点击获取
返回列表