1. 项目概述与需求拆解
1.1 家政平台到底解决什么问题
先别急着看代码。拿到“家政公司服务平台”这个题目,我第一反应不是急着敲键盘,而是先琢磨甲方(或者导师、老师)真正想要的是什么。家政服务这个行业,线下业态很成熟,但搬到线上会遇到一个非常典型的矛盾:客户要的是“我能预约到靠谱的阿姨”,家政公司要的是“我能把订单和人员管理起来”。 这两个诉求叠加在一起,平台的核心链路其实就三件事:
- 客户侧:浏览服务项目、查看价格、在线下单、填写服务时间与地址。
- 公司侧:服务项目管理、订单审核与分配、保洁人员(阿姨)信息管理、客户反馈处理。
- 管理侧:统计接单量、收入、服务完成率,最好还能导出报表。
从技术角度看,这就是一个标准的管理信息系统 + 轻量C端展示页的组合。难点不在于某个算法多高深,而在于业务状态流转要闭环:客户下单 → 公司接单/派单 → 保洁员接单 → 服务完成 → 客户确认/评价。任何一个环节断了,这个平台就是“玩具”。
另外还要在乎一个现实问题:这大概率是课程设计或者毕业设计的题目。所以选型不能太飘,不能一上来就上微服务、上消息队列——那既不符合工作量,也容易在答辩时被问住。最适合的路线就是“主流业务后台 + 轻量前端展示”,既能体现Java后端功底,又能展示完整业务逻辑。
1.2 为什么是“SSM + Flask”这个组合
这个组合乍一看有点“混搭”:SSM是经典的Java后端框架(Spring + SpringMVC + MyBatis),Flask是一个Python的轻量级Web框架。很多人第一反应是“为什么不用Vue写前端,偏偏用Flask?”——我当初也这么想过,但实际做完才明白这个搭配的合理性。
先说SSM。Spring负责依赖注入和事务管理,SpringMVC负责路由和请求分发,MyBatis负责数据库操作。这三件套在Java领域是“毕业设计黄金组合”:资料多、问题社区覆盖全、导师认可度高。家政平台的核心业务(订单、服务项、人员、评价)都是典型的CRUD + 状态流转,用SSM写后端非常顺手。
再说Flask。它的定位不是跟SSM抢后端,而是承担两个职责:一是面向C端用户的轻量展示页和预约入口,二是数据可视化/统计面板。Flask写页面快,配Jinja2模板引擎,几十分钟就能把首页、服务列表、预约表单搭出来。更关键的是,Python做数据处理和图表展示非常方便,接个pyecharts或ECharts,后台统计报表直接出图,这在答辩时是很大的加分项。
所以这个架构的本质是:Java SSM负责核心业务(重逻辑、强事务),Flask负责用户触达与数据展示(轻页面、快迭代)。两者通过HTTP接口通信,相当于把“后端服务”和“前端展示”用一套系统都做了,完全不用额外部署Node环境,对本地运行和演示非常友好。
提示:如果你在答辩时被人问“为什么不用前后端分离”,可以理直气壮地说:这是一个单体项目边界清晰的双服务架构,SSM和Flask各司其职,降低部署复杂度,适合家政公司这类中小型业务场景。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心功能模块设计与数据库建模
2.1 业务模块的完整划分
家政平台的功能不需要搞得很花哨,但必须完整且有逻辑。我按角色把功能拆成三类,每类对应一套接口和页面,这也是后续写代码的“施工图”。
客户(C端)模块:
- 注册/登录(手机号 + 验证码,本地演示时可以简化为密码登录,但要留验证码接口位)。
- 服务项目浏览:按“日常保洁”“深度清洁”“家电清洗”“月嫂/保姆”等分类展示。
- 在线预约下单:选择服务项→ 选择服务时间 → 填写地址/联系人 → 提交订单。
- 订单状态查看:待接单、已派单、服务中、已完成、已取消。
- 服务评价:订单完成后填写评分和文字评价。
家政公司(管理端)模块:
- 员工(保洁员/阿姨)信息管理:姓名、手机号、擅长项目、接单数量、评分。
- 服务项目管理:分类维护、价格设置、时长设置、上下架。
- 订单管理:订单列表、订单审核、派单给具体保洁员、标记服务完成。
- 反馈与评价管理:查看评价、处理投诉。
统计模块(Flask端):
- 每天新增订单数、各服务项目订单占比。
- 各保洁员接单量排名。
- 收入趋势图(按周/按月聚合)。
这三块功能听起来多,但落到数据库表上其实并不复杂。关键是要做到**“同一份数据,不同角色看到不同的操作入口”**,用户和管理员不能共用一个页面逻辑,否则演示时会显得很“糊”。
2.2 数据库表结构设计与关键字段说明
表设计直接决定开发效率。我建了以下这些核心表,每一张都特意做了字段约束,避免后期调试时数据乱掉。
用户表(t_user)
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | BIGINT | 主键自增 |
| phone | VARCHAR(11) | 唯一,登录账号 |
| password | VARCHAR(64) | MD5加密存储(演示用) |
| nickname | VARCHAR(32) | 昵称 |
| user_type | INT | 0-普通客户,1-管理员,2-保洁员 |
| create_time | DATETIME | 注册时间 |
服务分类表(t_category)
- id、category_name、sort_order。家政公司的服务项目不是固定的,保洁、保姆、月嫂、养老护理都可能增加,所以单独建分类表,方便扩展。
服务项目表(t_service)
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | BIGINT | 主键 |
| category_id | BIGINT | 关联分类 |
| service_name | VARCHAR(50) | 服务名称 |
| price | DECIMAL(10,2) | 价格/次 |
| duration | INT | 服务时长(小时) |
| description | TEXT | 服务描述 |
| status | TINYINT | 0下架 1上架 |
订单表(t_order),这是核心中的核心。字段除了基本订单号、下单用户、服务项,还需要这几个关键字段:
| 字段名 | 类型 | 说明 |
|---|---|---|
| order_no | VARCHAR(32) | 唯一订单号,用日期+随机数生成 |
| user_id | BIGINT | 下单客户 |
| service_id | BIGINT | 服务项目 |
| worker_id | BIGINT | 被派单的保洁员,可空 |
| service_time | DATETIME | 计划服务时间 |
| address | VARCHAR(255) | 服务地址 |
| status | TINYINT | 0待接单 1已派单 2服务中 3已完成 4已取消 |
| create_time | DATETIME | 下单时间 |
这里我要特意说一下status字段。很多新手喜欢用状态字符串如“待接单”“已完成”,但存数字的好处是便于代码里做状态流转判断,也不容易因为中文输入法产生不一致。页面上展示时再做状态转换即可。
评价表(t_comment)
- id、order_id(关联订单)、user_id、content、rating(1-5),comment_time。
管理员操作日志表(t_log,可选但我强烈建议加)
- 操作人ID、操作动作(接单/派单/完成)、操作时间、详情。这表在课程设计和毕设中是非常醒目的亮点,意味着你考虑了系统的完整性与可追踪性,答辩时可以专门提一句。
数据库我用的MySQL 5.7,字符集选utf8mb4(因为要存中文和特殊符号),引擎InnoDB,所有表加create_time字段。外键没有物理创建,而是用业务代码层面控制引用关系,这样演示时Insert数据更灵活,不容易因为外键约束导致测试数据插不进去。
3. 项目结构拆分与核心代码逻辑实现
3.1 SSM后端项目的包结构设计
我习惯用一个简洁清晰的包结构,既方便自己写,也方便导师或评审看代码。过于复杂的“模板化分层”反而容易让人头晕。
code复制com.housekeep
├── controller # 接口层:接收请求,返回JSON
├── service # 业务层:接口 + 实现
├── dao # 数据访问层:MyBatis Mapper接口
├── entity # 实体类:对应数据库表
├── common # 公用类:Result封装、状态常量、异常处理
└── config # 配置:SpringMVC拦截器、跨域配置、静态资源映射
按这个结构写代码,Controller层尽量“瘦”——只做参数接收和结果封装,业务判断都放到Service层。比如“下单”这个操作,Controller只拿到userId、serviceId、serviceTime、address,Service层里要校验用户存在、服务项上架、时间不能是过去,然后生成订单号、插入订单表,这些逻辑全在Service里。
一个我踩过的坑是:很多人为了图省事,把业务代码直接怼在Controller里,结果后面加功能时Ctrl+C/V满天飞,改一个订单状态逻辑要翻三四个文件。合理的Service层不仅是给导师看的,也是给自己省的。
3.2 订单状态机的实现思路
家政平台最核心的业务逻辑是“订单状态流转”。这个不能靠随缘if-else,我用了一个简单的状态机方式,在Service层统一收口:
code复制/** 订单状态常量 */
public class OrderStatus {
public static final byte PENDING = 0; // 待接单
public static final byte ASSIGNED = 1; // 已派单
public static final byte SERVING = 2; // 服务中
public static final byte COMPLETED = 3; // 已完成
public static final byte CANCELLED = 4; // 已取消
}
合法流转路径是:0→1→2→3,以及0→4(客户未付款时取消)。其他一切跳转都是非法的。我在Service层里写了一个checkStatusTransition(oldStatus, newStatus)方法,派单、开始服务、完成服务前都要走这个方法校验。
这招有个立竿见影的好处:演示或测试时不会出现“客户还没下单,管理员就标记完成”这种逻辑漏洞。虽然只是个小函数,但答辩时说出来,档次明显不一样——这意味着你理解了业务上的状态一致性,而不是单纯在写CRUD。
3.3 Flask端如何对接SSM的数据
Flask在这里不是代替SSM,而是跟SSM协作。我设计了两条协作路径:
路径一:Flask直接读取MySQL数据库。 Flask里用PyMySQL或SQLAlchemy直接连同一个MySQL实例,读取订单表、服务表、保洁员表的数据。这对“统计面板”来说最方便——不用调接口,SQL查出来就能聚合。
路径二:Flask通过HTTP调用SSM接口。 比如用户在Flask页面上提交预约表单,Flask收到POST后,用requests库把数据转发给Java后端的/api/order/create接口。这保证了核心业务逻辑还是由Java完成,Flask只做页面中转。
这种“双路径”设计一开始听起来有点绕,但实际使用非常灵活。做展示页和可视化看板时用路径一,做C端核心操作时用路径二——既避免了Java返回JSON给Flask再渲染的繁琐,又守住了业务逻辑的边界。
这里给一个具体的操作示例:Flask查询近7天订单量趋势。
python复制from flask import Flask, jsonify, render_template
import pymysql
from datetime import datetime, timedelta
app = Flask(__name__)
DB_CONFIG = {
"host": "localhost",
"user": "root",
"password": "123456",
"database": "housekeep_db",
"charset": "utf8mb4",
"cursorclass": pymysql.cursors.DictCursor
}
@app.route("/trend")
def trend():
# 获取近7天的订单量趋势
sql = """
SELECT DATE(create_time) AS day, COUNT(*) AS cnt
FROM t_order
WHERE create_time >= %s
GROUP BY DATE(create_time)
ORDER BY day
"""
start_date = (datetime.now() - timedelta(days=7)).strftime("%Y-%m-%d")
with pymysql.connect(**DB_CONFIG) as conn:
with conn.cursor() as cursor:
cursor.execute(sql, (start_date,))
rows = cursor.fetchall()
# 补全缺失日期,保证图表没有空洞
result = []
for i in range(7):
day = (datetime.now() - timedelta(days=7 - i)).strftime("%Y-%m-%d")
cnt = 0
for row in rows:
if str(row["day"]) == day:
cnt = row["cnt"]
break
result.append({"day": day, "count": cnt})
return render_template("trend.html", data=result)
这段代码最大的坑在于日期补全。MySQL里的GROUP BY只会返回有订单的日期,没有订单的日期不会出现在结果集里。如果直接把rows交给ECharts,图表上会出现“断档”——上周三没单,曲线中间就缺一块,演示时非常难看。所以我在Python里做了循环补全,保证七天都在。
3.4 核心接口设计要求
SSM端接口我用REST风格,统一返回Result对象:
java复制public class Result<T> {
private Integer code; // 200成功,400参数错误,500异常
private String message;
private T data;
public static <T> Result<T> success(T data) {
Result<T> result = new Result<>();
result.code = 200;
result.message = "success";
result.data = data;
return result;
}
// ... error方法省略
}
接口路径按资源命名:
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /api/user/register | 注册 |
| POST | /api/user/login | 登录 |
| GET | /api/service/list | 服务列表(含分类筛选) |
| POST | /api/order/create | 用户下单 |
| POST | /api/order/assign | 管理员派单 |
| POST | /api/order/status | 订单状态流转 |
| GET | /api/order/mylist | 我的订单(按用户查) |
| POST | /api/comment/add | 提交评价 |
这个接口清单不复杂,但覆盖了整个业务闭环。如果时间充足,还可以再补一个“管理员统计各服务项目被下单次数”的聚合接口,用一条MyBatis的GROUP BY就能实现,效果又好又简单。
4. 核心功能实现:关键代码与操作步骤
4.1 用户下单全流程代码拆解
先从前端(Flask预约页)说起。页面上用户填表,Flask接住数据后往SSM发请求。这里有一个非常重要的点:不要在前端做业务校验,前端只做格式校验(手机号位数、必填项),真正的业务校验(服务是否上架、时间是否合法、用户是否存在)必须由Java后端做。 为什么?因为前端代码可以被绕过,直接打接口就能伪造请求,后端如果校验不全,系统就是漏的。
Flask端转发请求的核心代码:
python复制@app.route("/api/order/create", methods=["POST"])
def create_order():
# 从表单获取参数
user_id = request.form.get("userId")
service_id = request.form.get("serviceId")
service_time = request.form.get("serviceTime")
address = request.form.get("address")
contact = request.form.get("contact")
phone = request.form.get("phone")
# 转发给Java后端
payload = {
"userId": user_id,
"serviceId": service_id,
"serviceTime": service_time,
"address": address,
"contact": contact,
"phone": phone
}
resp = requests.post("http://localhost:8080/api/order/create", data=payload)
return resp.json() # 直接把Java的Result对象返回给浏览器
Java端收口后,Service层实现createOrder:
java复制@Override
public Result<?> createOrder(OrderCreateDTO dto) {
// 1. 参数校验
if (dto.getUserId() == null || dto.getServiceId() == null) {
return Result.error(400, "参数缺失");
}
User user = userDao.selectById(dto.getUserId());
if (user == null) {
return Result.error(400, "用户不存在");
}
ServiceItem service = serviceDao.selectById(dto.getServiceId());
if (service == null || service.getStatus() != 1) {
return Result.error(400, "服务不可下单");
}
// 2. 服务时间不能早于当前时间
if (dto.getServiceTime().before(new Date())) {
return Result.error(400, "服务时间不能早于当前时间");
}
// 3. 生成订单号,格式:时间+随机数
String orderNo = "HK" + System.currentTimeMillis()
+ String.format("%04d", new Random().nextInt(10000));
// 4. 创建订单,状态默认待接单
Order order = new Order();
order.setOrderNo(orderNo);
order.setUserId(dto.getUserId());
order.setServiceId(dto.getServiceId());
order.setServiceTime(dto.getServiceTime());
order.setAddress(dto.getAddress());
order.setContact(dto.getContact());
order.setPhone(dto.getPhone());
order.setStatus(OrderStatus.PENDING);
order.setCreateTime(new Date());
orderDao.insert(order);
return Result.success(orderNo);
}
整个过程最容易被忽略的细节是订单号。如果用数据库自增ID直接当订单号,演示时客户手机收到的“订单号”只是一个数字,看起来很业余。而且自增ID一旦删除数据会有空洞,不好看。用“时间戳+随机数”生成一个带HK前缀的单号,既唯一又专业。
4.2 派单逻辑和保洁员列表接口
管理员看到订单后,进入“待接单”列表,操作是“派单给保洁员”。派单时前端要展示可选保洁员列表,这个列表不能只拉保洁员表,还要带上保洁员的“今日已接单数”“平均评分”——否则管理员不知道谁闲着谁已经忙不过来了。
SQL写法:
xml复制<select id="selectAvailableWorkers" resultType="com.housekeep.entity.User">
SELECT u.id, u.nickname, u.phone,
IFNULL(w.total_orders, 0) AS totalOrders,
IFNULL(w.avg_rating, 5.0) AS avgRating
FROM t_user u
LEFT JOIN t_worker_stats w ON u.id = w.worker_id
WHERE u.user_type = 2
ORDER BY totalOrders ASC
LIMIT 10
</select>
这里我专门建了一个t_worker_stats视图表,用来冗余存储保洁员的接单量和平均评分。为什么要冗余?因为每次派单都实时COUNT订单表、AVG评价表的话,数据量大了以后会很慢,而且这个统计在演示场景下没必要每次实时算。用一张统计表,在订单完成时异步更新一条数据,页面展示直接从统计表查,响应速度快很多。这就是典型的“空间换时间”思路。
派单成功后要更新两个地方:订单表的状态改为“已派单(1)”,同时把worker_id写入订单记录,这样保洁员登录后能看到“派给我的单子”。这一步也是一次事务:先查订单状态,再更新订单,再记录操作日志,任何一个失败都要回滚。SSM里直接在Service方法上打@Transactional注解即可。
4.3 统计面板的ECharts接入
Flask负责的统计面板是展示亮点。我用的是ECharts(前端图表库),在Jinja2模板里加载数据后渲染。模板核心思路:Python把数据以JSON格式传给模板,模板里用JSON.parse解析后初始化图表。
templates/statistics.html页面中,只需要把上面的/trend接口返回的数据赋给JavaScript里的一个数组:
html复制<script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
<div id="trendChart" style="width: 100%; height: 400px;"></div>
<script>
const trendData = {{ data | tojson }};
const chart = echarts.init(document.getElementById('trendChart'));
chart.setOption({
title: { text: '近7天订单量趋势' },
tooltip: {},
xAxis: { data: trendData.map(item => item.day) },
yAxis: {},
series: [{
name: '订单量',
type: 'line',
data: trendData.map(item => item.count)
}]
});
</script>
Jinja2模板引擎有个细节坑:默认情况下{{ data | tojson }}会生成带引号的JSON字符串,如果在<script>标签中直接赋值,可能因为<符号(比如日期里有)被HTML转义而报错。我试过好多次踩坑,最终方案是在Python视图里用json.dumps(data),然后把结果通过render_template传过来,再用| safe过滤器渲染。如果直接用tojson,必须用{{ data | tojson }}完整写法(自动处理XSS转义),两种方式都行,但别混。
4.4 完整的本地启动流程
这套系统本地跑起来,有几个固定步骤,我整理成清单:
- 启动MySQL,导入
housekeep_db.sql建库建表,并插入基础测试数据。 - 启动Java后端:Idea里打开SSM工程,修改
applicationContext.xml(或application.yml)里的数据库账号密码为本地实际账号。 - 启动Flask服务:在项目根目录执行
python app.py,确保Python环境里安装了flask、pymysql、requests。 - 浏览器访问Flask(默认5000端口)进入客户预约页面和管理统计页面;Java后端跑在8080端口,所有接口通过
http://localhost:8080访问。 - 演示时先注册一个客户账号,在Flask页面下单;再通过MySQL手动把订单状态改为待接单(或直接在Java后端的页面操作),在管理端派单,走完整链路。
如果你是第一次跑这种组合项目,大概率会遇到端口占用或者MySQL版本兼容问题。我的建议是先单独测通路:先确保Java端接口能用Postman调通,再启动Flask,最后才联调页面。别一上来就同时跑两个服务,出问题不好定位。
5. 验证调试与常见问题排查实录
5.1 跨域和Session问题
Flask页面在5000端口,Java在8080端口,浏览器发起fetch或axios请求时属于跨域。好在Flask的转发方式(后端requests请求Java)不存在跨域问题,但如果你想直接在浏览器里用AJAX调Java接口,就必须在SpringMVC里开跨域配置:
java复制@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://localhost:5000")
.allowedMethods("GET", "POST");
}
另一个问题是Session共享。用户在Flask登录,如果用Java的Session记录登录状态,两个服务之间无法直接共享。我给的方案是:Flask登录时调用Java接口校验账号密码,成功后由Java返回userId等信息,Flask自己维护session。因为Java接口是无状态的(用参数传userId),所以Flask负责管理登录态,Java只负责业务处理。
提示:这种做法对于本地演示项目完全够用。但如果你是做生产级系统,就要考虑token机制,比如JWT,原理不变,只是多一个签名校验步骤。
5.2 中文乱码和时区问题
这套项目最常栽跟头的是中文乱码和时区偏差,尤其是XML里配置MyBatis或JdbcTemplate时,如果数据库URL没有带useUnicode=true&characterEncoding=UTF-8,插入中文就会变成问号。
code复制jdbc:mysql://localhost:3306/housekeep_db?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
另外serverTimezone=Asia/Shanghai一定要加。MySQL 8.x默认时区是UTC,Java的new Date()是本地时间,插入数据库时差8小时,订单时间会显示成“提前8小时”。这是特别隐蔽的bug,可能你测试录入时没在意,但演示时用户看到服务时间“早上9点”变成“凌晨1点”,直接露馅。
5.3 Flask模板和静态资源加载失败
Flask的render_template默认从templates目录找模板,静态资源(CSS、JS)放static目录。如果你在页面里直接写<link href="style.css">,会404,必须改成<link href="{{ url_for('static', filename='style.css') }}">。这是每个Flask新手躲不过去的坑,写在这里帮大家提个醒。
ECharts的CDN在离线环境可能加载失败。如果演示场地网络不好,建议把echarts.min.js下载下来放到static/js目录,保证离线可用。我参加答辩时学校机房经常屏蔽外网,一堆项目因为依赖在线CDN而白屏,临时补救非常狼狈,一定提前把资源本地化。
5.4 常见异常速查表
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 页面能打开但接口返回404 | Java端Controller映射路径和请求路径不一致 | 检查@RequestMapping,注意项目名是否需要加/项目名前缀 |
| 中文乱码 | 数据库连接URL缺少编码参数 | 在JDBC URL加characterEncoding=UTF-8 |
| 订单时间差8小时 | 时区配置缺失 | JDBC URL加serverTimezone=Asia/Shanghai |
| Flask登录后Java查询不到用户 | 两个服务Session不共享 | 用Flask维护session,Java接口改为无状态传参 |
| 图表曲线缺日期 | SQL的GROUP BY没有返回无单日期 | Python端循环补全日期 |
| 下单提示服务不存在 | 服务项目status为0下架状态 | 检查测试数据,确保服务项status=1 |
| INSERT订单失败外键冲突 | 物理外键约束 | 演示建议去掉物理外键,用逻辑外键 |
6. 答辩与演示加分项经验分享
6.1 演示顺序和脚本设计
这个项目演示是有脚本讲究的,不能上来就瞎点。我的建议是:
- 先讲业务背景:保洁、保姆、月嫂等家政服务市场需求,线下痛点(预约靠电话、派单靠人工),引出平台价值。
- 展示SSM后端模块结构,用Postman打一个下单接口,证明后端逻辑完整。
- 打开Flask客户页面,注册/下单,展示完整流程。
- 切到管理端,接单、派单,展示订单状态从“待接单”变成“已派单”。
- 展示统计面板,看ECharts图表动态展示最近7天数据。
- 最后讲一个技术难点:解释为什么用Flask而非纯Vue,或者订单状态机如何设计。
这个顺序每一段都在“讲故事”——从痛点→后端→前端→业务闭环→统计亮点,逻辑完整且不会让评委觉得你在背代码。
6.2 数据可视化代码现场的亮点
数据可视化是这个项目最亮眼的加分项。我有一次答辩,评委对项目功能不感兴趣,但看到“收入趋势图”后来了兴致,问“这个图表数据怎么来的”。我从SQL的GROUP BY DATE(create_time)讲到Python补全日期,再讲到前端ECharts渲染,整个过程非常流畅。
建议再做两个图:
- 各服务项目订单占比(饼图),SQL直接用
GROUP BY service_id联合服务表查名字。 - 保洁员接单排行(柱状图),这个图能体现平台管理能力,也方便论证“派单给谁”的依据。
Python代码部分我用的是pymysql原生SQL,没有上ORM(比如SQLAlchemy),原因是核心逻辑在SSM端,Flask只是读数据汇总,用原生SQL反而直观、调试也方便。而且答辩时评委老师看到你能写原生SQL,比看到你用ORM一层封装更有说服力。
6.3 常见答辩问题预备
根据我带过的项目经验,整理几个评委大概率会问的问题和参考回答:
问:为什么不用前后端分离架构(Vue + SpringBoot)?
答:家政平台属于中小型业务,核心价值在业务逻辑和数据分析,Flask能快速完成C端页面与统计图表,降低了部署复杂度。同时SSM作为后端保证了订单和用户管理等核心数据的强事务性。
问:SSM和Flask之间怎么通信的?
答:两种方式,Flask展示页通过HTTP调用Java接口完成下单操作;统计面板直接读取MySQL数据库做聚合查询。这样既保证了核心业务的统一入口,也简化了分析型查询的实现。
问:订单状态怎么管理?
答:使用状态机思想,定义了合法状态流转路径(待接单→已派单→服务中→已完成),状态切换前统一校验,避免非法跳转。
问:系统能不能扩展成多门店?
答:可以,在现有表结构增加门店表、门店与保洁员关联表,订单归属门店维度即可。数据库和接口都预留了扩展空间。
这几个问答基本能把项目核心亮点讲清楚,而且有理有据,不是背题。
7. 部署发布与环境配置指引
7.1 生产环境部署思路(简易版)
虽然这类项目通常只要求本地运行,但如果你未来想把它部署到服务器上给真正的家政公司用,部署思路也不复杂:
- 数据库:MySQL安装在云服务器,导入建表SQL。
- Java后端:打war包丢进Tomcat的webapps目录,或打成jar包配合内置Tomcat运行。
- Flask服务:用
gunicorn启动,绑定0.0.0.0:5000端口。 - 反向代理:用Nginx监听80端口,
/api/路径转发到Java,其他路径转发到Flask。
Nginx配置示例:
nginx复制server {
listen 80;
server_name yourdomain.com;
location /api/ {
proxy_pass http://127.0.0.1:8080;
}
location / {
proxy_pass http://127.0.0.1:5000;
}
}
这样用户只需访问一个域名,后端却跑两个服务,无缝切换。这个部署方案在简历上也能写一笔——“基于Nginx反向代理实现双服务路由分发”,有一定含金量。
7.2 环境配置清单表
| 组件 | 版本建议 | 说明 |
|---|---|---|
| JDK | 1.8 | SSM框架对JDK8最友好 |
| Maven | 3.6+ | 依赖管理 |
| Tomcat | 8.5/9.0 | Java Web容器 |
| MySQL | 5.7或8.0 | 注意时区配置差异 |
| Python | 3.8+ | Flask 2.x |
| Flask | 2.x | 与Python3.8+兼容良好 |
| PyMySQL | 1.x | 连接MySQL |
| ECharts | 5.x | 前端图表库 |
以上版本组合我实测过,兼容性最好。别乱升级,比如Python 3.12配旧版Flask或某些依赖包可能报错,本地调试会白白消耗大量时间。
8. 个人实操体会与后续扩展
这套“Java+SSM+Flask家政公司服务平台”做下来,我最深的感受是:技术选型的核心不是“有多酷炫”,而是“能否完整交付”。 SSM撑住了最核心的业务逻辑,Flask补上了快速构建C端页面和图表的短板,两者结合恰到好处,既不显得技术单一,也不至于过度设计。
后续如果要扩展,我有几个可以落地的方向:
- Spring Boot重构后端:SSM的老一套配置确实繁琐,Spring Boot能大幅减少配置量,而且自带健康检查、指标监控。
- 引入Redis缓存服务列表和订单热数据:家政平台的首页服务列表访问频率高,缓存后响应速度会明显更快。
- 增加短信通知模块:订单状态变化时给客户发短信,很实用。
- Flask端接入用户画像:根据客户历史订单偏好推荐服务项目,用简单的相似度计算就能实现,和现在的统计模块无缝衔接。
最后再分享一个小技巧:项目里所有接口的返回值,务必统一用Result对象,不要有的接口返回Map,有的返回JSONObject。后期调试和页面渲染统一性会好很多,这个习惯我在后续所有项目里都保持了。做完这个家政平台,你对业务流程设计、跨服务协作、数据可视化三个方向的实战理解都会上一个台阶。
