1.1 项目简介
云岚到家是一个互联网+家政 的o2o平台
-
家政:随着人口老龄化的严重,家政行业越来越火,对应的互联网平台随之产生,比如:58到家,天鹅到家等
-
互联网+:指的是"互联网+传统行业",即利用互联网的优势对传统行业进行优化升级转型
-
o2o(Online To Offline):指的是将线下的机会与互联网的技术结合在一起,让互联网成为线下交易的前台,同时起到推广和成交的作用
目前家政服务O2O平台的运营模式,主要有两种:
-
C2B2C:消费者(Consumer,家政人员)---企业(Business,平台方)---消费者(Consumer,需求方)
-
B2B2C:企业(Business,家政公司)---企业(Business,平台方)---消费者(Consumer,需求方)

本项目采用两种结合的方式实现

本项目包括四个端:
-
家政平台方(运营端):通过管理端完成服务人员管理、机构管理、订单管理等操作,它通过订单的抽成进行获利
-
家政需求方(用户端):通过用户端小程序完成在线预约下单、支付、评价、投诉、退款等操作
-
家政服务人员(阿姨端):通过服务端APP完成在线接单、结算等操作
-
家政服务公司(中介端):通过机构端完成在线接单、派单、投诉处理、结算等操作
项目核心业务流程如下:
-
平台方在运营区域上架家政服务,比如:在北京上架日常保洁、空调维修等项目
-
用户通过定位区域获取当前区域的服务项目,选择家政服务,下单、支付
-
家政服务人员及家政服务公司通过平台抢单
-
家政服务人员现场服务,平台跟踪管理整个服务过程
-
服务完成,用户评价、售后服务等
1.2 项目模块
根据每个端去细化模块,项目业务模块图如下:
-
运营端:主要进行服务类型、服务项目、服务企业(人员)以及优惠券的管理
-
用户端:主要进行服务搜索下单、抢券用券以及支付评价等操作
-
机构端:主要进行接单、抢单以及服务人员的管理
-
服务端:主要进行接单、抢单管理

1.3 项目架构
该项目是基于spring Cloud Alibaba架构的微服务项目,采用前后端分离模式开发,系统架构图如下:

**用户层:**包括四个端:运营端(PC)、服务端(APP)、机构端(PC)、用户端(小程序)
**负载层:**Nginx实现反向代理、负载均衡
服务层:包括网关、业务微服务、基础服务
-
网关:请求路由、统一鉴权
-
基础服务:Nacos、Sentinel、RabbitMQ、ES、Canal、XXL-JOB(任务调度)
-
业务微服务:运营基础服务、客户管理服务、订单管理服务、抢单服务、派单服务、支付服务等
数据层:
-
MySQL实现基础数据存储、ShardingShphere进行分库分表
-
TiDB分布式数据库实现历史订单信息归档
-
RabbitMQ实现存储数据同步消息、各类异步消息
-
Redis实现服务信息、订单信息、服务单信息的缓存
1.4 熟悉项目
1.4.1 需求分析
以服务模块为例了解这个模块的需求
服务管理模块为运营人员提供基础数据管理功能,包括:服务类型管理、服务项管理、区域管理等子模块
-
服务项就是服务项目,也就是本平台提供的家政服务项目,如:空调维修、电视维修、空调清洗、洗衣机清洗等等

-
服务类型就是对服务项目的分类,如:空调维修和电视维修都属于家电维修分类,空调清洗和洗衣机清洗属于家电清洗分类

-
区域就是对服务地区的划分

1.4.2 库表设计
服务管理模块一共涉及到了四张数据表
-
serve_type:服务类型表
-
serve_item: 服务项目表
-
region:区域表,存储运营地区信息,一般情况区域表行政级别是市
-
serve: 服务表,存储了各个区域运营的服务及相关信息
表关系如下:
-
serve_type与serve_item之间是一对多的关系
-
serve_item与region之间是多对多的关系,serve是中间表,但它又不仅是中间表,他还有自己的业务字段,比如服务价格等等

1.4.3 工程结构

1.5 功能开发
1.5.1 分页查询
本接口用于分页查询某个区域下目前所有的服务项目
1)接口文档
接口路径:GET /foundations/operation/serve/page
请求参数:application/x-www-form-urlencoded

响应参数:

思路分析
根据接口文档中的参数和响应部分的字段,我们分析得知,需要从三张数据表中进行查询,且表关系如下

根据表关系我们来写以下的接口语句:
sql
select
s.*,
si.serve_type_id as serveTypeId,
si.name as serveItemName,
si.reference_price as referencePrice,
st.name as serveTypeName
from serve s
inner join serve_item si on s.serve_item_id = si.id
inner join serve_type st on si.serve_type_id = st.id
where s.region_id = 192565656595654656
3)代码开发
ServeController
接收参数:ServePageQueryReqDTO
返回结果:ServeResDTO
在jzo2o-foundations微服务下创建com.jzo2o.foundations.controller.operation.ServeController
java
@PostMapping("/batch")
@ApiOperation("区域服务新增")
public Result add(@RequestBody List<ServeUpsertReqDTO> dtoList) {
serveService.add(dtoList);
return Result.ok();
}
IServeService
java
/**
* 区域服务新增
*
* @param dtoList 区域服务集合
*/
void add(List<ServeUpsertReqDTO> dtoList);
ServeServiceImpl
java
//这个业务方法中是多次对数据库进行保存操作,务必进行事务处理
@Transactional(rollbackFor = Exception.class)
@Override
public void add(List<ServeUpsertReqDTO> dtoList) {
//遍历集合 拿到每一个区域服务(服务项目id 区域id 价格)
for (ServeUpsertReqDTO dto : dtoList) {
//1. 服务项目必须是启用状态的才能添加到区域
//根据服务项目id去serve_item查询记录
ServeItem serveItem = serveItemMapper.selectById(dto.getServeItemId());
if (ObjectUtil.isNull(serveItem) || serveItem.getActiveStatus() != 2) {
throw new ForbiddenOperationException("添加失败,服务项目状态有误");
}
//2. 一个服务项目对于一个区域,只能添加一次
//根据指定的服务项目id和区域id进行统计,如果统计结果是>0 代表当前项目在当前区域已经存在,就不能再次添加了
Integer count = this.lambdaQuery()
.eq(Serve::getServeItemId, dto.getServeItemId())
.eq(Serve::getRegionId, dto.getRegionId())
.count();
if (count > 0) {
throw new ForbiddenOperationException("添加失败,当前服务项目已经存在");
}
//3.向serve数据表进行保存
//Serve serve = new Serve();
//serve.setServeItemId(dto.getServeItemId());//serve_item_id
//serve.setRegionId(dto.getRegionId());//region_id
//serve.setPrice(dto.getPrice());//price
Serve serve = BeanUtil.copyProperties(dto, Serve.class);
//city_code: 需要根据regionId从region表查询
Region region = regionMapper.selectById(dto.getRegionId());
if (ObjectUtil.isNotNull(region)){
serve.setCityCode(region.getCityCode());
}
baseMapper.insert(serve);
}
}
3)代码测试
重新启动jzo2o-foundations微服务,然后为郑州市添加厨卫维修服务,结果如下
重新启动jzo2o-foundations 微服务,然后为郑州市添加厨卫维修服务,结果如下