拓冰建站拓冰建站
首页 / 资讯中心 / 正文

SSM+微信小程序实战:家庭记账本后端接口与数据库联调指南

简介基于微信小程序与SSM框架的家庭记账本毕业设计资源主要面向计算机相关专业学生用于毕业设计、课程设计或期末大作业也适合想学习小程序与Java后台整合开发的新手。代码注释较完整环境配置思路清晰便于阅读和二次开发。压缩包共774个文件总大小约126.05MB涵盖Java后端代码、Vue管理页面、小程序WXML/WXSS、JavaScript、JSON配置文件、MySql数据库脚本以及构建运行脚本等核心源码、界面资源和初始化数据均有覆盖目录结构清晰便于按需查找。目前已有62人浏览学习。资源内提供项目源码、数据库脚本、部署说明与运行工具前端小程序与SSM后台接口完整配合建议的MySql 5.7、Tomcat和微信开发者工具即可搭建使用同时附有图片、图标、音频、视频等辅助素材能支撑从环境准备到功能演示的完整流程是毕业设计和课程设计的高分参考也可作为后续功能扩展的基础。1. 一个家庭记账本小程序为什么要从 SSM 后端讲起“家庭记账本”是毕业设计池子里出现频率最高的题目之一这个标题真正值钱的地方在于它把日常业务、移动端、服务端和数据库串成了一条完整的链路。前端是微信小程序负责录入一笔餐费、选择分类、查看月度统计后端是 SSMSpring Spring MVC MyBatis提供记账、查账、删账的接口数据库落一张账单表、一张分类表、一张用户表钱从哪来、花到哪去全都查得到。这类资源包通常由“后端 Java 工程 微信小程序目录 数据库脚本 教程文档”四部分组成拿到手第一件事不是看论文而是先让一条请求真正跑通。我讲这个题目的方式就是一线工程师拿到这套工程后自己会做的事先拆 SSM 接口链路再写小程序页面对接然后把数据库和统计 SQL 调对最后本地启动、用开发者工具逐一验证。“源码”不是让你背的是给你改出来的。接下来按动手的顺序推进。2. 先理解 SSM 这半边接口、分层和统一响应体2.1 毕业设计选 SSM 而不选 Spring Boot 的直接原因SSM 是 Spring、Spring MVC、MyBatis 三个框架的组合本科教学里 Java Web 课程通常就落在这套体系上。虽然现在生产环境大量转向 Spring Boot但毕业设计选 SSM 有一个很现实的好处它把 Bean 管理、请求映射、SQL 映射三件事拆开每一层都能单独讲清楚答辩时“为什么用事务”“为什么用接口编程”都有具体代码可以指。从技术栈关系看Spring 管 Service 层对象的创建和注入Spring MVC 管前端请求怎么找到 Controller 方法MyBatis 管 SQL 和 Java 对象的映射。三者之间靠applicationContext.xml、springmvc.xml以及 Mapper 接口装配在一起。常见工程结构是典型的“Controller → Service → ServiceImpl → Mapper → XML”前缀包名一般是com.xxx.familybill你在 IDEA 里能一眼认出来。2.2 一个记账接口从 Controller 到 Mapper 的完整链路2.2.1 统一返回结构 Result 的字段设计小程序端不像浏览器页面那样天然有会话 cookie它拿到响应后需要先判断“这次请求到底成没成功”所以后端要有一个统一的 JSON 包装体。最常规的字段就三个code、msg、data。public class ResultT { private Integer code; private String msg; private T data; public static T ResultT success(T data) { ResultT r new Result(); r.setCode(200); r.setMsg(ok); r.setData(data); return r; } public static T ResultT error(Integer code, String msg) { ResultT r new Result(); r.setCode(code); r.setMsg(msg); return r; } // getter / setter 省略实际运行时必须有完整实现 }这里把业务失败和 HTTP 状态码做了一次解耦HTTP 200 代表网络层通了code才是业务层的标识比如 401 表示 token 过期500 表示服务器异常。小程序端只需要对body.code做分支判断不用关心 404、405 这类传输层状态这对移动端联调非常友好。2.2.2 记账接口的请求与响应新记一笔账是家庭记账本最核心的操作。Controller 层接收一个 JSON 对象同时从请求头里取出 token用来识别当前用户是谁。常见写法如下RestController RequestMapping(/api/bill) public class BillController { Autowired private BillService billService; PostMapping(/add) public ResultString add(RequestBody BillDTO billDTO, RequestHeader(token) String token) { Long userId tokenService.getUserId(token); if (userId null) { return Result.error(401, 登录过期请重新登录); } billService.addBill(userId, billDTO); return Result.success(记账成功); } }注意RequestHeader(token)不是随便写的。微信小程序的wx.request里可以自定义 header但某些版本的开发者工具会拦截带中文或特殊符号的 header 值所以 token 最好只用UUID这类十六进制字符串。另外如果远程调试时出现“token 取不到”的报错先检查 header 的 key 拼写再检查是否在onLoad阶段提前触发了请求。Service 层的职责是写业务规则比如“支出金额必须大于 0”“分类必须属于当前用户”Mapper 层只管 SQL 落库。加分的小设计是让BillDTO只在 Controller 和 Service 之间传递避免把数据库实体直接暴露给前端字段多了也不容易误传。2.3 Spring 集成 MyBatis 的配置要点传统 SSM 工程的核心配置一般落在两个 XML 文件里。spring-dao.xml负责数据源、SqlSessionFactory 和 Mapper 扫描bean iddataSource classcom.alibaba.druid.pool.DruidDataSource property namedriverClassName valuecom.mysql.cj.jdbc.Driver/ property nameurl valuejdbc:mysql://localhost:3306/family_bill?useUnicodetrueamp;characterEncodingutf8/ property nameusername valueroot/ property namepassword valueroot/ /bean bean idsqlSessionFactory classorg.mybatis.spring.SqlSessionFactoryBean property namedataSource refdataSource/ property namemapperLocations valueclasspath:mapper/*.xml/ /bean bean classorg.mybatis.spring.mapper.MapperScannerConfigurer property namebasePackage valuecom.familybill.mapper/ /beanmapperLocations指定的是 SQL 映射 XML 的路径新手常犯的错是把 XML 放在src/main/java下但没配置 resources 识别导致启动时报Invalid bound statement (not found)。解决办法是在pom.xml里显式声明让 Maven 打包时把src/main/java下的 XML 也带上或者在src/main/resources/mapper下统一存放。数据源用 Druid 还是 C3P0 不影响业务关键是 MySQL 8.x 需要com.mysql.cj.jdbc.DriverMySQL 5.x 用com.mysql.jdbc.Driver版本不对时驱动加载就会静默失败。3. 再写微信小程序端记账页、分类选择和 request 封装3.1 页面结构与表单校验微信小程序的记账首页主要由“金额输入框”“分类选择区”“类型切换支出/收入”“备注输入框”和“保存按钮”组成。分类按钮用scroll-view横向排列比swiper更轻量切换时通过data绑定维护当前选中的分类 id。表单提交前先做本地校验避免无效请求打到后端。以下是小程序里常见的submit逻辑submitBill() { const amount this.data.amount; const categoryId this.data.categoryId; const type this.data.type; if (!amount || Number(amount) 0) { wx.showToast({ title: 请输入有效金额, icon: none }); return; } if (!categoryId) { wx.showToast({ title: 请选择分类, icon: none }); return; } // 校验通过继续调用 request 封装 this.saveBill(); }这里建议把金额输入框的type设为digit键盘会弹出带小数点的数字面板同时在小程序端限制最多两位小数。原生小程序的input组件拿到的是字符串Number(amount)转成浮点数后要留意0.1 0.2这类精度陷阱所以传给后端的金额建议直接是字符串由后端用BigDecimal转换。3.2 wx.request 封装与 token 注入家庭记账本的每个查询、新增接口都依赖当前用户但小程序没有 cookie 机制。常见做法是登录接口返回 token小程序用wx.setStorageSync存起来之后每次请求都把这个 token 放进 header。封装好的request是整段前端代码里最值得复用的部分const BASE_URL http://localhost:8080/family_bill; function request(url, method, data) { return new Promise((resolve, reject) { wx.request({ url: BASE_URL url, method: method, data: data, header: { Content-Type: application/json, token: wx.getStorageSync(token) }, success(res) { const body res.data; if (body.code 200) { resolve(body.data); } else if (body.code 401) { wx.removeStorageSync(token); wx.navigateTo({ url: /pages/login/login }); reject(body); } else { wx.showToast({ title: body.msg, icon: none }); reject(body); } }, fail(err) { wx.showToast({ title: 网络异常, icon: none }); reject(err); } }); }); }fail回调不等于“后端报错”它只代表网络层没通常见原因在小程序开发工具里是“不在以下 request 合法域名列表中”在真机上则是后端地址填成了localhost。把BASE_URL抽出来放在独立文件里后面切服务器地址时只改一行。3.3 加载态和 toast 反馈记一笔账的完整反馈链路是点击保存 → 按钮变 loading → 成功 toast → 刷新账单列表 → 返回。不能用wx.showToast同时展示 loading 和成功提示因为同一个页面同时只能渲染一种 toast 实例后者会直接覆盖前者。常规写法是在saveBill里先wx.showLoading收到request成功结果后再wx.hideLoading和wx.showToast。如果“加载中”一闪而过甚至不出现检查 Promise 是否在success回调里同步调用了resolve异步时序不对时 loading 会被系统自动回收。4. 钱记进去之后数据库设计、核心 SQL 与金额统计4.1 数据表如何拆成一个宽表和两个窄表家庭记账本最少需要三张表用户表、分类表、账单表。分类表按用户拆分是很多毕业设计容易漏掉的细节——每个家庭可以自定义“宠物”“育儿”等分类如果所有用户共用一个全局分类字典统计就会串户。建议表结构如下表名关键字段说明t_useruser_id, username, password, nicknamepassword 用 MD5 加盐或 BCrypt不要存明文t_categorycategory_id, user_id, category_name, type, icontype 区分 expense / incomet_billbill_id, user_id, category_id, amount, type, remark, bill_dateamount 用 DECIMAL(10,2)bill_date 用 DATEt_bill冗余了一个type字段因为从账单查询时先按“支出/收入”过滤再联分类表拿分类名。这个冗余能省一层 join也避免分类被删除后历史账单失去收支属性。外键可以不建靠 Mapper 里的JOIN条件保证一致性更符合 SSM 项目的常见写法。4.2 按分类统计“支出”的 MyBatis 映射写法月度统计是本项目的核心查询。需求是“某个月按分类汇总支出金额从高到低排序”对应 SQL 以时间范围作为筛选条件以category_id分组。Mapper XML 里要写成动态 SQL因为开始日期和结束日期可能只传一个select idselectExpenseStatByMonth resultTypecom.familybill.vo.CategoryStat SELECT c.category_name AS categoryName, SUM(b.amount) AS totalAmount, COUNT(*) AS billCount FROM t_bill b INNER JOIN t_category c ON b.category_id c.category_id WHERE b.user_id #{userId} AND b.type expense if teststartDate ! null AND b.bill_date gt; #{startDate} /if if testendDate ! null AND b.bill_date lt; #{endDate} /if GROUP BY c.category_id, c.category_name ORDER BY totalAmount DESC /selectgt;和lt;是 XML 里的转义写法不能直接写否则 XML 解析就会报错。返回值CategoryStat不需要对应数据库表它是一个 VO字段名通过AS与 SQL 别名对齐MyBatis 开启驼峰映射后totalAmount和total_amount会自动转换。统计接口在 SSM 侧的入参是一个StatQueryDTO包含 userId、startDate、endDate。小程序端传入的日期格式固定为yyyy-MM-dd后端不要用java.util.Date接收否则时区偏移会让统计少一天或多一天直接用字符串接收最省心。4.3 查询与写入容易踩的精度和时区问题第一金额必须用DECIMAL(10,2)Java 实体里对应BigDecimal。如果用double平均数、环比增长率在展示时会产生 0.0000001 的残留小程序toFixed(2)只能掩盖显示层问题四舍五入的统计口径却已经错了。第二bill_date存的是“这笔钱发生在几号”不是“这笔记录什么时候创建”。两者分开bill_date由前端选择或默认当天create_time用数据库DEFAULT CURRENT_TIMESTAMP。很多统计图月份对不上就是因为把create_time当成了账单日期。第三删除分类时不能物理删除。用户删掉“宠物”分类后历史账单里category_id会指向不存在的分类统计 SQL 用INNER JOIN时这些账单会被直接丢弃总额瞬间变小。常见做法是给t_category加一个status字段删除改成软删或者选另一个兜底分类替换过去。5. 落地验证本地启动、联调配置和 Network 面板排错5.1 导入项目后的 4 个必看目录拿到资源包后先别急着跑。先在 IDEA 里打开后端工程重点看四个地方src/main/java下的包结构是否完整、src/main/resources下是否有applicationContext.xml和springmvc.xml、src/main/webapp/WEB-INF/web.xml里 ContextLoaderListener 是否配置、src/main/resources/mapper下是否有 BillMapper.xml。数据库脚本通常在压缩包根目录的sql或db文件夹里用 Navicat 或命令行导入后再改spring-dao.xml里的账号密码。5.2 开发者工具里必须做的一处设置本地起后端后接口地址是http://localhost:8080而微信小程序生产环境强制 HTTPS。开发阶段的解决方式不是换域名而是直接在微信开发者工具右上角“详情 → 本地设置”里勾选“不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书”。只有勾了这一步wx.request才允许访问http://localhost。如果你在 Network 面板里看到request:fail十有八九就是这一项没勾上。5.3 接口不通时按这个顺序排查联调失败时不要直接猜。按下面顺序排查每个步骤都有明确的验证点序号排查点验证方法1请求是否发出开发者工具 Network 面板看请求记录2请求是否到后端Tomcat 控制台看/api/bill/add日志3数据库连接是否成功后端日志里的 SQLException4表是否存在Navicat 打开 family_bill 库看表列表5token 是否为空Network 面板看 header 里的 token 字段一个常见现象是用浏览器直接访问后端接口能通小程序里却报 404。这是因为小程序请求路径里带了/api而后端web.xml配置的 servlet-mapping 是/但 contextPath 如果配成了/family_bill完整 URL 应该是http://localhost:8080/family_bill/api/bill/add少拼一段路径就会被 Tomcat 当作资源找不到。5.4 用 Network 面板验证“记账成功”最后一次完整验证一笔支出。小程序里填“早餐 12.50 元”点击保存打开开发者工具 Network 面板选中那条bill/add请求。点开 Response 标签能看到code: 200, msg: ok再切到 SQL 查询工具输入SELECT * FROM t_bill ORDER BY create_time DESC LIMIT 1;确认 amount 是12.50、category_id 对得上。整套流程走通后说明跨了“小程序端 → SSM 接口 → MyBatis → MySQL”四层的链路全部打通。6. 借助 Network 面板再压榨一层从“能用”到“敢改”6.1 通过请求详情判断慢在谁身上Network 面板的 Time 字段把一次 wx.request 的耗时拆成了两类等待服务器响应的耗时以及数据传输耗时。如果 Total Time 大但后端日志里打印 SQL 执行只用了几毫秒问题通常出在数据库连接池初始化或者t_bill表数据量增长后的索引缺失上。给t_bill加一个idx_user_billdate (user_id, bill_date)联合索引月度统计的分组查询会明显变快。这是不需要改业务代码就能见效的低成本优化。6.2 用响应码引导自己看懂后端异常后端报 500 时Network 面板只能看到 body 里的错误消息看不到堆栈。把springmvc.xml里的异常处理器补一段日志输出每次请求失败后直接看 IDEA 控制台最后的Caused by绝大多数问题都集中在三类SQL 语法不兼容、Mapper XML 里resultType写错类全限定名、以及#{}和${}用混导致 SQL 注入。把握住这三个方向比反复刷新页面更高效。6.3 把静态分类换成自己的规则理解整套代码后最值得改的第一处就是分类体系。把分类表改成“系统默认分类 用户自建分类”双层结构category_id不变只给t_category增加一个is_system字段。统计 SQL 不必改因为汇总只关心 category_id 和 type。这个小改动让“家庭”语义更成立——不同家庭可以维护自己的消费科目而通用的“餐饮”“交通”保留为系统数据。改完后重新跑一遍月度分组查询输出结果里新分类的金额能正确归并到用户所选科目上说明这个记账本已经从“跑通”升级成了“可扩展”。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门