概述
昨天用户已经"资料完整",但产品还缺一块控制面板:谁能给我发消息、通知要不要推送、看谁不顺眼能不能屏蔽。今天补上这块"隐私与打扰的边界控制",同时引入一个全新的存储引擎 MongoDB——它不只是给今天的功能用,更是为后面的圈子动态铺路。
纲要
- 衔接:之前的产出如何被现在直接复用
- 昨日回顾:OSS、人脸识别、资料 CRUD、拦截器鉴权、统一异常(只列清单)
- 今日任务书:五个板块的做什么 / 产出物 / 验收标准
- 通用设置(查询 + 保存通知开关)
- 陌生人问题(一用户一条的保存与更新)
- 通知设置(幂等落库)
- 黑名单(分页查询 + 取消拉黑)
- MongoDB 入门(安装、体系结构、shell CRUD、索引、SpringData-Mongo)
- 依赖关系图与工程产出预告
- 学习建议与常见误解澄清
从昨天到今天:产品视角的衔接
之前结束时,用户能完善资料、上传头像、查看和修改个人信息。但从产品角度看,用户的"自主权"还是零:平台推什么就看什么,谁都能来搭讪,通知发不发也只能全盘接收。
今天做的通用设置模块就是解决这件事。按讲义的定义,它包含三块:
- 设置陌生人问题:其他用户想在线交流时,必须先回答这个问题,相当于一道门槛;
- 通知设置:喜欢、评论、公告三类推送的开关;
- 黑名单:对不感兴趣的用户屏蔽骚扰。
存储层面有个容易忽略的细节:这三块今天全部落在 MySQL(tb_settings、tb_question、tb_black_list三张表),而今天引入的 MongoDB 暂时不给它们用——它服务于"今日佳人"这个功能(推荐好友列表是大数据系统算好存进 Mongo 的,今天只是第一次用 Java 去读),真正的重头戏在后面的圈子动态。
还要交代一个边界:讲义里黑名单部分只包含分页查询和移除黑名单两个接口。"把人拉进黑名单"这个动作本身挂在后续的互动功能里(比如对某条动态操作时触发),今天先把名单的管理能力建好。
回顾:之前做了什么
只列清单,细节各有专篇,这里不展开:
| 板块 | 做了什么 | 产出物 | 可复用套路 |
|---|---|---|---|
| 阿里云 OSS | 头像上传到对象存储,抽取成自动装配组件 | OssTemplate | 第三方 SDK 封装成 template + starter |
| 百度人脸识别 | 上传头像前做人脸检测校验 | AipFaceTemplate | 同上,模板工具类 + 配置属性类 |
| 用户资料 CRUD | 保存、查询、更新tb_user_info | UserInfoApi+UserInfoVo | Controller → Service → Dubbo API → Mapper |
| 统一 token 处理 | 拦截器校验 JWT,ThreadLocal存当前用户 | TokenInterceptor+UserHolder | 任何接口里一行UserHolder.getUserId()拿人 |
| 统一异常处理 | 业务异常集中兜底 | BusinessException+ExceptionAdvice+ErrorResult | Service 抛异常,Controller 不用写 try-catch |
今天写的每一个接口,鉴权和异常兜底都是白捡的——拦截器放行后直接取用户 ID,出问题直接抛BusinessException。
今日任务书
本篇的核心。五个板块,每个都有可验证的验收标准:
| 板块 | 做什么 | 产出物 | 验收标准 |
|---|---|---|---|
| ① 通用设置 | 查询设置项 + 保存三类通知开关 | GET /users/settings、SettingsController、SettingsVo、tb_settings | 新用户首次查询返回默认值(三个开关均为开);保存后刷新页面不丢 |
| ② 陌生人问题 | 保存/更新问题内容 | POST /users/questions、QuestionApi、tb_question | 保存后能查回;同一用户重复保存不产生重复行(有则更新、无则插入) |
| ③ 通知设置 | 单独保存通知开关 | POST /users/notifications/setting | 开关正确落库;重复提交结果一致(幂等),不报错、不产生脏数据 |
| ④ 黑名单管理 | 分页查询黑名单 + 取消拉黑 | GET /users/blacklist、DELETE /users/blacklist/{uid}、BlackListApi、PageResult | 分页数据正确且带对方资料(关联tb_user_info);取消后该用户从列表消失 |
| ⑤ MongoDB 入门 | 认识文档数据库 → Docker 安装 → 体系结构与数据类型 → shell 增删改查 → 索引与执行计划 → SpringBoot 整合 | 单机 MongoDB 环境 +mf-dubbo-mongo模块 | 能连上库并完成基本 CRUD;Java 端用 SpringData-Mongo 存取文档成功 |
②③ 有个共同的设计点提前说:SettingsService里的保存逻辑都是"先按userId查,查到就update,查不到就save"。这样新用户第一次保存也不会因为没有记录而报错,这就是设置类功能最典型的"默认值 + 幂等"处理。
⑤ 按讲义的实际编排,覆盖 MongoDB 简介、Docker 安装、体系结构、数据类型、入门 CRUD、索引、执行计划,以及 SpringData-Mongo 整合;讲义最后用"今日佳人"功能做了首个实战——推荐好友数据存在 Mongo 的recommend_user集合里,工程上新增了mf-dubbo-mongo这个独立 Dubbo 服务模块来读它。这块在下面的产出预告里能看到对应代码。
依赖关系
一句话概括:设置与黑名单是"旧地基上的新房间",直接复用 day02 的鉴权、异常和分层套路;MongoDB 是"新地基",今天打地基,后面圈子功能的高楼盖在它上面。
接口速览
| 方法 | 路径 | 作用 |
|---|---|---|
| GET | /users/settings | 查询通用设置(陌生人问题 + 三类通知开关) |
| POST | /users/questions | 保存/更新陌生人问题 |
| POST | /users/notifications/setting | 保存通知开关 |
| GET | /users/blacklist?page=&pagesize= | 分页查询黑名单列表 |
| DELETE | /users/blacklist/{uid} | 取消黑名单 |
工程产出预告
对照 之前 的代码快照,今天结束时工程里会多出这些类(以之前代码实读为准):
mf ├── mf-app-server │ └── src/main/java/com/mf/server │ ├── controller/SettingsController.java # 设置面板唯一入口,挂 5 个接口 │ ├── controller/mfController.java # 今日佳人接口(MongoDB 首个实战) │ ├── service/SettingsService.java # 设置/问题/通知/黑名单的业务逻辑 │ └── service/mfService.java # 今日佳人业务逻辑 ├── mf-dubbo │ ├── mf-dubbo-interface │ │ └── com/mf/dubbo/api │ │ ├── SettingsApi.java # 设置项的按 userId 查/存/改 │ │ ├── QuestionApi.java # 陌生人问题的查/存/改 │ │ ├── BlackListApi.java # 分页查黑名单、移除 │ │ └── RecommendUserApi.java # Mongo 侧推荐用户查询接口定义 │ ├── mf-dubbo-db │ │ └── com/mf/dubbo │ │ ├── api/SettingsApiImpl.java # 操作 tb_settings │ │ ├── api/QuestionApiImpl.java # 操作 tb_question │ │ ├── api/BlackListApiImpl.java # 操作 tb_black_list,分页返回 UserInfo │ │ └── mappers/SettingsMapper.java 等 # 三张新表对应的 Mapper │ └── mf-dubbo-mongo # 新模块:独立的 Mongo Dubbo 服务 │ ├── DubboMongoApplication.java # 独立启动类 │ └── api/RecommendUserApiImpl.java # 用 SpringData-Mongo 读 recommend_user └── mf-model └── src/main/java/com/mf/model ├── domain/Settings.java # 通知设置实体,三个 Boolean 开关 ├── domain/Question.java # 陌生人问题实体(userId + txt) ├── domain/BlackList.java # 黑名单实体(userId + blackUserId) ├── mongo/RecommendUser.java # Mongo 文档实体,@Document 注解 └── vo/SettingsVo.java、PageResult.java、TodayBest.java # 返回值对象注意mf-dubbo-mongo是个独立模块、独立进程——MySQL 的 API 和 Mongo 的 API 分属两个 Dubbo 服务,存储引擎不同就连部署单元也分开,这个分层决定后面会一直沿用。
学习建议
- 设置类功能小而多,套路雷同,重点不是写出多少接口,而是吃透默认值与幂等:新用户没有记录时查询给默认值、保存走"有则更新无则插入",这两招以后做任何用户偏好类功能都用得上。
- 黑名单重点学分页查询 + 关联查询:
BlackListApiImpl里要拿着黑名单的blackUserId列表去tb_user_info捞资料,这个"先查 ID 再补详情"的模式很常见。 - MongoDB 是全新的概念体系(集合、文档、BSON、
_id),先照着讲义把环境跑起来、CRUD 敲一遍,体系结构的细节用到再回头深究,别卡在概念上。 - 遇到报错先看 Dubbo 服务有没有起全——今天多了一个
mf-dubbo-mongo进程,忘了启动就是NoSuchProviderException这类找不到提供者的错。
常见误解澄清
| 误解 | 实际情况 |
|---|---|
| “设置就是几个开关的小功能” | 设置是产品的隐私与打扰边界:陌生人问题是社交门槛,通知开关决定打扰策略,做错了直接影响用户体验和数据一致性 |
| “黑名单只是一个列表” | 黑名单会在推荐、互动等多个环节被过滤使用;今天的接口只是管理名单本身,真正的拦截发生在后续功能里 |
| “MongoDB 就是另一个 MySQL” | MongoDB 是文档模型:没有表和行的概念,是集合和 BSON 文档,无 schema、_id自动生成,查询语法是完全另一套 |
| “设置类接口不用考虑并发” | 用户双击保存、断网重试都会造成重复提交,"有则更新无则插入"加幂等设计就是为此准备的 |
| “新模块可以塞进现有工程里省事” | Mongo 服务独立成mf-dubbo-mongo是刻意的:引擎不同、依赖不同、后续扩容节奏也不同,拆开才能各自演进 |
从哪篇开始
目前实质内容《通用设置:需求分析》已经就位,直接从它开始——先看三张表怎么设计、为什么实体类都继承BasePojo,然后按 1.2 → 1.5 的顺序把五个接口依次写完,最后进入 MongoDB 部分。
总结
- 之前 解决"资料完整",现在解决"边界可控":设置、陌生人问题、通知、黑名单四块合成用户的控制面板。
- 今天的功能全部复用 之前 的鉴权、异常与 Dubbo 分层,增量只有三张表、五个接口和一套"默认值 + 幂等"的处理方式。
- MongoDB 今天完成环境搭建与入门,实战落点是今日佳人;圈子动态才是它的主场。
- 验收标准逐条过:新用户查设置有默认值、保存后不丢、重复提交幂等、黑名单分页正确且可取消、Mongo 能连能存取。