十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

微信小程序宿舍水电缴费系统开发实战:Spring Boot+MySQL全栈实现

微信小程序宿舍水电缴费系统开发实战:Spring Boot+MySQL全栈实现 基于微信小程序的宿舍水电缴费系统开发实战在校园信息化建设中宿舍水电缴费一直是个高频且痛点明显的场景。传统的人工收费方式效率低下学生排队缴费耗时耗力管理员对账工作繁琐。基于微信小程序的解决方案能够完美解决这些问题让学生随时随地完成缴费管理员实时掌握数据。本文将完整介绍一个宿舍水电缴费小程序的开发全过程从环境搭建到功能实现包含前端界面设计、后端API开发、数据库设计以及支付集成等核心模块。无论你是计算机专业的学生需要完成毕业设计还是开发者想要学习微信小程序开发都能从中获得实用的技术方案。1. 系统架构与技术选型1.1 整体架构设计宿舍水电缴费系统采用典型的前后端分离架构。前端使用微信小程序原生框架后端采用Spring Boot构建RESTful API数据库使用MySQL存储业务数据同时集成微信支付完成交易流程。系统主要包含以下模块用户认证模块微信授权登录、手机号绑定费用查询模块水电用量查询、费用计算支付模块微信支付集成、订单管理管理后台数据统计、费用设置、用户管理1.2 技术栈说明前端技术栈微信小程序原生框架WXML/WXSS/JavaScriptVant Weapp组件库微信支付SDK后端技术栈Spring Boot 2.7MySQL 8.0MyBatis PlusRedis缓存微信开放平台SDK2. 开发环境准备2.1 前端开发环境首先需要安装微信开发者工具这是开发微信小程序的必备工具。# 下载微信开发者工具最新稳定版 # 官方下载地址https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html创建小程序项目的基本结构miniprogram/ ├── pages/ # 页面文件 │ ├── index/ # 首页 │ ├── bill/ # 账单页面 │ └── profile/ # 个人中心 ├── components/ # 自定义组件 ├── utils/ # 工具类 ├── app.js # 小程序入口 ├── app.json # 小程序配置 ├── app.wxss # 全局样式 └── project.config.json # 项目配置2.2 后端开发环境后端使用Spring Initializr快速创建项目!-- pom.xml 主要依赖 -- dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-redis/artifactId /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.2/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency /dependencies3. 数据库设计3.1 核心表结构设计宿舍水电缴费系统的数据库设计需要充分考虑扩展性和数据一致性。以下是几个核心表的设计-- 用户表 CREATE TABLE user ( id bigint(20) NOT NULL AUTO_INCREMENT, openid varchar(64) NOT NULL COMMENT 微信openid, student_id varchar(20) NOT NULL COMMENT 学号, name varchar(50) NOT NULL COMMENT 姓名, phone varchar(11) DEFAULT NULL COMMENT 手机号, dormitory_id bigint(20) NOT NULL COMMENT 宿舍ID, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_openid (openid), UNIQUE KEY uk_student_id (student_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 宿舍表 CREATE TABLE dormitory ( id bigint(20) NOT NULL AUTO_INCREMENT, building varchar(10) NOT NULL COMMENT 楼栋, room_number varchar(10) NOT NULL COMMENT 房间号, water_rate decimal(10,2) DEFAULT 5.00 COMMENT 水费单价, electricity_rate decimal(10,2) DEFAULT 0.60 COMMENT 电费单价, PRIMARY KEY (id), UNIQUE KEY uk_building_room (building, room_number) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 水电记录表 CREATE TABLE utility_record ( id bigint(20) NOT NULL AUTO_INCREMENT, dormitory_id bigint(20) NOT NULL, type tinyint(1) NOT NULL COMMENT 1-水费 2-电费, previous_reading decimal(10,2) NOT NULL COMMENT 上次读数, current_reading decimal(10,2) NOT NULL COMMENT 本次读数, usage_amount decimal(10,2) NOT NULL COMMENT 使用量, amount decimal(10,2) NOT NULL COMMENT 金额, record_date date NOT NULL COMMENT 记录日期, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 订单表 CREATE TABLE payment_order ( id bigint(20) NOT NULL AUTO_INCREMENT, order_no varchar(32) NOT NULL COMMENT 订单号, user_id bigint(20) NOT NULL, dormitory_id bigint(20) NOT NULL, amount decimal(10,2) NOT NULL COMMENT 支付金额, status tinyint(1) NOT NULL DEFAULT 0 COMMENT 0-待支付 1-已支付 2-已取消, pay_time datetime DEFAULT NULL COMMENT 支付时间, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_order_no (order_no) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;3.2 数据关系设计用户与宿舍是多对一关系一个宿舍可以有多个用户但一个用户只能属于一个宿舍。水电记录与宿舍是一对多关系每个宿舍会有多条水电使用记录。订单与用户是多对一关系一个用户可以有多个支付订单。4. 前端界面开发4.1 首页设计首页需要展示用户基本信息、当前水电费用情况以及快捷缴费入口。!-- pages/index/index.wxml -- view classcontainer view classuser-info image classavatar src{{userInfo.avatarUrl}}/image text classusername{{userInfo.nickName}}/text text classdormitory{{dormitoryInfo.building}}栋{{dormitoryInfo.roomNumber}}/text /view view classbill-card view classcard-title本月费用明细/view view classbill-item text水费/text text classamount¥{{waterBill.amount}}/text /view view classbill-item text电费/text text classamount¥{{electricityBill.amount}}/text /view view classtotal-amount text合计/text text classamount¥{{totalAmount}}/text /view /view button classpay-btn bindtapgoToPay立即缴费/button /view对应的样式文件/* pages/index/index.wxss */ .container { padding: 20rpx; } .user-info { display: flex; align-items: center; margin-bottom: 30rpx; } .avatar { width: 120rpx; height: 120rpx; border-radius: 50%; margin-right: 20rpx; } .bill-card { background: #fff; border-radius: 16rpx; padding: 30rpx; margin-bottom: 30rpx; box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.1); } .card-title { font-size: 32rpx; font-weight: bold; margin-bottom: 20rpx; } .bill-item { display: flex; justify-content: space-between; padding: 20rpx 0; border-bottom: 1rpx solid #f0f0f0; } .total-amount { display: flex; justify-content: space-between; padding: 20rpx 0; font-weight: bold; color: #e64340; } .pay-btn { background: #07c160; color: white; border-radius: 50rpx; font-size: 32rpx; }4.2 用户登录逻辑微信小程序需要实现用户授权登录获取用户基本信息。// pages/index/index.js Page({ data: { userInfo: {}, dormitoryInfo: {}, waterBill: {}, electricityBill: {}, totalAmount: 0 }, onLoad() { this.checkLoginStatus(); }, checkLoginStatus() { const token wx.getStorageSync(token); if (token) { this.getUserInfo(); this.getBillInfo(); } else { this.login(); } }, login() { wx.login({ success: (res) { if (res.code) { this.requestLogin(res.code); } } }); }, requestLogin(code) { wx.request({ url: https://your-domain.com/api/login, method: POST, data: { code }, success: (res) { if (res.data.success) { wx.setStorageSync(token, res.data.data.token); this.getUserInfo(); this.getBillInfo(); } } }); }, getUserInfo() { wx.getUserInfo({ success: (res) { this.setData({ userInfo: res.userInfo }); } }); }, getBillInfo() { wx.request({ url: https://your-domain.com/api/bill/current, header: { Authorization: wx.getStorageSync(token) }, success: (res) { if (res.data.success) { this.setData({ dormitoryInfo: res.data.data.dormitory, waterBill: res.data.data.waterBill, electricityBill: res.data.data.electricityBill, totalAmount: res.data.data.totalAmount }); } } }); }, goToPay() { wx.navigateTo({ url: /pages/pay/pay?amount this.data.totalAmount }); } });5. 后端API开发5.1 用户登录接口后端需要处理微信登录code换取openid并生成用户token。// UserController.java RestController RequestMapping(/api) public class UserController { Autowired private UserService userService; PostMapping(/login) public Result login(RequestBody LoginRequest request) { try { // 调用微信接口获取openid String openid wechatService.getOpenid(request.getCode()); // 查询或创建用户 User user userService.findOrCreateUser(openid); // 生成JWT token String token jwtUtil.generateToken(user.getId()); LoginResponse response new LoginResponse(); response.setToken(token); response.setUser(user); return Result.success(response); } catch (Exception e) { return Result.error(登录失败); } } } // LoginRequest.java Data public class LoginRequest { private String code; private String encryptedData; private String iv; } // WechatService.java Service public class WechatService { Value(${wechat.appid}) private String appid; Value(${wechat.secret}) private String secret; public String getOpenid(String code) { String url https://api.weixin.qq.com/sns/jscode2session ?appid appid secret secret js_code code grant_typeauthorization_code; RestTemplate restTemplate new RestTemplate(); String response restTemplate.getForObject(url, String.class); JSONObject json JSON.parseObject(response); return json.getString(openid); } }5.2 费用查询接口根据用户所在宿舍查询当前水电费用。// BillController.java RestController RequestMapping(/api/bill) public class BillController { Autowired private BillService billService; GetMapping(/current) public Result getCurrentBill(RequestHeader(Authorization) String token) { try { Long userId jwtUtil.getUserIdFromToken(token); CurrentBillResponse response billService.getCurrentBill(userId); return Result.success(response); } catch (Exception e) { return Result.error(查询失败); } } } // BillService.java Service public class BillService { Autowired private UserMapper userMapper; Autowired private UtilityRecordMapper recordMapper; Autowired private DormitoryMapper dormitoryMapper; public CurrentBillResponse getCurrentBill(Long userId) { User user userMapper.selectById(userId); Dormitory dormitory dormitoryMapper.selectById(user.getDormitoryId()); // 查询最近的水电记录 UtilityRecord lastWaterRecord recordMapper.selectLastRecord( dormitory.getId(), 1); // 1表示水费 UtilityRecord lastElectricityRecord recordMapper.selectLastRecord( dormitory.getId(), 2); // 2表示电费 CurrentBillResponse response new CurrentBillResponse(); response.setDormitory(dormitory); // 计算水费 if (lastWaterRecord ! null) { BillItem waterBill calculateBill(lastWaterRecord, dormitory.getWaterRate()); response.setWaterBill(waterBill); } // 计算电费 if (lastElectricityRecord ! null) { BillItem electricityBill calculateBill(lastElectricityRecord, dormitory.getElectricityRate()); response.setElectricityBill(electricityBill); } return response; } private BillItem calculateBill(UtilityRecord record, BigDecimal rate) { BillItem bill new BillItem(); bill.setPreviousReading(record.getPreviousReading()); bill.setCurrentReading(record.getCurrentReading()); bill.setUsageAmount(record.getUsageAmount()); bill.setAmount(record.getAmount()); return bill; } }6. 微信支付集成6.1 支付流程设计微信支付的完整流程包括创建订单、调用统一下单API、生成支付参数、前端调起支付、处理支付结果。// PaymentController.java RestController RequestMapping(/api/payment) public class PaymentController { Autowired private PaymentService paymentService; PostMapping(/create) public Result createPayment(RequestBody PaymentRequest request, RequestHeader(Authorization) String token) { try { Long userId jwtUtil.getUserIdFromToken(token); PaymentResponse response paymentService.createPayment(userId, request.getAmount()); return Result.success(response); } catch (Exception e) { return Result.error(创建支付失败); } } } // PaymentService.java Service public class PaymentService { Autowired private OrderMapper orderMapper; Value(${wechat.pay.appid}) private String appid; Value(${wechat.pay.mchid}) private String mchid; Value(${wechat.pay.key}) private String key; public PaymentResponse createPayment(Long userId, BigDecimal amount) { // 创建订单 PaymentOrder order new PaymentOrder(); order.setOrderNo(generateOrderNo()); order.setUserId(userId); order.setAmount(amount); order.setStatus(0); orderMapper.insert(order); // 调用微信支付统一下单 MapString, String params new HashMap(); params.put(appid, appid); params.put(mch_id, mchid); params.put(nonce_str, generateNonceStr()); params.put(body, 宿舍水电费缴纳); params.put(out_trade_no, order.getOrderNo()); params.put(total_fee, amount.multiply(new BigDecimal(100)).intValue() ); params.put(spbill_create_ip, 127.0.0.1); params.put(notify_url, https://your-domain.com/api/payment/notify); params.put(trade_type, JSAPI); params.put(openid, getOpenidByUserId(userId)); // 生成签名 String sign generateSign(params); params.put(sign, sign); // 调用微信支付API String xmlResult postWechatPay(https://api.mch.weixin.qq.com/pay/unifiedorder, params); // 解析返回结果 MapString, String result parseXml(xmlResult); if (SUCCESS.equals(result.get(return_code))) { PaymentResponse response new PaymentResponse(); response.setOrderNo(order.getOrderNo()); response.setPrepayId(result.get(prepay_id)); response.setTimeStamp(String.valueOf(System.currentTimeMillis() / 1000)); response.setNonceStr(generateNonceStr()); response.setSignType(MD5); // 生成前端支付参数 MapString, String payParams new HashMap(); payParams.put(appId, appid); payParams.put(timeStamp, response.getTimeStamp()); payParams.put(nonceStr, response.getNonceStr()); payParams.put(package, prepay_id response.getPrepayId()); payParams.put(signType, MD5); String paySign generateSign(payParams); response.setPaySign(paySign); return response; } else { throw new RuntimeException(微信支付下单失败: result.get(return_msg)); } } }6.2 前端支付调用小程序端调用微信支付接口// pages/pay/pay.js Page({ data: { amount: 0, orderInfo: null }, onLoad(options) { this.setData({ amount: options.amount }); this.createOrder(); }, createOrder() { wx.request({ url: https://your-domain.com/api/payment/create, method: POST, header: { Authorization: wx.getStorageSync(token), Content-Type: application/json }, data: { amount: this.data.amount }, success: (res) { if (res.data.success) { this.setData({ orderInfo: res.data.data }); } } }); }, handlePayment() { const orderInfo this.data.orderInfo; wx.requestPayment({ timeStamp: orderInfo.timeStamp, nonceStr: orderInfo.nonceStr, package: orderInfo.package, signType: orderInfo.signType, paySign: orderInfo.paySign, success: (res) { wx.showToast({ title: 支付成功, icon: success }); setTimeout(() { wx.navigateBack(); }, 1500); }, fail: (res) { wx.showToast({ title: 支付失败, icon: error }); } }); } });7. 管理后台功能7.1 费用设置模块管理员可以设置不同宿舍的水电费用单价。// AdminController.java RestController RequestMapping(/api/admin) public class AdminController { Autowired private DormitoryService dormitoryService; PostMapping(/dormitory/rate) public Result updateRate(RequestBody RateUpdateRequest request) { try { dormitoryService.updateRate(request.getDormitoryId(), request.getWaterRate(), request.getElectricityRate()); return Result.success(更新成功); } catch (Exception e) { return Result.error(更新失败); } } } // DormitoryService.java Service public class DormitoryService { Autowired private DormitoryMapper dormitoryMapper; public void updateRate(Long dormitoryId, BigDecimal waterRate, BigDecimal electricityRate) { Dormitory dormitory dormitoryMapper.selectById(dormitoryId); if (dormitory ! null) { dormitory.setWaterRate(waterRate); dormitory.setElectricityRate(electricityRate); dormitoryMapper.updateById(dormitory); } } }7.2 数据统计功能提供数据统计接口方便管理员查看缴费情况。// StatisticsController.java RestController RequestMapping(/api/admin/statistics) public class StatisticsController { Autowired private StatisticsService statisticsService; GetMapping(/daily) public Result getDailyStatistics(RequestParam String date) { try { DailyStatistics stats statisticsService.getDailyStatistics(date); return Result.success(stats); } catch (Exception e) { return Result.error(获取统计失败); } } } // StatisticsService.java Service public class StatisticsService { Autowired private PaymentOrderMapper orderMapper; public DailyStatistics getDailyStatistics(String date) { DailyStatistics stats new DailyStatistics(); // 查询当日总缴费金额 BigDecimal totalAmount orderMapper.selectTotalAmountByDate(date); stats.setTotalAmount(totalAmount); // 查询缴费订单数 Integer orderCount orderMapper.selectCountByDate(date); stats.setOrderCount(orderCount); // 查询各楼栋缴费情况 ListBuildingStatistics buildingStats orderMapper.selectBuildingStatistics(date); stats.setBuildingStatistics(buildingStats); return stats; } }8. 系统部署与运维8.1 小程序发布流程小程序开发完成后需要提交审核发布代码上传在微信开发者工具中点击上传提交审核在微信公众平台提交版本审核发布上线审核通过后发布到线上环境8.2 服务端部署使用Docker容器化部署后端服务# Dockerfile FROM openjdk:8-jre-slim VOLUME /tmp COPY target/dormitory-payment-0.0.1-SNAPSHOT.jar app.jar ENTRYPOINT [java,-Djava.security.egdfile:/dev/./urandom,-jar,/app.jar]部署命令# 构建镜像 docker build -t dormitory-payment . # 运行容器 docker run -d -p 8080:8080 \ -e SPRING_DATASOURCE_URLjdbc:mysql://mysql-server:3306/dormitory \ -e SPRING_REDIS_HOSTredis-server \ dormitory-payment9. 常见问题与解决方案9.1 支付相关问题问题1支付签名错误原因参数顺序错误或密钥不正确解决方案检查签名算法确保参数按字典序排序问题2支付回调失败原因网络问题或证书配置错误解决方案检查服务器网络配置正确的SSL证书9.2 数据库连接问题问题数据库连接超时原因连接池配置不合理或网络延迟解决方案优化连接池参数增加超时时间设置# application.yml 数据库配置 spring: datasource: url: jdbc:mysql://localhost:3306/dormitory?useSSLfalse username: root password: your_password hikari: maximum-pool-size: 20 minimum-idle: 5 connection-timeout: 300009.3 微信登录问题问题获取openid失败原因appid和secret配置错误或网络问题解决方案检查微信开放平台配置确保网络连通性10. 性能优化建议10.1 数据库优化索引优化为常用查询字段添加索引查询优化避免SELECT *使用分页查询缓存策略使用Redis缓存热点数据10.2 前端优化图片优化压缩图片使用WebP格式请求合并合并API请求减少网络开销本地缓存合理使用本地存储10.3 后端优化异步处理使用异步处理耗时操作连接池优化数据库连接池配置负载均衡部署多实例使用负载均衡这个宿舍水电缴费小程序项目涵盖了微信小程序开发的完整流程从需求分析到系统部署每个环节都提供了详细的技术实现方案。在实际开发中还需要根据具体需求进行调整和优化特别是支付安全和数据一致性方面需要格外重视。对于计算机专业的毕业设计来说这个项目具有很好的实用性和技术深度既展示了前端界面设计能力也体现了后端业务逻辑处理能力。建议在实现基础功能后可以进一步扩展如数据可视化、智能提醒等高级功能提升项目的完整度和竞争力。
返回列表