ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

基于Web的房屋销售管理系统:设计思路、表结构与RBAC权限模型全解析

2026/10/1 16:30:30 拓冰建站 浏览量
基于Web的房屋销售管理系统:设计思路、表结构与RBAC权限模型全解析 说到基于Web的房屋销售管理系统这应该是计算机专业毕业设计里最经典的几个题目之一了。我当年自己也做过类似的系统这两年也帮学弟学妹们看过不少版本Java、PHP、Python三套技术栈都有接触过。这项目看起来是“房屋销售管理”六个字但真正动手做起来业务逻辑、表结构设计、权限控制、数据统计这些环节每个地方都有坑。今天这篇就把这套系统的设计和实现从头到尾拆开揉碎讲清楚。不管你是准备自己写毕业设计还是想接这种定制开发的活儿都能少走不少弯路。1. 项目整体设计与需求拆解1.1 核心需求解析房屋销售管理系统本质上是一个围绕“房源”和“客户”两个核心对象展开的业务管理系统。你把它拆开来看无非就是几个事房子从哪来、客户从哪来、房子怎么卖出去、卖出去之后怎么统计。所以功能模块一定绕不开这几个房源管理录入新房源、修改房源信息、房源上下架、条件检索房源客户管理客户档案建档、跟进记录、客户意向等级销售流程预约看房、成交登记、合同信息、付款记录统计分析成交数据统计、销售业绩排行、房源去化率系统管理用户登录、角色权限、操作日志很多新手一开始会忽略一个关键点这个系统的主角不是“管理员”一个角色而是至少要有两种角色——管理员和销售人员。管理员管房源、管人员、看全局数据销售人员管自己的客户、录自己的跟进记录。如果我用管理员账号登录却看不到一线销售每天具体接了多少客户那我做这个系统的意义就少了一半。1.2 角色划分与权限边界做权限设计的时候很多人直接用一张用户表加一个role字段就完事了。这种方案在小项目里能用但后患很大。我建议至少用三张表sys_user用户、sys_role角色、sys_user_role用户角色关联再抽象出一套菜单权限或按钮权限的控制逻辑。实际操作为什么要这么麻烦因为你在答辩的时候老师大概率会问“不同角色的用户登录后看到的东西为什么要不一样”。这个问题直接考察你对权限模型的理解程度。用简单的字段区分你能解释的深度有限用RBAC模型你可以很自然地扯到“用户-角色-权限”三层解耦再配合一个拦截器在后台做统一校验整体逻辑就清晰很多。我实际在项目里是这样划分的功能项管理员销售员房源管理增删改查全部权限仅查看和登记成交客户管理查看全部客户仅操作自己的客户成交登记可修改可删除仅新增统计报表可见全部数据仅见个人数据用户管理全部权限无权限这个表看着简单但每一行背后都是要写对应权限判断的。别偷懒用隐藏按钮的方式来控制权限后端接口必须做校验不然伪造请求就能拿到数据。1.3 业务流程设计业务流程上房屋销售最核心的一条链路是房源录入 → 客户登记 → 预约看房 → 意向跟进 → 成交签约。这条链路里的每一步前后端都要有对应操作入口数据流也是沿着这条链路走的。我见过有不少人做的系统房源和客户之间完全没有关系房子是房子客户是客户成交记录更是无从谈起。这种系统做得再花哨答辩的时候也会被问住你的房源和客户的关联体现在哪所以设计阶段就要明确至少要有一个“意向登记”或者“预约看房”的关联表把房源ID和客户ID挂在一起后续的跟进记录、成交记录才能顺势串起来。2. 技术选型与开发环境准备2.1 编程语言和框架怎么选标题里写到了Java、PHP、Python、C#那我把这四个方向展开说说。作为毕设项目选哪个技术栈决定了你后面三个月的日子好不好过。如果你选了Java主流方案是Spring Boot Spring MVC MyBatis-Plus MySQL。这套组合的优点是网上资料多得吓人基本你踩到的每一个坑都有人踩过缺点是Spring家族体系庞大新手容易在环境配置上栽跟头。建议用Spring Boot 2.7或3.2的稳定版别追最新版本。选PHP的话ThinkPHP框架是国内毕设的老朋友了自带ORM和模板引擎开发速度极快。它的坑在于PHP版本和框架版本的兼容性问题比如ThinkPHP 5不支持PHP 8的新特性你得保证环境版本匹配。如果是PHP 8那就用ThinkPHP 8或者Laravel 10。选Python那就是Django或Flask二选一。Django自带Admin后台很多管理功能几乎开箱即用配合DRF做接口也顺手。Flask更轻适合你只想做后端接口、前端完全独立的方案。但是注意在“管理系统”这种重表单、重列表的项目里Python不是效率最高的选择后期做统计图表时你得多依赖前端库。C#配ASP.NET Core的组合在Windows环境里很舒服Visual Studio一把梭调试体验比其他三门语言好一大截。如果你是Windows电脑用C#做反而最省心。不过你要留意如果你打算部署到服务器上做演示Linux服务器上跑.NET需要额外安装ASP.NET Core Runtime这一步偶尔会卡住。2.2 前端方案与页面实现思路老实说毕设项目的前端不需要整得太花哨关键是整洁、专业、功能完整。我个人的建议是前端用模板引擎渲染为主单独引入Bootstrap 5作为UI基础框架。这样你只要把精力花在写业务代码和画页面上而不是从零搭建前端工程。如果你有精力也可以把前后端拆开前端用Vue 3 Element Plus后端纯写接口。这种方案的优点是答辩的时候可以吹一下“前后端分离架构”缺点是工作量至少多出40%。你得设计接口文档、处理跨域、做Token认证。时间紧的话不建议冒险。我这里给一个折中方案整体用服务端渲染但在数据统计分析页面单独用Vue ECharts来做动态图表。这样既保证了大部分页面的开发效率又能在统计模块展示出一定的新意。2.3 开发环境搭建清单不管选哪种语言有几个环境配置是必须提前搞定的JDK 8/11/17或者Python 3.10或者PHP 8.2锁死版本装完就不动MySQL 8.0注意安装时选utf8mb4字符集不然中文存取必炸Maven / Composer / pip按语言对应选IDEIDEA对Java最友好PyCharm对Python友好VS Code通吃但调试能力差点开发机上建议再装一个Navicat或者DataGrip建库建表、看数据比命令行舒服太多了。3. 数据库设计与核心表结构3.1 表设计整体规划房屋销售管理系统的数据库可以按照我之前说的业务链路来拆表。不需要追求高大上的设计模式但必须保证表结构能满足所有的功能页面需要。我给出的核心表清单如下house房源表存楼盘名、户型、面积、总价、状态customer客户表存姓名、电话、意向区域、预算、来源渠道follow_record跟进记录表存客户和房源的多对多关联deal_record成交记录表存成交价、成交日期、经办人sys_user用户表存登录账号、密码、真实姓名sys_role角色表存角色编码和名称注意一点house和customer之间不是直接主外键关系而是通过follow_record这个中间表产生关联。这样设计的好处是一个客户可以同时跟着多套房源而一套房源也能被多个客户看中这是真实业务里最常见的场景。3.2 关键核心表结构说明房源表是我首先要聊的。别想得太复杂核心字段就这些CREATE TABLE house ( id int NOT NULL AUTO_INCREMENT, title varchar(100) NOT NULL COMMENT 房源标题/楼盘名称, address varchar(200) NOT NULL COMMENT 详细地址, area decimal(10,2) DEFAULT NULL COMMENT 建筑面积平方米, layout varchar(50) DEFAULT NULL COMMENT 户型如三室两厅, total_price decimal(12,2) DEFAULT NULL COMMENT 挂牌总价万元, unit_price decimal(10,2) DEFAULT NULL COMMENT 单价元/平方米, house_type varchar(20) DEFAULT 住宅 COMMENT 房源类型住宅/商铺/写字楼, status tinyint DEFAULT 1 COMMENT 状态1在售 2已预定 3已售 4已下架, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT房源表;这里垃圾坑特别多我提前说一下unit_price这个字段最好在业务逻辑里自动计算不要手动录入。录入总价和面积之后由后端算好单价再存库避免前后端数据对不上。客户表的核心字段是姓名、电话、意向区域、预算。phone字段建议加唯一索引但别做唯一约束因为同一客户可能有多个联系方式做索引只是为了查询快。跟进记录表是整个系统里最容易出错的设计点。CREATE TABLE follow_record ( id int NOT NULL AUTO_INCREMENT, customer_id int NOT NULL COMMENT 客户ID, house_id int DEFAULT NULL COMMENT 关注的房源ID, follow_type varchar(20) DEFAULT 看房 COMMENT 跟进类型电话/看房/谈判, content varchar(500) DEFAULT NULL COMMENT 跟进内容描述, follow_user_id int NOT NULL COMMENT 跟进人, follow_time datetime DEFAULT NULL COMMENT 跟进时间, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT跟进记录表;3.3 为什么要用逻辑删除做删除功能的时候很多新手默认用DELETE语句直接删行。这个习惯在毕设管理类项目里要改掉。我建议所有业务表都加上一个is_deleted字段删除操作只把字段置为1查询条件里统一加上is_deleted 0。原因很现实第一管理员手滑删错数据你还能救回来第二成交记录和跟进入记录都是历史数据物理删了就真的没痕迹了第三答辩时老师问你“怎么保证数据安全性”你至少能答出“采用逻辑删除保护历史数据”。也别担心实现复杂MyBatis-Plus里直接有TableLogic注解加上之后调用deleteById方法就自动帮你执行更新而不是删除。4. 核心功能模块实现详解4.1 登录认证与密码加密登录模块是每个管理系统的门面也是踩坑重灾区。先说密码存储绝对不要明文存密码。就算我这个项目只是课设级别也必须用BCrypt或者至少MD5加盐。Spring Boot里引入spring-security-crypto依赖调用BCryptPasswordEncoder即可Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } // 注册时加密 String encodedPassword passwordEncoder.encode(rawPassword); // 登录时校验 boolean matches passwordEncoder.matches(rawPassword, user.getPassword());登录校验逻辑建议写在拦截器里统一处理。用Session还是JWT看你的技术方案服务端渲染用Session最简单前后端分离用JWT顺手。我的建议是Java/PHP做服务端渲染就用SessionPython做前后端分离就用JWT选择跟技术栈匹配的就好。4.2 房源管理模块的CRUD与条件查询房源管理模块是系统的主要部分无非就是增删改查加列表。列表页我强烈建议做分页和条件组合查询这也是答辩演示时最能展示功底的地方。查询条件通常有关键词、价格区间、面积区间、户型、状态这几个条件排列组合起来就是动态SQL。Java的MyBatis-Plus里用LambdaQueryWrapper来拼条件非常舒服public PageHouse queryHouseList(int pageNum, int pageSize, HouseQueryDto dto) { PageHouse page new Page(pageNum, pageSize); LambdaQueryWrapperHouse wrapper new LambdaQueryWrapper(); wrapper.eq(StringUtils.hasText(dto.getStatus()), House::getStatus, dto.getStatus()) .like(StringUtils.hasText(dto.getKeyword()), House::getTitle, dto.getKeyword()) .ge(dto.getMinPrice() ! null, House::getTotalPrice, dto.getMinPrice()) .le(dto.getMaxPrice() ! null, House::getTotalPrice, dto.getMaxPrice()) .ge(dto.getMinArea() ! null, House::getArea, dto.getMinArea()) .le(dto.getMaxArea() ! null, House::getArea, dto.getMaxArea()) .orderByDesc(House::getCreateTime); return houseMapper.selectPage(page, wrapper); }这里要注意一个细节前端日期范围或数字区间传空值时你拼条件必须提前判断否则会把全表数据都刷出来。经验之谈这类条件查询接口Debug的时候最先检查的就是空值判断漏没漏。4.3 客户管理与销售跟进绑定客户管理模块的设计误区在于做成“客户通讯录”只有增删改查。我在实际开发中把“跟进记录”和“客户详情”绑在了一起点开客户详情直接能看到这位客户从第一次来电到现在每一次电话、看房、谈判的记录这才是完整闭环。前端班把客户详情页分成上下两段上面是客户基本信息下面是该客户的跟进时间线列表。这样演示起来视觉效果也好业务逻辑也说得通。后端提供一个查询接口传入客户ID返回客户信息加跟进记录列表前端直接渲染。public CustomerDetailVO getCustomerDetail(Integer customerId) { Customer customer customerMapper.selectById(customerId); ListFollowRecord records followRecordMapper.selectList( new LambdaQueryWrapperFollowRecord() .eq(FollowRecord::getCustomerId, customerId) .orderByDesc(FollowRecord::getFollowTime) ); CustomerDetailVO vo new CustomerDetailVO(); BeanUtils.copyProperties(customer, vo); vo.setFollowRecords(records); return vo; }4.4 成交登记与统计报表成交登记就是把整条业务链跑通的临门一脚。成交本质上要完成两件事在deal_record表插入一条成交数据同时把对应的房源状态改成“已售”。这两个操作必须在一个事务里完成否则就会出现“成交记录有了但房源还在售卖中”的尴尬局面。Transactional(rollbackFor Exception.class) public void createDeal(DealDto dto) { DealRecord deal new DealRecord(); BeanUtils.copyProperties(dto, deal); deal.setDealTime(new Date()); dealRecordMapper.insert(deal); House house houseMapper.selectById(dto.getHouseId()); if (house ! null) { house.setStatus(3); // 已售 houseMapper.updateById(house); } }统计报表模块清爽的做法是在后台查好聚合数据返回给前端渲染图表。用ECharts做柱状图和饼图展示月度成交量、各区域房源占比、销售人员业绩排行几块内容。核心SQL注意别把关联关系搞错销售排名要关联sys_user和deal_record两张表SELECT u.real_name, COUNT(d.id) AS deal_count, IFNULL(SUM(d.deal_amount), 0) AS total_amount FROM sys_user u LEFT JOIN deal_record d ON u.id d.sales_user_id WHERE d.deal_time BETWEEN #{startTime} AND #{endTime} GROUP BY u.id, u.real_name ORDER BY total_amount DESC5. 常见问题与排查技巧实录5.1 中文乱码问题及解决办法中文乱码是我接手整改别人代码时最常看到的问题没有之一。它的根源几乎都是字符集不统一。MySQL数据库整体要全链路统一成utf8mb4包括数据库本身、表结构、连接URL。Java侧特别容易在JDBC连接串上翻车很多旧教程里的连接串都没加字符集参数。正确做法是jdbc:mysql://localhost:3306/house_db?useUnicodetruecharacterEncodingutf8mb4serverTimezoneAsia/Shanghai注意这个serverTimezone参数不加上去在高版本MySQL里还会报时区错误。出现中文乱码时先不要急着改代码从连接URL、数据库表、前端页面三个环节依次排查。5.2 分页查询结果不准确的坑分页插件在MyBatis-Plus里叫PaginationInnerInterceptor但这个拦截器的版本和MyBatis-Plus核心版本有个匹配问题。有些同学引入插件后分页不生效查出来的数据永远是全量这是因为插件没注册成功。我给出一个标准的配置模板Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); PaginationInnerInterceptor pagination new PaginationInnerInterceptor(DbType.MYSQL); pagination.setOverflow(false); pagination.setMaxLimit(500L); interceptor.addInnerInterceptor(pagination); return interceptor; } }如果这样配置完还是不分页检查一下你的Mapper接口里有没有直接把Page对象写在参数列表里而不是放在查询方法的第一个参数位置。5.3 图片上传与静态资源访问房源管理里经常要上传户型图和实拍图这块的配置常常把人绊住。Spring Boot里你要先设置一个本地上传目录再把该目录映射为静态资源才能通过URL访问到。最简单的实现spring: servlet: multipart: max-file-size: 10MB web: resources: static-locations: classpath:/static/,file:${upload.path}上传接口把文件保存到upload.path目录数据库里存相对路径/upload/xxx.jpg。前端展示的时候直接拼接这个相对路径就能拿到图片。掺了中文文件名的上传大概率乱码建议上传的时候统一用UUID重命名文件。5.4 服务器部署后页面资源加载失败这个问题尤其容易出现。本地开发好好的传到云服务器上再访问图片没了、CSS样式丢了。绝大多数原因都是你在页面上写死了localhost或者127.0.0.1开头的URL。资源引用统一用相对路径或者上下文路径不要写死IP。比如img th:src{/upload/xxx.jpg} alt房源图片这样部署到哪个IP和端口都能正常访问。切记全项目搜索localhost有一个改一个。6. 部署测试与毕设答辩经验6.1 本地部署与服务器部署要点本地部署把后端起起来、MySQL数据库导入、前端页面能访问这套流程每个搞开发的人都该熟练。服务器部署有一个额外难题是防火墙和端口放行。云服务器除了系统内部防火墙要放行还得去云控制台的安全组里配置对应规则两边都放过才有用。数据库连接也不要再用localhost了改成服务器的内网IP或公网IP用户名密码用强密码。密码这地方我多说一句不要用root/123456这种组合跑演示被老师问到了很尴尬简单造一个复杂密码又不费事。6.2 测试用例设计与演示准备清单这里我更愿意称之为“演示脚本”。答辩现场和PPT不同系统演示是实时操作最容易翻车。我的经验是你必须在正式演示前按下面这个清单完整走过两遍每一步都要记录管理员登录系统检查首页统计数字是否与数据库一致新增一条房源确认列表页能搜到、详情页能打开录入一个客户给客户关联一条看房记录演示权限换销售账号登录确认该账号看不到别人的客户成交一套房源确认房源状态变为已售查看统计报表确认图表数字发生对应变化演示经费里最怕遇到的就是“新增操作后列表数据没刷新”这类低级故障。提前排查一遍稳了再上。6.3 答辩环节高频问题预判与应对答辩蜡烛的核心其实就四个方向设计思路、表结构、权限控制、某个技术点细节。你准备的时候围绕这四个方面去准备就行。问得最多的我列几个“为什么选择这个技术栈” 回答思路对比过其他方案本方案在开发效率、生态完善度、与需求的匹配度上更合适“数据库超了几张表表间关系是什么” 回答思路直接画ER图讲清楚中间表的作用“你的权限控制是怎么实现的” 回答思路基于RBAC模型用户绑定角色角色绑定权限后端拦截器做统一校验“系统有没有考虑并发场景” 回答思路诚实一点说明课设主要在单机环境下验证局部采用了事务保证一致性并发性能是后续优化方向“房价统计的准确性怎么保证” 回答思路成交和房源状态变更放在同一个事务里6.4 提升项目亮点的几个加分思路如果你时间充裕这几个方向能显著给项目加分操作日志记录功能记录关键操作的用户、时间、内容答辩现场演示一笔操作后去日志页查看记录效果很直观数据导功能用EasyExcel导出房源列表或成交明细老师基本都会觉得工作量大首页做一个数据看板近七天的成交量趋势、待办事项提醒视觉上冲击力很强验证码登录用Hutool工具类生成图形验证码加上之后系统完整度一下就上去了我今天把这套房屋销售管理系统的设计、表结构、核心功能实现和避坑经验都梳理了一遍。可以说这个项目虽然看起来是经典的“老题目”但它把业务系统开发的核心知识点都覆盖到了——需求拆分、权限模型、关联表设计、事务一致性、数据可视化每一个点做到位了都能在答辩或演示中给你加分。最后再分享一个我个人的习惯写这类管理系统先把表结构设计定稿再用Excel把每个页面的字段和操作列出来最后才写代码。表结构定了业务就定了字段对齐了前后端对接就不容易翻车。这套流程用熟了从拿到题目到交付成品不需要靠熬夜刷进度也能在你预期的时间里顺顺当当收工。