新闻详情

新闻详情

首页 / 资讯中心 / 详情

SpringBoot+Layui+AI大模型:智能物业缴费管理系统开发实战

发布时间:2026/9/7 3:41:50来源:尧图网络
SpringBoot+Layui+AI大模型:智能物业缴费管理系统开发实战
在中小型小区和公寓场景里物业缴费并不只是“收钱”这么简单。前台需要登记业主信息、按月生成物业费和水电费账单、跟踪每一张账单是待缴、已缴还是逾期还要回答业主关于缴费金额、明细和渠道的咨询。这个流程如果靠 Excel 和微信群维护很容易出现账单遗漏、状态错乱和沟通成本高的问题。基于 SpringBoot 加 Layui 加 AI 大模型搭建一套智能物业缴费管理系统正好可以通过后端接口统一管理账单数据用 Layui 提供简洁的后台界面再借助大模型理解业主的自然语言提问让“查账、缴费、咨询”都能在一个系统里完成。这篇教程会带着你从数据库设计做到前端页面从后端接口调通到 AI 问答联调以毕业设计项目为例拆解每个模块的实现思路和踩坑点。1. 先想清楚这个系统要解决什么AI 从哪里切入1.1 核心业务业主、房屋、账单、缴费记录四条线物业缴费管理系统的业务主体并不复杂但数据关系比想象中多。系统至少要维护业主信息、房屋信息、收费项目和缴费单并且每次缴费还要留一条可追溯的记录。第一类是业主。业主是缴费主体一个业主可以拥有多套房屋所以业主表和房屋表是一对多关系。业主信息包括姓名、手机号、身份证号、入住时间等这些字段在后面生成账单、发送催缴通知时会反复使用。第二类是房屋。房屋是计费对象物业费往往按房屋面积算所以房屋表里要有面积字段还要有楼栋、单元、房号等位置信息。房屋和业主之间还要保留一个当前归属关系避免房屋出售后账单仍然发到旧业主名下。第三类是收费项目。物业公司会同时收多种费用例如物业费、垃圾清运费、停车费。收费项目表里要保存费率单位例如“每平方米每月多少钱”这样生成月账单时才能用面积乘单价得出金额。第四类是缴费单和缴费记录。缴费单是某一时间段内应收的费用例如 2025 年 3 月的物业费。每一张缴费单对应一个业主、一套房屋、一个收费项目包含账单编号、金额、状态、应缴日期。缴费记录则是用户实际支付后的流水记录支付渠道、支付时间、第三方流水号。缴费单与缴费记录是一对多关系因为同一张账单可能发生部分支付、退款或补缴。这四条数据线串起来后系统的核心链路就是管理员录入业主和房屋配置收费项目然后系统周期性生成账单业主在前台或管理后台看到账单并发起缴费缴费成功后账单状态更新同时生成一条缴费记录。如果账单超过应缴日期仍未支付系统把它标记为逾期方便后续催缴。1.2 AI 大模型不是替代功能而是降低查询门槛在传统物业系统里业主想查账单一般需要打电话给前台或者登录后台自己找菜单。前台人员每天会收到大量重复问题“我这个月物业费多少钱”“去年的缴费记录怎么查”“逾期会收滞纳金吗”。这些问题本身不难但会占用大量人工时间。AI 大模型在这个系统中的定位不是替代缴费按钮而是提供一个自然语言入口。业主可以像聊天一样输入“帮我查一下 3 号楼 2 单元 501 的当前欠费”系统先把这句话翻译成结构化查询条件再从数据库里查出账单数据最后把结果组织成一段容易读的回复。这个交互方式比教用户理解复杂菜单友好得多。从毕业设计角度看这个大模型功能非常适合作为项目亮点。一方面它确实解决了一个真实场景里的客服问题另一方面实现难度可控不需要重新训练模型只需要调好大模型接口、设计好提示词模板、把数据库中的账单上下文拼接给模型。这里要注意边界大模型目前不擅长直接访问数据库和执行事务。不要让它直接生成 SQL 后去查询否则会出现幻觉、权限问题和安全风险。更稳妥的做法是把大模型作为“意图解析”和“文案生成”的中间层由代码控制数据库操作模型只负责理解和润色回复。1.3 技术选型为什么是 SpringBoot Layui技术选型决定了项目开发速度和后续扩展空间。SpringBoot 是目前 Java Web 开发中最容易上手的后端框架它通过自动配置减少了大量 XML 配置内置 Tomcat配合 MyBatis-Plus 后操作 MySQL 非常直接。对毕业设计来说SpringBoot 能保证你在有限时间里把接口写出来并且面试时更容易解释原理。Layui 则是一个老牌的前端 UI 框架虽然现在前端框架很多但 Layui 仍然适合这种以表格、表单、弹窗为主的管理后台。它自带组件不需要额外引入 Bootstrap 全家桶也不需要写复杂的前端工程化配置。Layui 的table.render、layer.open、form.on可以快速把后端接口绑到页面上尤其适合没有专业前端开发经验的场景。AI 大模型部分使用 Spring AI 接入。Spring AI 是 Spring 官方推出的 AI 应用框架它把“模型调用、提示词模板、输出解析”封装成了类似 Spring 风格的 API。这样你可以用很短的代码对接 OpenAI 兼容接口也可以连接到本地部署的 Ollama 服务从而在校内演示时不依赖外部网络。2. 环境准备、项目骨架和关键依赖2.1 先区分学习环境和生产环境学习环境的目标是“最快跑通”生产环境的目标是“稳定、安全、可回滚”。本文后面给出的示例配置以学习环境为主但如果要发布上线至少要额外考虑支付真实性、日志留存、数据库备份、操作权限控制等问题。项目学习环境生产环境JDKJDK 17 或 21JDK 17 / 21统一版本数据库本地 MySQL 8.0MySQL 8.0 主从或云数据库大模型本地 Ollama 部署开源模型商用 API 或私有化部署支付模拟支付回调微信/支付宝官方支付配置文件写在本项目 application.yml放到配置中心或环境变量日志控制台输出文件日志 日志收集系统权限简单的登录校验RBAC 操作审计这个表也可以在答辩时作为“系统未来优化”的内容来展示。2.2 用 Spring Initializr 创建工程并补全依赖建议使用 Spring Initializr 创建基础工程选择 Java 17、Maven、Spring Boot 3.x依赖先不急着全选后面手动添加到pom.xml中这样可以避免版本冲突。下面是最小依赖集合包含 Web、MyBatis-Plus、MySQL 驱动、Lombok、Spring AI 和测试依赖?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version3.3.4/version relativePath/ /parent groupIdcom.example/groupId artifactIdproperty-fee/artifactId version1.0.0/version properties java.version17/java.version spring-ai.version1.0.0-M5/spring-ai.version /properties dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.7/version /dependency dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId scoperuntime/scope /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-model-openai/artifactId version${spring-ai.version}/version /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-test/artifactId scopetest/scope /dependency /dependencies /project这段配置里有几个关键点。Spring AI 的坐标已经从spring-ai-openai-spring-boot-starter调整为spring-ai-starter-model-openai且不同版本对应的 Spring Boot 版本不同。实际下载依赖前建议先到 Maven 中央仓库或 Spring AI 官方文档确认当前稳定版本。mysql-connector-j是 MySQL 8.0 之后的官方驱动坐标不需要再加旧版mysql-connector-java。2.3 分层结构与静态资源配置项目里建议按“实体层、Mapper 层、Service 层、Controller 层、配置层”分包。AI 相关的逻辑单独放到ai包中避免和后端业务混在一起。com.example.propertyfee ├── PropertyFeeApplication.java ├── common │ ├── Result.java │ └── GlobalExceptionHandler.java ├── config │ ├── MybatisPlusConfig.java │ └── WebConfig.java ├── controller │ ├── OwnerController.java │ ├── BillController.java │ ├── PayController.java │ └── ai/AiController.java ├── service │ ├── BillService.java │ ├── OwnerService.java │ └── ai/AiAssistantService.java ├── mapper │ ├── OwnerMapper.java │ ├── HouseMapper.java │ └── BillMapper.java ├── entity │ ├── Owner.java │ ├── House.java │ ├── FeeItem.java │ ├── Bill.java │ └── PaymentRecord.java └── dto ├── BillQueryDTO.java └── ChatRequest.javaLayui 的静态资源可以直接放在src/main/resources/static/layui目录下也可以使用 CDN。推荐把 Layui 下载到本地这样答辩演示时即使没有外网前端界面也照样能打开。static目录中的index.html作为后台主入口和后端同端口部署不需要处理跨域问题。3. 数据库设计与 MyBatis-Plus 实体映射3.1 五张核心表的字段设计先创建数据库然后用下面 SQL 建立核心表。为了演示方便字段没有做得特别复杂但已经能支撑业主、房屋、收费项目、账单、缴费记录五条主线。CREATE DATABASE IF NOT EXISTS property_fee DEFAULT CHARACTER SET utf8mb4; USE property_fee; DROP TABLE IF EXISTS payment_record; DROP TABLE IF EXISTS payment_bill; DROP TABLE IF EXISTS fee_item; DROP TABLE IF EXISTS house; DROP TABLE IF EXISTS owner; CREATE TABLE owner ( id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL COMMENT 业主姓名, phone VARCHAR(20) COMMENT 手机号, id_card VARCHAR(30) COMMENT 身份证号, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); CREATE TABLE house ( id BIGINT PRIMARY KEY AUTO_INCREMENT, owner_id BIGINT COMMENT 当前业主ID, building VARCHAR(20) COMMENT 楼栋, unit VARCHAR(20) COMMENT 单元, room VARCHAR(20) COMMENT 房号, area DECIMAL(10,2) COMMENT 建筑面积, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); CREATE TABLE fee_item ( id BIGINT PRIMARY KEY AUTO_INCREMENT, item_name VARCHAR(50) NOT NULL COMMENT 收费项目名称, unit_price DECIMAL(10,2) NOT NULL COMMENT 单价, price_unit VARCHAR(20) COMMENT 计费单位, enabled TINYINT DEFAULT 1 COMMENT 是否启用 ); CREATE TABLE payment_bill ( id BIGINT PRIMARY KEY AUTO_INCREMENT, bill_no VARCHAR(40) NOT NULL UNIQUE COMMENT 账单编号, owner_id BIGINT COMMENT 业主ID, house_id BIGINT COMMENT 房屋ID, fee_item_id BIGINT COMMENT 收费项目ID, total_amount DECIMAL(10,2) NOT NULL COMMENT 账单金额, status TINYINT DEFAULT 0 COMMENT 0待支付 1已支付 2已逾期, period_start DATE NOT NULL COMMENT 账期开始, period_end DATE NOT NULL COMMENT 账期结束, due_date DATE COMMENT 应缴日期, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ); CREATE TABLE payment_record ( id BIGINT PRIMARY KEY AUTO_INCREMENT, bill_id BIGINT NOT NULL COMMENT 账单ID, pay_amount DECIMAL(10,2) NOT NULL, pay_way VARCHAR(20) COMMENT 支付方式, transaction_id VARCHAR(64) COMMENT 交易流水号, pay_time DATETIME DEFAULT CURRENT_TIMESTAMP );账单表里特意加了due_date字段它用于判断账单是否逾期。很多同学只记录生成日期不设计应缴日期导致后面催缴和逾期判断没法做。这里也把bill_no设计成唯一索引避免重复生成重复账单。3.2 实体类和 Mapper 接口用 Lombok 简化实体 Getter 和 Setter。以Bill为例字段和数据库字段保持一致并使用 MyBatis-Plus 的注解映射表名和主键自增策略。package com.example.propertyfee.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; Data TableName(payment_bill) public class Bill { TableId(type IdType.AUTO) private Long id; private String billNo; private Long ownerId; private Long houseId; private Long feeItemId; private BigDecimal totalAmount; private Integer status; private LocalDate periodStart; private LocalDate periodEnd; private LocalDate dueDate; private LocalDateTime createTime; private LocalDateTime updateTime; }Mapper 接口只需继承BaseMapper常见的增删改查就有了不需要重复手写基本 SQL。package com.example.propertyfee.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.example.propertyfee.entity.Bill; import org.apache.ibatis.annotations.Mapper; Mapper public interface BillMapper extends BaseMapperBill { }3.3 配置 MyBatis-Plus 与分页插件在application.yml中配置数据源、MyBatis-Plus 的逻辑删除和驼峰映射server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/property_fee?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: Asia/Shanghai mybatis-plus: configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: id-type: auto分页插件需要单独写一个配置类package com.example.propertyfee.config; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); PaginationInnerInterceptor pagination new PaginationInnerInterceptor(DbType.MYSQL); pagination.setMaxLimit(100L); interceptor.addInnerInterceptor(pagination); return interceptor; } }分页插件的作用不是必须的但列表页一般都会分页。没有分页插件时调用Page对象虽然不报错但不会自动生成LIMIT语句。加了之后前端table.render的分页参数才能正确生效。4. 后端功能怎么拆账单生成、缴费确认、AI 问答4.1 缴费单生成接口把房屋和收费项目变成账单缴费单生成是整个系统的起点。一个比较实用的方式是“按房屋 费用项目 账期生成”。每次生成前先检查同一房屋、同一费用项目、同一账期是否已经存在账单避免重复生成。下面是BillService中最核心的生成逻辑package com.example.propertyfee.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.example.propertyfee.entity.Bill; import com.example.propertyfee.entity.FeeItem; import com.example.propertyfee.entity.House; import com.example.propertyfee.mapper.BillMapper; import com.example.propertyfee.mapper.FeeItemMapper; import com.example.propertyfee.mapper.HouseMapper; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; import java.util.UUID; Service public class BillService { private final BillMapper billMapper; private final HouseMapper houseMapper; private final FeeItemMapper feeItemMapper; public BillService(BillMapper billMapper, HouseMapper houseMapper, FeeItemMapper feeItemMapper) { this.billMapper billMapper; this.houseMapper houseMapper; this.feeItemMapper feeItemMapper; } public ListBill generateMonthlyBill(Long houseId, Long feeItemId, LocalDate periodStart, LocalDate periodEnd) { House house houseMapper.selectById(houseId); FeeItem feeItem feeItemMapper.selectById(feeItemId); if (house null || feeItem null) { throw new IllegalArgumentException(房屋或收费项不存在); } LambdaQueryWrapperBill wrapper new LambdaQueryWrapper(); wrapper.eq(Bill::getHouseId, houseId) .eq(Bill::getFeeItemId, feeItemId) .eq(Bill::getPeriodStart, periodStart) .eq(Bill::getPeriodEnd, periodEnd); Long count billMapper.selectCount(wrapper); if (count 0) { throw new IllegalArgumentException(该账期的账单已存在请勿重复生成); } BigDecimal amount feeItem.getUnitPrice().multiply(house.getArea()); Bill bill new Bill(); bill.setBillNo(BILL System.currentTimeMillis() UUID.randomUUID().toString().substring(0, 6)); bill.setOwnerId(house.getOwnerId()); bill.setHouseId(houseId); bill.setFeeItemId(feeItemId); bill.setTotalAmount(amount); bill.setStatus(0); bill.setPeriodStart(periodStart); bill.setPeriodEnd(periodEnd); bill.setDueDate(periodEnd.plusDays(10)); billMapper.insert(bill); ListBill result new ArrayList(); result.add(bill); return result; } }这段代码里要注意三点。金额计算必须使用BigDecimal不能用float或double。uuid只用于演示生产环境最好使用专门的单号服务。生成账单后要检查重复这个检查应放在数据库唯一约束和事务里一起处理不能只靠代码判断。4.2 缴费确认与状态翻转先查账单再更新记录缴费接口并不需要真正对接支付网关在毕业设计里可以用模拟支付回调来处理。核心流程是根据账单 ID 查询账单如果账单状态是“已支付”则直接返回失败避免重复缴费否则插入一条缴费记录再把账单状态改为“已支付”。package com.example.propertyfee.controller; import com.example.propertyfee.common.Result; import com.example.propertyfee.entity.Bill; import com.example.propertyfee.entity.PaymentRecord; import com.example.propertyfee.mapper.BillMapper; import com.example.propertyfee.mapper.PaymentRecordMapper; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.math.BigDecimal; RestController RequestMapping(/api/pay) public class PayController { private final BillMapper billMapper; private final PaymentRecordMapper paymentRecordMapper; public PayController(BillMapper billMapper, PaymentRecordMapper paymentRecordMapper) { this.billMapper billMapper; this.paymentRecordMapper paymentRecordMapper; } PostMapping(/mock) Transactional(rollbackFor Exception.class) public Result mockPay(RequestParam Long billId, RequestParam String payWay) { Bill bill billMapper.selectById(billId); if (bill null) { return Result.error(账单不存在); } if (bill.getStatus() 1) { return Result.error(该账单已支付请勿重复操作); } PaymentRecord record new PaymentRecord(); record.setBillId(billId); record.setPayAmount(bill.getTotalAmount()); record.setPayWay(payWay); record.setTransactionId(MOCK System.currentTimeMillis()); paymentRecordMapper.insert(record); bill.setStatus(1); billMapper.updateById(bill); return Result.ok(缴费成功); } }Transactional保证“插入缴费记录”和“更新账单状态”要么同时成功要么同时回滚。如果漏掉这个注解一旦第二步出现异常就会出现账单已经标记为已支付但找不到任何缴费记录的脏数据。4.3 用 Spring AI 接入大模型本地 Ollama 也能跑Spring AI 可以对接 OpenAI 兼容协议。这里选择先配置一个本地 Ollama 地址因为 OLLama 支持以v1接口方式暴露本地模型例如qwen2.5:7b。只需要把base-url指到本地端口api-key随意填写就能在演示环境中调用。spring: ai: openai: base-url: http://localhost:11434/v1 api-key: ollama chat: options: model: qwen2.5:7b在代码中使用ChatClient生成 AI 回复。ChatClient.Builder是 Spring AI 1.0 中推荐的入口。package com.example.propertyfee.service.ai; import org.springframework.ai.chat.client.ChatClient; import org.springframework.stereotype.Service; Service public class AiAssistantService { private final ChatClient chatClient; public AiAssistantService(ChatClient.Builder builder) { this.chatClient builder.build(); } public String chat(String userMessage) { return chatClient.prompt() .system(你是一名物业客服助手只能根据提供的账单上下文回答问题不要编造数据。) .user(userMessage) .call() .content(); } }调用前要确认本地模型名称真实存在。Ollama 安装后可以通过ollama list查看已下载模型。如果模型名写错Spring AI 会返回 HTTP 404 或模型不存在错误。这个功能可以作为毕业设计的亮点但也要在答辩前准备好模型现场不要临时下载。4.4 用提示词和账单上下文提高回答准确率大模型不知道数据库里有什么数据所以要把“账单查询结果”拼到提示词里。一个可行的方式是后端先识别业主和房屋信息再去数据库查询最近账单最后把账单内容转成文本让模型生成自然语言回复。public String answerBillQuestion(String ownerName, String question) { // 1. 根据业主姓名查询房屋和账单 ListBill bills billMapper.selectRecentBillsByOwnerName(ownerName); // 2. 把账单拼成上下文 StringBuilder context new StringBuilder(); for (Bill bill : bills) { context.append(账单编号).append(bill.getBillNo()) .append(金额).append(bill.getTotalAmount()) .append(状态).append(bill.getStatus() 0 ? 待支付 : 已支付) .append(账期).append(bill.getPeriodStart()).append( 至 ).append(bill.getPeriodEnd()) .append(\n); } String systemPrompt 你是物业缴费系统的客服助手。 请根据下面的账单数据回答业主的问题只能引用给定数据不要编造。 账单数据 %s .formatted(context); return chatClient.prompt() .system(systemPrompt) .user(question) .call() .content(); }这里需要扩展BillMapper编写一个连表查询方法。也可以在查询到业主和房屋后分多次查询毕业设计里优先保证理解难度。提示词加入上下文的效果远比“开放式问答”更好因为模型有了明确的数据边界不会编造一个不存在的账单金额。5. Layui 前端页面表格、弹层和 AI 助手窗口5.1 页面布局侧边栏、顶栏、内容区管理后台采用经典布局左侧菜单、顶部标题栏、右侧内容区。Layui 的layui-layout可以快速实现这个结构。!DOCTYPE html html langzh head meta charsetUTF-8 title智能物业缴费管理系统/title link relstylesheet href/layui/css/layui.css /head body div classlayui-layout layui-layout-admin div classlayui-header div classlayui-logo智能物业缴费管理系统/div /div div classlayui-side layui-bg-black div classlayui-nav-tree lay-filtermenu a classlayui-nav-item lay-href/pages/bill.html i classlayui-icon layui-icon-form/i 账单管理 /a a classlayui-nav-item lay-href/pages/ai.html i classlayui-icon layui-icon-chat/i AI 助手 /a /div /div div classlayui-body iframe src/pages/bill.html idcontentFrame stylewidth:100%;height:100%;border:0;/iframe /div /div script src/layui/layui.js/script /body /html这里使用iframe嵌入子页面简单直接。也可以使用 JS 动态切换div内容但 iframe 的隔离性更好子页面之间不会互相污染变量。实际项目中如果需要更好的性能可以改成前后端分离或使用模板路由但毕业设计用 iframe 足够。5.2 用 table.render 渲染账单列表账单列表页是系统最核心的页面。Layui 的table.render会自动请求后端接口并把返回的data渲染到表格。table idbillTable lay-filterbillTable/table script typetext/html idbillStatusTpl {{# if(d.status 0){ }} span stylecolor: orange;待支付/span {{# } else if(d.status 1){ }} span stylecolor: green;已支付/span {{# } else { }} span stylecolor: red;已逾期/span {{# } }} /script script typetext/html idbillOperateTpl {{# if(d.status 0){ }} a classlayui-btn layui-btn-xs lay-eventpay缴费/a {{# } }} /script对应的 JSlayui.use([table, layer, form], function () { var table layui.table; var layer layui.layer; table.render({ elem: #billTable, url: /api/bill/page, page: true, cols: [[ {field: billNo, title: 账单编号, minWidth: 160}, {field: ownerName, title: 业主, minWidth: 100}, {field: itemName, title: 收费项目, minWidth: 120}, {field: totalAmount, title: 金额}, {field: status, title: 状态, templet: #billStatusTpl, minWidth: 100}, {title: 操作, toolbar: #billOperateTpl, minWidth: 100} ]], parseData: function (res) { return { code: res.code, msg: res.msg, count: res.data.total, data: res.data.records }; } }); table.on(tool(billTable), function (obj) { var data obj.data; if (obj.event pay) { layer.confirm(确认完成该账单的模拟支付, function (index) { $.post(/api/pay/mock, {billId: data.id, payWay: mock}, function (res) { if (res.code 0) { layer.msg(缴费成功); table.reload(billTable); } else { layer.msg(res.msg); } }); layer.close(index); }); } }); });这里最容易出错的是parseData。Spring Boot 后端如果返回统一结构{code: 0, msg: , data: {records, total}}必须通过parseData转成 Layui 需要的{code: 0, msg: , count: total, data: records}。如果漏写parseData表格会出现“数据异常”或空白列表。5.3 缴费操作和弹窗表单弹窗一般用于新增业主、维护房屋信息。以新增业主为例使用layer.open打开内容页再用form.on(submit)监听提交。$(#addOwnerBtn).on(click, function () { layer.open({ type: 1, title: 新增业主, area: [500px, 400px], content: $(#ownerFormHtml).html(), success: function () { // 重新渲染下拉框等动态表单控件 form.render(); } }); }); form.on(submit(ownerSubmit), function (data) { $.post(/api/owner/add, data.field, function (res) { if (res.code 0) { layer.closeAll(); table.reload(ownerTable); } else { layer.msg(res.msg); } }); return false; });弹窗表单 HTML 可以先隐藏在普通script标签里用 ID 取出来。这种方式代码简单适合页面不多的后台系统。5.4 预留 AI 助手聊天窗口AI 助手页面可以做成一个简单的聊天窗口底部是输入框上方是对话区域。前端把用户问题提交到/api/ai/chat后端返回回答。div idchatBox styleheight: 500px; border: 1px solid #ccc; overflow: auto; padding: 10px;/div div stylemargin-top: 10px; display: flex; input idquestionInput classlayui-input placeholder输入问题例如5号楼302还欠多少钱 button idsendBtn classlayui-btn stylemargin-left: 10px;发送/button /div$(#sendBtn).on(click, function () { var question $(#questionInput).val(); if (!question) { return; } $(#chatBox).append(div stylemargin-bottom:8px;b我/b question /div); $.post(/api/ai/chat, {message: question}, function (res) { if (res.code 0) { $(#chatBox).append(div stylemargin-bottom:8px;bAI/b res.data /div); } else { $(#chatBox).append(div stylecolor:red; res.msg /div); } $(#questionInput).val(); $(#chatBox).scrollTop($(#chatBox)[0].scrollHeight); }); });前端代码要特别注意 XSS 问题。如果直接把大模型返回内容插入页面模型被恶意提问时可能返回包含 HTML 脚本的内容。演示环境还好生产环境必须对回复内容做 HTML 转义或使用富文本安全过滤。6. 运行联调与结果验证6.1 初始化数据库与启动后端启动前依次执行以下操作本地启动 MySQL 并执行建表 SQL确认application.yml中数据库账号密码正确然后执行 Spring Boot 启动命令。mvn spring-boot:run启动成功后控制台会出现 Spring Boot 的 Banner并打印 Tomcat 端口。如果使用了 MyBatis-Plus 的日志配置执行 SQL 时会打印实际查询语句方便调试。验证后端接口可以使用浏览器直接访问http://localhost:8080/api/bill/page?current1size10接口返回 JSON 说明后端已经正常运行。6.2 前端操作路径从新增业主到 AI 查账整个系统按下面的流程走一遍能覆盖主要功能在业主管理页面新增一个业主并给业主添加房屋信息。在收费项目页面添加“物业费”设置单价为 2.5 元/平方米/月。在账单管理页面选择房屋和收费项目设置账期为当月点击生成账单。列表中会出现一条待支付账单点击“缴费”完成模拟支付。再次进入 AI 助手页面输入“查一下该业主最近欠费情况”确认模型能返回账单摘要。如果 AI 服务没启动第 5 步会失败但前面 4 步都应该正常。这说明系统拆分为核心业务和 AI 增强两部分即使临时去掉 AI 也不会影响缴费主流程。6.3 接口返回结构与自测清单后端统一返回结构建议设计成{ code: 0, msg: success, data: {} }分页列表返回数据放在data内部{ code: 0, msg: success, data: { records: [], total: 0, current: 1, size: 10 } }自测时可以准备一张检查表测试项输入预期结果生成账单房屋存在费用项存在账期无重复生成一条待支付账单重复生成同一房屋、同一费用项、同一账期再次生成返回“账单已存在”模拟缴费传入待支付账单 ID账单状态变为已支付重复缴费再次缴费同一账单返回“已支付请勿重复操作”查询不存在账单传入不存在 ID返回“账单不存在”AI 问答输入“物业费是多少”根据提示词上下文给出回复7. 常见问题排查从前端 404 到大模型调用失败7.1 Layui 表格数据格式不对导致无法渲染现象是页面表格一直“加载中”或者提示“数据异常”。先打开浏览器 F12 看接口返回如果接口本身返回了数据但 Layui 表格不显示通常是因为返回结构与 Layui 默认结构不一致。Layui 默认期望code: 0, msg: , count: 总数, data: 数据数组而 Spring Boot 分页接口返回的是{records, total}。解决办法就是在table.render里加parseData做一次转换。问题现象常见原因检查方式处理建议表格空白返回结构不对F12 查看接口响应增加 parseDataHTTP 404Controller 路径或静态路径错误检查请求 URL确认RequestMapping路径HTTP 500SQL 异常或空指针看后端控制台日志修复 Mapper 或判空逻辑7.2 跨域、路径和静态资源问题如果后端接口能通但页面样式或脚本加载不了优先检查静态资源路径。Layui 文件放在static/layui下访问地址应该写/layui/layui.js注意不要写classpath:或static/前缀。如果采用前后端分离部署前端端口是 8081后端端口是 8080需要在后端写一个 WebMvcConfigurer 配置跨域package com.example.propertyfee.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; Configuration public class WebConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/api/**) .allowedOrigins(*) .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*); } }毕业设计里更推荐把前端静态资源放进后端直接同端口访问省掉跨域这层麻烦。7.3 Spring AI 接入失败与版本兼容问题Spring AI 是一个更新较快的框架常见问题集中在版本和配置两个方向。如果项目启动时提示找不到ChatClient类先检查spring-ai-starter-model-openai是否真的引入成功以及版本是否和 Spring Boot 兼容。Spring AI 的 Maven 版本早期是1.0.0-M*不同版本包名和 API 有差异。这里给出的代码适合1.0.0-M5或相近版本如果你使用更新版本请以上下文中的类名和官方示例为准。如果启动正常但调用模型时报 404检查base-url是否指向/v1结束。本地 Ollama 地址是http://localhost:11434/v1如果写成http://localhost:11434Spring AI 会拼接出错误的 API 路径。如果调用超时检查本地模型是否已经加载到内存。第一次调用会有一个模型加载过程响应会比较慢。可以提前用ollama run qwen2.5:7b命令加载模型再通过 Spring Boot 调用。7.4 数据一致性问题重复缴费和并发更新模拟缴费接口如果不加判断连续点击两次“缴费”可能生成两条支付记录。这里有三个层面的保护第一代码层在mockPay中先查状态再更新状态。第二数据库层给payment_bill的status字段加约束或通过乐观锁更新。第三事务层使用Transactional保证记录和状态更新原子性。毕业设计阶段做到第一、第三层就够了但答辩时如果能说出“生产环境应使用乐观锁或 Redis 分布式锁防止并发重复支付”会是很好的加分项。// 使用乐观锁示例更新时带上 status 0 条件 int updated billMapper.update(null, new LambdaUpdateWrapperBill() .eq(Bill::getId, billId) .eq(Bill::getStatus, 0) .set(Bill::getStatus, 1));如果updated 1说明只有当前请求成功更新如果updated 0说明账单已经被其他请求更新过直接返回“账单已支付”。8. 毕业设计答辩与生产化扩展建议8.1 最小可演示范围先把主链路跑通如果时间紧张请优先完成以下主链路而不是追求功能数量业主和房屋信息的维护。收费项目配置。根据房屋和收费项目生成当月账单。模拟缴费和状态更新。账单列表的分页展示。AI 智能问答能回答“某业主的欠费情况”。这条链路覆盖了管理系统的核心 CRUD、业务规则、分页查询和 AI 应用。答辩时按照这条链路演示评审老师能快速理解系统价值。其他功能如数据导入导出、滞纳金计算、权限模块可以放到论文的“未来展望”中不必全部实现。8.2 再往后可以扩展的方向系统完成基础功能后可以从几个方向做深度扩展扩展方向实现思路微信小程序端复用后端 Controller新增小程序页面缴费定时任务每月 1 日自动生成账单到期自动标记逾期消息通知使用 Spring Task 或 XXL-Job 发送催缴短信/站内信数据可视化使用 ECharts 展示月度收缴率、欠费排行RAG 知识库把物业规章制度、公告文档作为向量知识库提升 AI 回答准确性真正接入支付对接微信支付 Native/JSAPI替换模拟回调8.3 答辩展示时的重点与注意事项答辩时要先讲业务痛点再讲系统设计最后做功能演示。演示前一定要检查模型服务是否已启动、数据库是否恢复干净状态、端口是否被占用。如果 AI 功能现场依赖外网模型一旦网络波动就会卡在演示环节推荐使用本地部署模型。代码和配置可以在论文中作为关键模块展示但不要贴整段源码。重点画清楚三个模块账单生成流程、模拟支付流程、AI 提示词拼接流程。评审更关心你是否理解“为什么要这样设计”而不是代码行数多少。本项目的最大亮点是 AI 与业务结合的方式。你不需要强调大模型多强大而是要说明在你的系统里大模型如何通过结构化上下文降低业主查账门槛以及你为了安全让模型只回答给定账单数据。这个设计思路比单纯调一个 API 更有说服力也是后续做智能客服、智能运维、企业知识库时值得复用的通用模式。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

酒店管理系统多端联动实战:从架构到排坑的完整记录 2026/9/7 4:11:56

酒店管理系统多端联动实战:从架构到排坑的完整记录

简介:一套开箱即用的酒店管理系统,完整覆盖后台管理、官方网站与微信小程序三大版块,面向中小型酒店及民宿运营者,解决房态管理、订单流转、餐饮预订与移动支付等日常经营问题,适合需要快速上线数字化系统的团队参考或…

阅读更多 →
数据结构大作业实战:C语言构建教务管理系统全解析 2026/9/7 4:11:56

数据结构大作业实战:C语言构建教务管理系统全解析

简介:面向高校数据结构课程设计的一份完整教务管理系统实现,包含教师端、学生端与教务员端三大模块,能够覆盖学生信息管理、课程维护、选课处理等常见教务场景,适合完成数据结构课程后需要撰写大作业或课程设计的本科学生参考。压…

阅读更多 →
相位梯度超表面:从广义斯涅耳定律到10GHz波束偏转设计 2026/9/7 4:11:56

相位梯度超表面:从广义斯涅耳定律到10GHz波束偏转设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
不会电脑也能用!手机扫码云进销存选型指南 2026/9/7 4:11:56

不会电脑也能用!手机扫码云进销存选型指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
基于Spring Boot的转账系统:事务、幂等与并发控制实践 2026/9/7 4:11:56

基于Spring Boot的转账系统:事务、幂等与并发控制实践

简介:这是一份用于教学演示的模拟银行账户转账系统源码,面向正在学习图形界面编程和多线程开发的初学者。系统设有两个初始余额为一千元的账户,随机向对方转账,转账金额不能超过当前余额,余额为零则停止交易&#xff1…

阅读更多 →
career-ops 西班牙语模式深度解析:modes/es/_shared.md 如何用“事实源 + 防虚构护栏 + 西语市场规则”约束 AI 求职 Agent 2026/9/7 4:08:55

career-ops 西班牙语模式深度解析:modes/es/_shared.md 如何用“事实源 + 防虚构护栏 + 西语市场规则”约束 AI 求职 Agent

career-ops 西班牙语模式深度解析:modes/es/_shared.md 如何用“事实源 防虚构护栏 西语市场规则”约束 AI 求职 Agent 【免费下载链接】career-ops Open-source AI job search: scan job portals, evaluate listings into a structured A-H report with a global…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞