ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

微信小程序物业管理系统:Spring Boot三角色权限与报修全流程解析

微信小程序物业管理系统:Spring Boot三角色权限与报修全流程解析

简介:这是一套基于微信小程序的小区物业管理系统毕业设计资料包,面向计算机相关专业学生与初级Java开发者,可用于课程设计或毕业设计参考。系统完整覆盖管理员、物业管理员、业主三类角色:管理员负责用户信息管理,物业端处理卫生记录、停车位查询、维修与缴费、公告发布及安保人员管理,业主端支持公告查看、报修提交、满意度反馈、车位与物业费查询等。压缩包共402个文件,其中Java源码与接口约67个,小程序前端包含31个wxml、117个wxss及40个js文件,另有95个xml配置、34个json数据和1个sql数据库脚本,包体仅726KB,目录结构清晰,便于部署与二次开发。资源还附带毕业论文文档及项目说明,能帮助读者快速理解小程序与Java后台的联调逻辑。目前已有380人学习下载,适合需要完整前后端闭环方案、希望直接参考实现细节的毕业设计人群。

1. 微信小程序物业管理系统:不是简单的增删改查,是三套权限逻辑的落地

在你接手一套基于微信小程序的小区物业管理系统时,真实场景里的核心诉求不是“做个登录页”,而是:业主报修了,维修单多久能流到物业侧?缴费记录是不是还靠表格人工对账?满意度调查是不是纸质统计?这套毕设源码把这三件事串成了闭环——前端微信小程序面向业主和物业,后端 Java 接口面向管理员,源码包里除了可运行的工程代码,还附带设计文档和论文框架。它适合两类人:准备毕业答辩的开发者,以及想搞清小程序端与 Java 后端如何真正配合的前端新人。接下来按架构、后端、联调、避坑、演示逐层拆它。

2. 架构与权限边界:Spring Boot 后端与三类角色的数据隔离

2.1 前后端分离结构:小程序的“端”和 Java 的“端”怎么分工

小程序端和 Java 后端,在这套系统里是彻底分离的两个工程。后端是 Spring Boot 风格的 Maven 工程,项目根目录下的 wuye.iml 说明它是用 IntelliJ IDEA 建出来的,.gitignore 里一般屏蔽了 target 目录和本地配置,拉下来不用管这部分。前端则是微信开发者工具里直接导入的小程序目录,页面、逻辑、样式都是独立一套,运行时通过 HTTP 访问后端接口拿数据。

数据流向很直接:小程序端负责采集用户行为,比如业主填报修单、点提交按钮;后端负责校验数据、读写数据库、把业务状态返回给页面。以报修为例,业主在小程序里传图片、选故障类型,后端收到后把内容落库,并把工单状态置为“待处理”;物业管理员登录后拉取全部待处理工单,点击处理完成,状态再回写。整个过程里,小程序端不做任何业务判断,所有权限校验都在后端接口层完成。

后端模块从源码上看分得很清楚:RepairApi 是报修接口,UserApi 负责用户登录与个人信息,PersonApi 管理安保人员,QueAndOpt 是业主需求管理,Vote 是满意度调查的业务类。它们共用的底层是同一套数据库连接和实体映射。动手跑之前,我一般建议先把 MySQL 里建好库,再改 application.yml 里的连接串,否则接口会直接超时。

这套系统的核心数据表可以按下表理解,字段不追求全,够业务闭环就行:

表名关键字段作用
useruid, username, password, role, house_id三类账号统一存一张表,role 区分 0/1/2
repairrepair_id, uid, type, content, image, status业主报修工单,status 控制流转
feefee_id, house_id, amount, period, status物业费、水费、电费统一按户存
noticenotice_id, title, content, publisher公告,所有角色都可读
parkingparking_id, position, status车位占用情况
needneed_id, uid, type, content, status家政、上门清理等需求
votevote_id, uid, score, content满意度调查记录
guardguard_id, name, age, native_place, work_date安保人员信息

role 字段是整个系统的权限基石。业主账号 role=0,只能读写自己的数据;物业管理员 role=1,能处理业务单;系统管理员 role=2,拥有用户管理权限。数据隔离的实现不复杂,核心就是每个业务接口先取当前登录人身份,再决定 SQL 的查询范围和更新范围。

2.2 登录与权限控制:一次登录,三套菜单

毕设项目里登录一般不用真实微信授权换取 openid,最常用的方案是账号密码登录。小程序端先调 wx.login 拿不到业务身份,所以项目常见做法是提供一个独立登录页,输入用户名密码,后端校验后返回一个 token,小程序端把它存在 storage 里,后续每个请求在 header 里带上。token 的有效期不需要做太复杂,生成一个随机串或者 JWT 都行,重点是后端通过拦截器统一校验。

拦截器的实现,我习惯用一个简单的 HandlerInterceptor:

public class AuthInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getHeader("token"); if (token == null || token.isEmpty()) { response.setStatus(401); return false; } Integer uid = TokenStore.getUserId(token); if (uid == null) { response.setStatus(401); return false; } request.setAttribute("uid", uid); return true; } }

这段代码做的事很简单:从请求头里取 token,查不到或已过期就返回 401,在请求链路里放行。通过 request.setAttribute("uid") 把当前登录用户塞进上下文,后面的业务代码随时可以取。参数说明就三个关注点:header 名字前后端约好叫 token 而不是 Authorization;TokenStore 可以是 ConcurrentHashMap,毕设没必要上 Redis;拦截后要放行登录接口本身,否则会死循环。

登录授权完成后,前端展示的菜单是三套模板。业主端看到的是“公告列表、我要报修、车位信息、缴费查询、满意度调查、个人中心”;物业端多出“卫生记录、维修处理、缴费管理、需求列表、公告管理、安保人员管理”;系统管理员端单独有“用户管理”。菜单的显隐一般由小程序端的 role 变量用 wx:if 判断,但真正防止越权操作,必须靠后端接口里的角色校验,前端藏菜单只是体验层的优化。

3. 后端核心模块:建表思路与 Api 层业务的实现细节

3.1 实体设计与表关系:Repair、Vote、QueAndOpt 是怎么落表的

后端代码的可读性,很大程度上取决于实体类能不能直接对应业务语义。Repair.java 的作用是报修单的映射载体,字段命名和表字段保持驼峰一致,避免 XML 里写一堆 resultMap 映射。它的核心字段一般长这样:

private Integer repairId; // 工单编号 private Integer uid; // 提交报修的业主用户ID private String type; // 故障类型:水、电、门窗、设备 private String content; // 文字描述 private String image; // 现场图片路径 private Integer status; // 0待处理 1处理中 2已完成 private Date createTime; // 提交时间 private Date handleTime; // 处理完成时间

对应数据库里的 repair 表结构,逻辑上 uid 是外键,指向用户表的主键。查询的时候要连表把业主的楼栋房号和手机号带出来,方便物业联系。image 字段存的不是二进制,而是图片的相对路径,比如 /upload/repair/20250601_xxx.png,前端拿这个路径拼接后展示。

Vote.java 对应满意度调查。字段不需要多,uid、score、content、createTime 四个就够。设计上要注意一点:一次调查周期里每个业主通常只能提交一次,后端在 insert 之前先按 uid 和调查批次查一遍,存在记录就用 update 覆盖或直接拒绝。这个逻辑在 Api 层做,而不是靠数据库唯一索引,因为表结构里未必预留了批次字段。

3.2 Api 层业务逻辑:报修工单怎么从提交走到完成

RepairApi.java 是这套系统业务量最大的一块接口,它至少要承担三个动作:业主提交维修、业主查看自己的报修列表、物业管理员处理工单。

@RestController @RequestMapping("/repair") public class RepairApi { @PostMapping("/add") public Result addRepair(@RequestParam String type, @RequestParam String content, @RequestParam(required = false) String image, @RequestAttribute("uid") Integer uid) { Repair repair = new Repair(); repair.setUid(uid); repair.setType(type); repair.setContent(content); repair.setImage(image); repair.setStatus(0); repair.setCreateTime(new Date()); repairService.save(repair); return Result.success(); } @GetMapping("/list") public Result listRepair(@RequestParam("role") Integer role, @RequestAttribute("uid") Integer uid) { List<Repair> list; if (role == 1) { list = repairService.findAll(); // 物业看全部 } else { list = repairService.findByUid(uid); // 业主只看自己 } return Result.success(list); } }

addRepair 接口里几个参数要解释清楚。@RequestAttribute("uid") 是从拦截器里取到的当前登录人,前端传过来的 role 不可信,因为业主可以手动改请求参数,所以判断身份要拿 uid 关联 user 表查 role。rose 这个校验逻辑在 listRepair 里我简化成直接依赖 role 参数了,实际项目里应该从 token 对应的用户信息里取角色,这是安全底线问题,不能图省事。

物业端处理工单走的是另一个接口,更新 status 和 handleTime。但这个操作要根据工单状态做前置校验:只有 status=1 的工单可以流转到 2,已经是 2 的不允许重复修改;否则业主端看到的工单流转记录会乱掉。这类状态机校验是报修模块最容易踩坑的地方,多人反复测试后状态就错乱了。

费用模块的建议设计是:缴费表按“户”聚合而不是按“人”。物业管理员按楼栋楼号查询所有未缴记录,业主端按 house_id 查自己的账单。账单类型用 type 字段区分物业费、水费、电费,金额字段用 BigDecimal 而不是 double,钱的东西用浮点类型后面对账会出玄学误差。

满意度调查的统计逻辑更简单:把该小区所有投票记录的 score 取平均,展示最近一个周期。源码里的 Vote.java 提供的是单条记录的增删改查,统计报表一般自己写一条 SQL:

SELECT ROUND(AVG(score), 1) AS avg_score, COUNT(*) AS total FROM vote WHERE create_time BETWEEN DATE_SUB(NOW(), INTERVAL 7 DAY) AND NOW()

这段 SQL 返回最近七天的平均分和样本量。注意 AVG 会返回多位小数,ROUND 后保留一位即可。样本量大于 30 份才有参考意义,答辩时候这个点可以展开讲,比较出彩。

4. 小程序端页面与联调:从 request 封装到维修、缴费两条主链路

4.1 小程序工程组织与全局请求封装

小程序端的目录结构,常见划分是 pages 下按角色建文件夹:pages/owner 放业主页面,pages/admin 放物业和管理员页面,utils 放公共方法。后端登录返回的 token 存在 wx.setStorageSync 里,请求前统一取出。

我一般会在项目里放一个 utils/request.js,把 wx.request 包一层 Promise:

const BASE_URL = 'http://192.168.1.100:8080'; 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) => { if (res.statusCode === 401) { wx.redirectTo({ url: '/pages/login/index' }); reject(res); return; } if (res.data.code === 200) { resolve(res.data.data); } else { wx.showToast({ title: res.data.msg, icon: 'none' }); reject(res); } }, fail: (err) => reject(err) }); }); } module.exports = { request };

BASE_URL 写开发机局域网 IP 而不是 localhost 的原因,是微信开发者工具模拟器里 localhost 指电脑本身没问题,但真机预览时 localhost 指向手机自己,根本连不上后端。这个坑几乎每个联调的人都会踩一遍,后面避坑章节再展开。header 里统一塞 token,后端拦截器就能统一校验,不用每个接口重复写。

小程序端每个页面的生命周期,推荐在 onLoad 里拉取列表数据,onPullDownRefresh 里做下拉刷新,提交按钮走完后端逻辑后重新拉一次。不要依赖跳转页面时用参数传递整个对象,因为小程序页面栈有内存压力,数据多时会卡顿,传 id 再回查是更稳的做法。

4.2 两条核心业务链路:提交报修与查看缴费

报修链路是这套系统的演示重点。业主在 pages/owner/repair 页面选故障类型、填描述、传图片,提交时先调用 wx.uploadFile 上传图片,拿到返回的图片路径后,再连同表单数据一起 POST 给 /repair/add。注意这两个动作是分开的,不能在一次请求里既传文件又传 JSON:

wx.uploadFile({ url: BASE_URL + '/upload', filePath: that.data.imagePath, name: 'file', success: (res) => { const imageUrl = JSON.parse(res.data).data; const form = { type: that.data.type, content: that.data.content, image: imageUrl }; request('/repair/add', 'POST', form).then(() => { wx.showToast({ title: '提交成功', icon: 'success' }); }); } });

这里有两个参数细节。name 字段必须和后端 MultipartFile 的形参名一致,比如后端写 @RequestParam("file") MultipartFile file,前端 name 就要是 file,不然后端直接报 400。filePath 在真机上是一个 wxfile:// 开头的临时路径,上传动作必须在页面未销毁前发起,如果跳转了页面再上传,路径失效,后端就收不到文件。

缴费链路的页面要展示未缴费项目和已缴费项目,通常用两个 tab 或者一个列表里加状态标签。后端返回的 fee 列表包含 amount、type、period、status 四个字段,前端渲染时定义一个映射对象,把物业费、水费、电费的 type 值换成中文;status 用 0/1 渲染成“未缴/已缴”。

const feeTypes = { 1: '物业费', 2: '水费', 3: '电费' }; data.list.forEach(item => { item.typeName = feeTypes[item.type]; item.statusText = item.status === 0 ? '未缴' : '已缴'; });

这段逻辑是典型的“前端做展示转换、后端不做”。不建议后端直接返回中文,因为中文类型字段后续做统计或导出时不方便;后端给数字、前端映射显示,是更合理的约定。联调时如果发现缴费列表不显示,优先检查返回里的字段名大小写,feeId 和 fee_id 这种差异是 JSON 序列化配置导致的,统一一下就好。

5. 部署与联调避坑:跨域、图片路径与角色状态的五个问题

5.1 真机预览连不上本地后端

现象:微信开发者工具模拟器里一切正常,数据都能拉取;一换到真机预览,页面全部白屏,控制台报 request:fail。

原因:开发者工具设置里勾了“不校验合法域名”,模拟器环境下绕过了域名校验;真机上没有这个选项,而且真机访问不了 localhost。BASE_URL 写的是 localhost 或 127.0.0.1 时,手机请求的是它自己。

解决:把 BASE_URL 改成电脑的局域网 IP,比如 192.168.x.x:8080,手机和电脑连同一个 WiFi。如果还不行,关掉系统防火墙的入站规则,或者在后端加跨域配置,因为 https 和 http 混用、协议不统一也会导致请求失败。

5.2 图片上传“成功”但后端没拿到文件

现象:上传调用返回了成功,但后端日志里打印的 MultipartFile 为 null,或者图片 URL 存进去之后页面加载显示破图。

原因:最常见的是 name 参数不匹配,前端 wx.uploadFile 里 name 写成了 image,后端的 @RequestParam 写成了 file;其次是小程序临时路径生命周期问题,先跳页面后上传导致路径过期。

解决:先看后端日志报不报 MissingServletRequestParameterException,报了就说明请求根本没带上文件流。把前后端的 name 改成一致,通常统一为 file。另外在上传接口里打印 MultipartFile.getOriginalFilename(),能看到文件名说明传输层没问题,往后排查就是存储路径和访问路径的拼接问题。

5.3 拦截器拦截后接口返回 401,角色状态对不上

现象:业主能正常登录,但一点报修按钮就弹登录过期;或者管理员登录后调用接口,后端判断角色不是管理员。

原因:token 存放在了 storage 里,但 request.js 封装时 header 名写错,或者后端拦截器用的 header 名字对不上;另一种可能,是登录接口本身没走拦截器白名单,导致登录时也返回 401,客户端判断为失败。

解决:打开开发者工具的 Network 面板,看请求 header 里到底有没有带 token。后端拦截器打印 request.getRequestURI(),把登录接口排除出拦截范围。角色不对的情况,一定要从后端根据 token 查用户信息,不能信任前端传的角色参数。

5.4 数据库中文乱码与字段大小写问题

现象:接口返回的数据英文正常,中文全是问号;或者 MyBatis XML 里写了 create_time,数据库字段是 createTime。

原因:数据库连接串没配置 characterEncoding=utf-8,或者数据库建表时默认字符集是 latin1;字段大小写问题多半是实体类里使用驼峰命名,数据库下划线命名,MyBatis 开启 camelCase 映射后写 XML 时漏了别名。

解决:连接串统一加 ?useUnicode=true&characterEncoding=utf8mb4,建表语句里显式指定 DEFAULT CHARSET=utf8mb4。字段问题最简单粗暴的办法是写 SQL 时全部用下划线风格并加别名,在 XML 里 resultMap 手动映射一遍,跑通之后再考虑全局配置。

5.5 业主改完信息后列表不刷新

现象:业主在个人中心修改手机号,返回上一页再进入,页面还是旧数据。

原因:小程序页面栈会缓存,onShow 没有重新拉数据,只是走了 onLoad 第一次渲染的逻辑。

解决:在个人信息的 onShow 生命周期里重新调用接口拉用户信息,而不是依赖 onLoad。前端更新之后,后端要确认改了之后返回给前端的是更新后的完整对象,而不是只返回一个成功标识,后者会导致前端拿不到新数据。

6. 答辩演示与数据验证:把物业系统跑顺的一套实操脚本

这套代码最怕的不是跑不通,是演示时数据太假、流程断档。我习惯在答辩前准备三组固定账号,用真实数据把链路走一遍。

步骤操作预期结果
1业主账号登录,提交一条带图片的报修单列表出现待处理状态
2物业账号登录,把该单状态改为处理中业主端状态同步变化
3物业发布一条公告业主端公告列表可见
4系统管理员新增一个安保人员业主端安保人员信息可查
5业主填写满意度调查后端统计平均分更新
6业主提交家政需求物业需求列表出现匹配记录

演示顺序要有讲究。先演示报修闭环,这是业务强度最高的链路,图片上传、状态流转、权限隔离都涉及;再演示缴费查询和满意度调查,数据是静态的,不容易出意外。最后打开数据库管理工具,把 repair 表里记录改前改后的 status 变化现场指给导师看,这一手比口头讲解“状态流转”有说服力得多。

验证方法补充两个细节:一是准备一个错误的 token 去请求接口,现场演示 401 拦截效果,把权限边界展示出来;二是用同样的业主账号去调物业接口,让导师亲眼看到返回无权限,这个比任何讲稿都直观。

这套源码包里已经带了设计文档和论文框架,只要把表结构和接口说明对应上,答辩的“系统设计”环节不需要额外发挥。可复现是它的价值,我因为之前接过类似的定制需求,被这种项目坑过几轮,从那以后每次部署完都会强制走一遍“业主报修→物业处理→业主缴费→满意度反馈”的完整链路。希望帮到你,省下联调的半天时间。

本文还有配套的精品资源,点击获取

返回列表