☰
SSM智慧社区管理系统:从框架原理到毕业设计落地全解析
2026/10/18 12:03:11 网站建设 项目流程

简介:这是一套基于SSM框架(Spring、SpringMVC、MyBatis)开发的智慧社区管理系统,面向正在准备毕业设计的计算机专业学生和需要项目实战练习的Java学习者。系统采用B/S架构,使用JSP技术开发页面,数据库采用MySQL,开发环境为JDK、Eclipse、Tomcat,并且经过严格调试,可直接运行使用。系统包含业主和管理员两种角色,分为前台与后台两大模块,覆盖业主信息管理、房产信息管理、社区内容管理、物业收费管理、物业服务管理、服务预约管理、报损报修管理、意见反馈管理和留言交流管理等完整功能,能够实现社区、业主、物业与小区管理者的高效联动,使社区管理工作更加系统化、规范化、高效化。资源包共3个文件,压缩包大小约28.3MB,主要包含项目源码、数据库脚本以及项目说明文档,其中sql脚本可快速初始化数据库环境,txt说明有助于部署参考,整体界面美观、操作简单,具有较高的实际应用价值。已有6803人学习下载,适合直接作为毕业设计项目,也适合作为SSM框架综合练习的完整案例。

1. SSM智慧社区管理系统:为什么它成了毕设项目的常青树

答辩前两周,最让人心安的莫过于从素材站拿到一个带数据库脚本的毕设源码包:导入数据库、改个密码、点运行,整个系统就该站起来了。基于SSM的智慧社区管理系统正是这类项目里最常见的面孔——SSM 是 Spring、SpringMVC、MyBatis 的组合称呼,社区管理是落点,功能绕不开住户、房屋、缴费、报修、公告这几块。它解决的问题很实在:给需要完成 Java Web 毕设的学生一条从建库到页面交互的完整链路,而不是几个 CRUD 拼凑起来就交差。适合两类人:一类是时间紧、需要快速把项目跑起来并能在答辩时把原理讲清楚的毕设选手;另一类是刚学完框架、想拿一个完整业务项目练手的入门开发者。但我要先泼一盆冷水:能跑起来是项目包的下限,不是上限。素材站里下载、学长那里拷贝来的源码包,通常都能跑,但你得能回答三个问题——数据库脚本里每张表是干什么的、请求从页面点一下到返回经过了哪些类、改一个功能要动哪几层。这篇文章就沿着这三个问题把项目拆开,再合上。

2. SSM 技术选型与工程结构:为什么“老三样”还是毕设首选

先讲清楚这套组合里每样东西管什么。Spring 管对象生命周期和依赖注入,SpringMVC 管 URL 到方法的映射和参数绑定,MyBatis 管 SQL 与结果集映射。三者各管一段,分工清楚,出了问题能很快定位到层。做真实项目我通常劝人用更现代的脚手架,毕业设计则不一样:评的是结构清不清楚、组件讲不讲得明白,SSM 的显式配置反而给了学生一次把“配置为什么存在”讲清楚的机会。

拿 SSM 和 Spring Boot 对比,差异其实就在“自动配置”四个字。SSM 的每个 bean 都要自己声明,配在 XML 里明明白白,报错也报在明处;Spring Boot 把逻辑藏进了 starter 和自动配置后面,开发更快,但回答“数据源是怎么来的”这类问题时,你得翻一层源码。所以我的建议是:如果项目包里已经是 SSM,不要临时改成 Boot,毕设求稳。

2.1 SSM 工程分包:拿到源码后第一件事是画目录

不管项目是下载的还是自己写的,先从目录结构开始看。一个标准的 SSM 项目分包长这样:

src/main/java/com/smartcommunity ├── controller # 接收请求、返回视图或 JSON ├── service # 业务逻辑与事务边界 ├── mapper # MyBatis 接口,只定义方法 ├── entity # 与表对应的实体类 └── common # 通用返回值、分页封装等 src/main/resources ├── mapper # MyBatis XML 映射文件 ├── config # Spring、SpringMVC 配置文件 └── jdbc.properties src/main/webapp/WEB-INF/views └── owner/list.jsp # JSP 视图

这个分包不是随便定的。mapper 只放接口,SQL 全在 XML 里,是为了把 Java 代码和 SQL 分离;service 夹在 controller 和 mapper 中间,是为了给事务一个清晰的作用边界;entity 只做数据载体,不放业务逻辑。拿到打包好的源码后,第一步不是点运行,而是把目录画出来,对照 web.xml 看加载顺序——这一步能帮你避开后面九成的疑难杂症。

2.2 双容器模型:root 容器和 web 容器为什么必须分开

SSM 里最迷糊的就是配置文件拆成好几分。常见配置是 web.xml 加载两个 Spring 容器:root 容器负责数据源、事务、service、mapper;DispatcherServlet 自己再加载一个 web 容器,负责 controller 和视图解析器。web.xml 里大概长这样:

<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:config/applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:config/spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>

context-param 里的 applicationContext.xml 是父容器,DispatcherServlet 的 spring-mvc.xml 是子容器,子容器能看到父容器的 bean,反之不行。如果图省事把 MapperScannerConfigurer 放到 spring-mvc.xml 里,项目也能跑,但可能出现事务失效这种怪问题——因为事务管理器在父容器,而 Mapper 在子容器,代理关系会乱掉。记住这个原则:数据源、事务、Mapper 扫描放父容器,Controller 和视图解析器放子容器。

2.3 SSM 和 Spring Boot 的取舍:别在答辩前临时换栈

对比项SSMSpring Boot
配置量多,但每个 bean 可见少,约定优于配置
学习价值能讲清容器和 MVC 原理偏重如何使用生态
答辩提问风险低,问题集中在 XML 配置中,可能被追问自动配置源码
从源码包接手成本低低,但依赖管理易乱

如果已经选择了带 SSM 源码包,就顺着它走。临时换 Boot 意味着重写配置类、重新理依赖,两周时间未必够,还会引入一堆新坑。SSM 项目在答辩现场被问得最多的就是“这个配置为什么这么写”,你把上面的父容器子容器关系讲清楚,比背十个 Bootstrap 组件更让老师信服。

3. 数据库脚本设计:核心表的结构、外键取舍与初始化数据

这个项目的数据库脚本是标题里明写的交付物,也是整个项目的地基。拿到手的 .sql 文件一般包含四段:建库、建表、插入测试数据、插入管理员账号。你要做的不是双击导入就完事,而是把每张表的字段含义逐一过一遍。

智慧社区管理系统通常会有这几张表:管理员表、房屋表、住户表、缴费表、报修表、公告表,有条件还会加车位表和访客登记表。表之间是小区运转的缩影:管理员建好房屋档案,住户入住后挂到某套房下面,住户名下产生缴费单,也可以提交报修单。

3.1 核心表关系:先有房,再有人

房屋和住户的关系是第一个设计要点。常见的做法是“先有房再有人”,房屋表里预留 owner_id 字段,空闲时为空,入住后填上。这样统计空置率只需要一条 SQL,不用 join 两次。如果考虑合租和多业主,可以单独建一张业主房屋中间表,但对毕设来说,owner_id 字段方案简单、好讲,也足够应对答辩。

CREATE TABLE t_house ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '房屋ID', building_no VARCHAR(10) NOT NULL COMMENT '楼栋号', unit_no VARCHAR(10) NOT NULL COMMENT '单元号', room_no VARCHAR(10) NOT NULL COMMENT '房号', area DECIMAL(8,2) NOT NULL DEFAULT 0.00 COMMENT '建筑面积', owner_id BIGINT DEFAULT NULL COMMENT '住户ID,空闲时为NULL', status TINYINT NOT NULL DEFAULT 0 COMMENT '0空闲 1已入住', create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '建档时间', UNIQUE KEY uk_house (building_no, unit_no, room_no) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='房屋信息表';

房屋表用唯一索引 uk_house 保证“同一栋楼同一单元同一房号”不重复录入。owner_id 不建物理外键,走逻辑关联。很多素材包的脚本里也没有物理外键,原因很简单:外键会影响导入顺序,而且删除数据时总报约束错误。毕设项目里用逻辑外键是主流做法,你把“为什么不用物理外键”这个问题准备好,反而能拿到加分。

住户表和缴费表的设计也同样要注意字段边界。状态字段用 TINYINT 而不是 VARCHAR 存“已入住”,因为状态是有限枚举,数字比字符串好判断、省空间,还方便扩展。金额用 DECIMAL(10,2) 而不要用 FLOAT,浮点数算账会莫名差几分钱,答辩现场被问到“为什么金额不用 double”时,这就是一个亮点回答。时间字段我习惯用 DATETIME 而不是 TIMESTAMP,TIMESTAMP 有 2038 年上限,社区系统用不到那么远,但 DATETIME 省心,默认值也好写。

3.2 初始化数据:给演示准备一个“故事线”

初始化数据是数据库脚本里最容易敷衍、但答辩价值最高的部分。很多素材包的 SQL 只会插入两条测试记录,状态还全是“已完成”。演示时老师一登录,看到的数据全是收尾状态,提不出问题,但也看不出系统逻辑。我自己做这类项目时,会按业务闭环造数据:

INSERT INTO t_house (building_no, unit_no, room_no, area, owner_id, status) VALUES ('1', '1', '101', 89.50, 1, 1), ('1', '1', '102', 89.50, 2, 1), ('1', '1', '201', 120.30, NULL, 0); INSERT INTO t_owner (owner_name, id_card, phone, house_id, status, create_time) VALUES ('张三', '110101199001011234', '13800000001', 1, 1, '2024-03-01 10:00:00'), ('李四', '110101199202021235', '13800000002', 2, 1, '2024-03-05 14:30:00'); INSERT INTO t_repair (owner_id, house_id, repair_type, description, status, create_time) VALUES (1, 1, '水管', '厨房水龙头漏水', 2, '2024-05-10 09:00:00'), (2, 2, '电路', '客厅灯不亮', 1, '2024-05-12 20:00:00'); INSERT INTO t_fee (house_id, fee_type, amount, pay_status, create_time) VALUES (1, '物业费', 890.00, 1, '2024-04-01 08:00:00'), (2, '物业费', 890.00, 0, '2024-04-01 08:00:00');

报修状态要有待处理、处理中、已完成三种,缴费记录得有已缴和未缴。演示时你才能顺着一套流程讲下来:新住户入住、发起报修、物业接单、完工、生成缴费、完成支付。这段初始化数据连贯性比数量重要,毕竟答辩时间就十分钟。

3.3 数据库脚本的导入习惯:留好后悔药

脚本文件要保存成 UTF-8 无 BOM 格式。很多从素材站下来的 .sql 文件带 BOM 头,Navicat 导入时第一个语句前面藏了个不可见字符,报错信息莫名其妙。命令行导入比图形界面更稳,而且可重复:

mysql -uroot -p -e "CREATE DATABASE IF NOT EXISTS smart_community DEFAULT CHARACTER SET utf8mb4;" mysql -uroot -p smart_community < smart_community.sql

第一条命令建库,第二条把脚本导入指定库。注意两条命令执行时要确认当前网络和数据库版本一致,如果脚本里已经带建库语句,重复执行可能会报库已存在的告警,但不影响后续。导入完成后用一条 SQL 验证基础数据:

SELECT COUNT(*) FROM t_house; SELECT COUNT(*) FROM t_owner;

数字不对就说明脚本没执行干净,趁早重导,不要拖到演示现场。

4. 从配置到业务链路:MyBatis、事务与 Controller 的配合

这一章讲一个请求从页面到数据库再返回的完整链路。跑通这条链路,你才真正掌握这套项目而不是背代码。先从 Spring 集成 MyBatis 开始。

4.1 数据源与 SqlSessionFactory:让 MyBatis 和 Spring 接上

SSM 里 MyBatis 不能自己独立跑,要交给 Spring 管理。核心是 SqlSessionFactoryBean,它把数据源、XML 映射、实体别名统一装配起来:

<context:property-placeholder location="classpath:jdbc.properties"/> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="mapperLocations" value="classpath:mapper/*.xml"/> <property name="typeAliasesPackage" value="com.smartcommunity.entity"/> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.smartcommunity.mapper"/> </bean>

Druid 的 init-method 和 destroy-method 要配合使用,否则连接池的监控和回收逻辑不生效。mapperLocations 告诉 MyBatis 去哪找 XML 文件,typeAliasesPackage 是把实体包名下所有类注册成短别名,后面写 XML 的 resultType 才能直接写 Owner 而不写全限定名。MapperScannerConfigurer 的作用是扫描 mapper 接口,把它们注册成 Spring bean,省去手动一个个声明。

如果项目里用了分页,还要在 SqlSessionFactory 里挂分页拦截器。这里有个版本差异要特别注意:PageHelper 5.x 用 PageInterceptor,网上很多旧教程写的是 4.x 的配置方式:

<property name="plugins"> <array> <bean class="com.github.pagehelper.PageInterceptor"> <property name="properties"> <props> <prop key="helperDialect">mysql</prop> <prop key="reasonable">true</prop> </props> </property> </bean> </array> </property>

helperDialect 指定数据库方言,reasonable 设为 true 表示页码越界时自动纠正到第一页或最后一页。这两个属性是答辩常问点,尤其是 reasonable 的行为逻辑,不少学生被问“页码传 999 会怎样”时答不上来。

4.2 Mapper 层:接口和 XML 的约定不能乱

Mapper 接口负责定义方法,XML 负责写 SQL。两者靠“接口全限定名 + 方法名”关联,namespace 写错是最隐蔽的坑。一个标准查询长这样:

public interface OwnerMapper { List<Owner> selectOwnerList(@Param("keyword") String keyword); }
<select id="selectOwnerList" resultType="Owner"> select id, owner_name, phone, house_id, status, create_time from t_owner <where> <if test="keyword != null and keyword != ''"> and owner_name like concat('%', #{keyword}, '%') </if> </where> order by create_time desc </select>

resultType 能写 Owner 靠的是前面配置的 typeAliasesPackage。#{}是预编译占位符,会生成?并做参数绑定,能防 SQL 注入;${}是字符串拼接,只在动态排序列名时用,其他地方不要碰。like concat('%', #{keyword}, '%')这种写法比直接写'%${keyword}%'安全得多。<where>标签会自动处理第一个条件前面的 and 关键字,这个细节经常让新手困惑——为什么这里多一个 and 也不报错。

4.3 Service 层:事务边界和分页的调用规则

Service 层是事务的边界。SSM 项目里 @Transactional 加在 Service 实现类或方法上,而不是 Controller 上。用 PageHelper 分页时,有个铁律必须遵守:

@Service public class OwnerServiceImpl implements OwnerService { @Autowired private OwnerMapper ownerMapper; @Override @Transactional(readOnly = true) public PageInfo<Owner> pageOwner(int pageNum, int pageSize, String keyword) { PageHelper.startPage(pageNum, pageSize); List<Owner> ownerList = ownerMapper.selectOwnerList(keyword); return new PageInfo<>(ownerList); } }

PageHelper.startPage 基于 ThreadLocal 实现:调用后把分页参数放进当前线程的局部变量,下一条 SQL 执行时自动拼接 LIMIT。所以 startPage 必须紧跟着目标查询,中间不能有任何其他 SQL 操作,否则分页会作用到错误的语句上。@Transactional(readOnly = true)表示该方法只读,对 MySQL 而言只读事务不做主要的锁竞争,适合纯查询场景。需要写入的方法则不加 readOnly,让事务默认读写。

4.4 Controller 层:页面跳转和 JSON 返回的分工

Controller 里有两种典型写法,一种是返回视图路径,一种是返回 JSON。列表页通常用前者:

@Controller @RequestMapping("/owner") public class OwnerController { @Autowired private OwnerService ownerService; @RequestMapping("/list") public String list(@RequestParam(defaultValue = "1") Integer pageNum, @RequestParam(defaultValue = "10") Integer pageSize, @RequestParam(required = false) String keyword, Model model) { PageInfo<Owner> pageInfo = ownerService.pageOwner(pageNum, pageSize, keyword); model.addAttribute("pageInfo", pageInfo); return "owner/list"; } }

返回的字符串owner/list会被视图解析器拼成/WEB-INF/views/owner/list.jsp。Model 里放的数据在 JSP 里直接用 EL 表达式取。注意 @RequestParam 的 defaultValue 一定要写,否则列表页第一次访问不带 pageNum 参数时,SpringMVC 会直接报 400。keyword 用 required = false 表示可空,空值时 Service 层传 null,XML 里的<if>会跳过条件。

异步操作如删除、状态更新,走 JSON 返回更合适:

@ResponseBody @RequestMapping("/delete") public Result delete(@RequestParam Long id) { ownerService.deleteById(id); return Result.success(); }

Result 是自定义的通用返回体,至少包含 code、message、data 三个字段。返回 JSON 时不要直接把实体类丢出去,尤其实体类有密码字段时,密码会跟着序列化返回到浏览器。统一用 Result 包装一层,由你来决定哪些字段暴露。这个习惯在答辩里体现出来,老师就知道你考虑过安全问题。

5. 排查避坑:SSM 智慧社区最常见的 5 个翻车点

这一章全是实际调项目时遇到过、帮别人调过的坑。素材站上下来的项目包,出问题最多的地方高度集中在这五个。每一条都按现象、原因、解决来写,遇到对应问题直接对照。

5.1 首页能开但 CSS/JS 全 404

现象:Tomcat 启动正常,登录页面 HTML 结构在,图片样式全部丢失,浏览器 F12 里能看到一堆/css/xxx.css的 404 请求。

原因:DispatcherServlet 的 url-pattern 配成了/,把所有请求都拦截下来交给 SpringMVC。而 SpringMVC 默认不知道去哪找静态资源,所以 css、js、图片全部找不到。

解决:在 spring-mvc.xml 里放行静态资源:

<mvc:resources mapping="/static/**" location="/static/"/> <mvc:default-servlet-handler/>

mapping 是 URL 前缀,location 是文件实际目录,两者要对应。配了之后再去 JSP 里检查引用路径,素材包最容易在这一步出问题:写成/css/style.css的绝对路径,在本地根路径部署没问题,一旦改了应用上下文路径就挂。正确的写法是带上下文:

<link rel="stylesheet" href="${pageContext.request.contextPath}/static/css/style.css">

5.2 数据库连不上:时区、驱动类名与特殊字符

现象:启动项目时控制台报Cannot create PoolableConnectionFactory或Access denied for user,Tomcat 直接起不来。

原因:三个高频原因叠加。一是 MySQL 8.x 的驱动类名和 5.x 不同,老配置写com.mysql.jdbc.Driver在 8.x 下已经废弃,要用com.mysql.cj.jdbc.Driver;二是 JDBC URL 少了serverTimezone参数,MySQL 8 要求显式指定时区;三是数据库密码里含&或#这类特殊字符,XML 里没做转义,密码被截断。

解决:把数据库连接统一收敛到 jdbc.properties 里,检查这份配置:

jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/smart_community?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true jdbc.username=root jdbc.password=你的密码

URL 里的参数逐个说清楚:useUnicode 和 characterEncoding 配合保证中文不乱码;serverTimezone 指定时区,不写会报Server returns invalid timezone;useSSL 建议关掉,避免本机环境证书告警;allowPublicKeyRetrieval=true 是 MySQL 8 的 caching_sha2_password 认证方式需要的,不加会报Public Key Retrieval is not allowed。先用命令行确认数据库本身能连,再怀疑配置:

mysql -uroot -p -h127.0.0.1 -P3306

命令行能进,说明问题就在驱动或 URL 参数,逐项比对配置即可。

5.3 数据库脚本导入报错:重复建库、外键顺序、BOM 干扰

现象:用 Navicat 运行 SQL 脚本报Table already exists或Cannot add foreign key constraint;或者脚本执行一半失败,后面表全没建成。

原因:脚本里带了CREATE DATABASE语句,第二次执行时表已存在造成冲突;外键依赖的表还没创建完;更隐蔽的是脚本保存时带 BOM 头,第一个语句前有不可见字符导致语法报错。

解决:放弃一键运行整个脚本,改成两步走,先建空库再导入:

mysql -uroot -p -e "CREATE DATABASE IF NOT EXISTS smart_community DEFAULT CHARACTER SET utf8mb4;" mysql -uroot -p smart_community < smart_community.sql

如果脚本里已经写了建库语句,直接执行第二步即可,会提示Database exists但不致命。外键问题优先检查 DROP 顺序:先删子表(带外键的表),再删父表(被引用的表)。脚本开头通常是 DROP TABLE,如果顺序是父表先删,子表删不掉,就会报错。一条条看完脚本的 DROP 段,把顺序理清楚,这是接手任何带数据库脚本项目的第一课。

5.4 页面能开但列表空白:Mapper 扫描、命名空间与事务未提交

现象:登录成功,点“住户列表”页面正常渲染,但表格里一行数据都没有,数据库里明明有数据。另一种极端是新增记录接口返回成功,刷新后数据库里查不到。

原因:三个高频原因。Mapper 接口没有被 Spring 扫描到,Controller 里注入的 service 一切正常,但调用 mapper 时是 null,页面往往表现为 500 或空白;XML 的 namespace 和接口全限定名不一致,MyBatis 启动时并不一定立刻报错,运行时才找不到映射;事务没提交,Service 方法没有加 @Transactional,或者加了但异常被外层 try-catch 吞掉,回滚了也没人知道。

解决:先看启动日志,MyBatis 正常注册 mapper 时会有Registered mapper interface相关输出;再比对接口路径和 XML 的 namespace。最快的定位方法是看抛出的异常栈:

curl http://localhost:8080/owner/list

返回 500 且异常指向 OwnerMapper 那一行,几乎是扫描问题,检查 MapperScannerConfigurer 的 basePackage 是否正确;返回 200 但列表为空,优先怀疑 SQL 条件写死或查询的列名和实体属性对不上。下划线转驼峰映射需要在 MyBatis 配置里打开map-underscore-to-camel-case,否则owner_name映射不到ownerName,查出来全是 null。

5.5 PageHelper 分页失效:startPage 没紧跟查询

现象:第一页正常,点第二页时数据重复或总数不对;更夸张的是翻页后查出全表。

原因:PageHelper 基于 ThreadLocal 实现,startPage 把分页参数放进当前线程变量,下一次执行的查询自动拼接 LIMIT。如果 startPage 之后、目标查询之前还执行了别的 SQL 语句,分页就作用到了错误的语句上。代码里最常见的错误是在循环里调用 startPage,以及把 startPage 放在了一个日志查询或 count 查询的前面。

解决:把 startPage 直接放在要分页的 mapper 方法调用前一行,中间不留任何空隙:

PageHelper.startPage(pageNum, pageSize); List<Owner> ownerList = ownerMapper.selectOwnerList(keyword); PageInfo<Owner> pageInfo = new PageInfo<>(ownerList);

6. 答辩前的最后一道工序:演示数据编排与两个加分习惯

项目能跑只是底线,答辩现场真正拉分的是演示节奏。核心思路是不要把所有菜单挨个点一遍,而是讲一个小故事。我会准备这样一条演示链路:管理员登录 → 首页看统计 → 给空闲房屋建档 → 住户入住 → 住户发起报修 → 物业处理报修 → 生成缴费单 → 完成缴费。每一步的数据状态提前在数据库里核对过,老师问到“为什么这条记录状态是 2”,我能立刻说出这是处理中的报修单。

演示步骤涉及功能演示前要确认的数据
登录管理员认证测试账号密码可用
房屋建档房屋管理新增准备一条空闲房屋记录
住户入住住户管理房屋状态变为已入住
发起报修报修管理生成一条待处理工单
处理报修工单流转状态改为处理中再改为已完成
缴费缴费管理生成未缴账单再模拟支付

两个加分习惯值得养成。第一个是整理一份“我改过的东西”备忘:serverTimezone 为什么加、utf8mb4 为什么换、PageHelper 为什么必须紧跟查询、物理外键为什么不用。答辩被提问时,打开备忘从容地说“这里我改过”,比背概念可信得多。第二个是演示前一晚从数据库脚本重新建一遍库,确认交付物不是只在你的机器上能跑。这一步能提前暴露脚本里的重复建库、外键顺序问题,而不是让它们在答辩现场炸开。

我自己有个血泪教训:帮同学调演示环境,他前一天晚上在自己电脑上跑得好好的,第二天现场导入 SQL 脚本,脚本里有一句 DROP TABLE IF EXISTS,把他现场刚录好的演示数据全清了,整个人在台上愣了几秒。那次之后我养成了两个习惯:拿到任何带数据库脚本的项目,第一件事是通读 DROP 和 CREATE 的顺序;演示前一晚重新从脚本建一遍库。这种慌,体验一次就够了。希望帮到你。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询