ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

学习项目第二天,今天将user板块看完

学习项目第二天,今天将user板块看完 前言本文承接《学习项目第一天先部署并了解项目commen块部分代码》继续围绕后端AImeeting项目源码补充分布式客户端、认证权限体系、并发线程池、启动初始化等基建组件并完整拆解用户模块三层架构落地实战从基础设施到底层业务实现全链路贯通。上篇已覆盖工程分层规范、统一异常与响应体系、登录用户自动注入、MP 持久层自动化、Redis 缓存常量、布隆过滤器防穿透基础。本篇不再重复赘述仅聚焦新增知识点与业务模块落地实践。本文目录分布式基础设施Redisson 单机客户端配置认证权限体系Sa-Token 框架、双会话架构、权限门面设计运行时基建启动目录初始化、业务隔离线程池、WebSocket 长连接配置用户模块实战标准三层架构完整拆解核心业务深度解析注册、登录、分页查询持久层核心baseMapper 原理与 MP 分层设计架构反思典型设计问题与优化方向一、分布式基础设施Redisson 单机客户端配置Redisson 是项目所有分布式能力的底层入口上篇提到的分布式锁、布隆过滤器均基于 Redisson 实现。RedissonConfig采用手动装配方式构建RedissonClient适用于未引入 Redisson Starter 的场景。核心设计要点配置外部化与默认兜底通过Value读取 Spring Redis 配置同时设置 localhost、6379、0 号库等默认值兼容本地开发与生产环境配置缺失不会直接启动失败。单机模式连接池精细化配置核心参数最小空闲连接 1、最大连接池 10兼顾性能与资源占用超时分层连接建立超时 10s、命令响应超时 3s区分网络建连与业务执行重试机制命令失败重试 3 次、间隔 1.5s提升网络波动下的稳定性优雅关闭机制Bean(destroyMethod shutdown)在 Spring 容器销毁时自动关闭客户端、释放连接避免 TCP 连接泄漏。密码兼容处理非空才设置密码无缝适配无密码的本地开发环境。关键注意事项禁止与 Redisson Spring Boot Starter 同时启用否则会重复创建客户端实例浪费连接资源。连接地址必须携带redis://协议前缀否则启动会报连接失败。生产环境需根据业务量级调整连接池大小过小易出现线程阻塞过大则会打满 Redis 连接数上限。二、认证权限体系框架扩展与门面封装1. Sa-Token 权限框架与自定义扩展Sa-Token 是国产轻量级权限认证框架核心负责登录身份认证、角色权限校验、会话管理API 极简、开箱即用非常适合中小型项目快速落地。框架本身不存储角色权限数据通过 SPI 接口StpInterface向业务层扩展数据源getPermissionList返回账号拥有的权限码集合对应细粒度接口操作校验getRoleList返回账号拥有的角色标识集合对应粗粒度身份校验StpInterfaceImpl实现类通过AdminPermissionService判断用户管理员身份分配admin/user角色与admin权限码。SaCheckRole、SaCheckPermission注解鉴权时框架会自动回调这两个方法完成比对。注意每次鉴权都会触发接口调用高并发场景必须增加缓存避免频繁穿透数据库权限变更默认不会实时生效需用户重新登录刷新。2. 双会话登录架构与门面设计项目登录链路存在两套会话体系并存的架构特点同时通过门面模式做业务解耦身份校验层UserService.login()负责数据库用户名密码比对确认账号合法性会话创建层LoginSessionService是自定义登录会话门面接口底层委托StpUtil.login()实现业务代码不直接依赖 Sa-Token 静态工具类门面模式的设计价值业务层、Controller 层只面向LoginSessionService接口编程与 Sa-Token 框架完全解耦。未来替换鉴权框架时仅需修改实现类所有上层业务代码无需改动符合开闭原则与依赖倒置原则。双会话冗余的核心问题UserServiceImpl内部仍保留了一套自建 Redis Hash 登录态实现一次登录同时写入「自建 Redis 会话」和「Sa-Token 原生会话」两套数据功能高度重叠维护成本翻倍登出、过期刷新、踢人下线只操作一套时会出现状态不同步自建登录态实际未被前端 token 使用属于无效冗余代码优化方向保留LoginSessionService门面层的解耦优势彻底删除业务层自建 Redis 登录逻辑统一由 Sa-Token 管理全量会话生命周期消除架构冗余。3. PermissionService 权限门面设计PermissionService是权限判断的统一业务门面SaTokenPermissionService为其实现类底层转发调用AdminPermissionService完成管理员身份判定。看似简单的一层转发实则是典型的门面模式落地统一收口所有业务代码权限判断唯一入口避免散落重复的权限查询逻辑依赖倒置上层业务不直接依赖底层权限表服务后续替换权限数据源数据库→缓存→远程权限中心无感知扩展预留后续增加权限缓存、操作审计、白名单降级等能力仅需在门面层修改全链路自动生效它与StpInterfaceImpl职责严格分离前者面向业务代码提供通用能力后者是 Sa-Token 框架的 SPI 扩展专供注解鉴权回调。三、运行时基建初始化、并发与长连接1. 启动目录初始化ApplicationRunnerApplicationStorageInitializer实现 Spring BootApplicationRunner接口在容器初始化完成、对外接收请求之前自动执行递归创建上传临时目录、音频目录、日志目录等运行时必需路径。设计思想故障前置暴露目录创建失败直接抛出IllegalStateException终止启动把磁盘权限、路径配置问题暴露在部署阶段避免运行时出现诡异的 IO 异常幂等创建使用Files.createDirectories()递归创建多级目录目录已存在不报错支持重复启动配置驱动路径全部读取配置属性类不同环境可灵活调整无需修改代码2. 业务隔离线程池体系项目采用「配置属性 实例化配置」双层设计拆分 4 类业务线程池 1 个定时任务线程池是企业级并发治理的标准范式。配置属性层ApplicationThreadPoolProperties通过ConfigurationProperties绑定 yml 配置定义 4 类线程池参数general通用异步任务核心 50、最大 200aiIoAI 大模型 IO 调用核心 24、最大 64cpuCPU 密集计算线程数自动适配机器 CPU 核数query数据库查询异步任务核心 16、最大 48CPU 密集型线程池默认取 CPU 核数核数 * 2IO 密集型设置更大线程数遵循并发调优基本原则。实例化配置层ThreadPoolConfig读取配置参数真正创建线程池 Bean核心设计亮点任务物理隔离不同类型任务独立线程池AI 慢调用、数据库慢查询不会耗尽通用业务线程避免线程饥饿与故障扩散差异化拒绝策略AI-IO 池使用AbortPolicy直接抛异常做降级其余池使用CallerRunsPolicy由提交方线程执行实现背压限流异常兜底钩子重写afterExecute打印任务内未捕获异常解决 JDK 线程池默认吞噬 Runnable 异常的经典坑可观测性埋点接入 Micrometer 监控线程池活跃数、队列长度、任务完成量全部可观测支持线上告警优雅关闭配置等待任务完成超时容器销毁自动 shutdown 释放资源3. WebSocket 长连接配置WebSocketConfig注册ServerEndpointExporterBean自动扫描项目中所有ServerEndpoint注解的 WebSocket 端点适用于 Spring Boot 内置 Tomcat 环境。AI 对话场景下WebSocket 是大模型流式输出的主流方案用于向前端实时推送生成结果。注意 war 包部署外部 Tomcat 时需移除该 Bean避免重复注册报错。四、用户模块实战标准三层架构完整落地用户模块是最典型的 Spring Boot MyBatis-Plus 业务模块严格遵循 Controller → Service → DAO 三层职责隔离全量复用 common 公共底座能力。模块分层总览表格层级包结构核心职责API 控制层api/io/req、api/io/resp、UserController接收 HTTP 请求、参数校验、统一返回、DTO 隔离Service 业务层service/、service/impl/核心业务逻辑、接口与实现分离、事务与异常处理DAO 持久层dao/entity、dao/mapper数据库实体映射、MP 单表 CRUD、数据读写数据模型分层ReqDTO请求入参配合校验注解拦截非法参数RespDTO响应出参脱敏裁剪隔离数据库实体DO数据库实体与表一一对应继承 BaseDO 公共字段1. Controller 层职责边界与接口设计UserController提供用户查询、注册、登录、登出、更新、管理员授权、分页查询完整接口严格遵守「只做路由与封装不写业务逻辑」的规范。设计亮点RESTful 语义化GET 查询、POST 新增、PUT 更新接口语义清晰全量复用公共组件CurrentUser注入登录用户、SaCheckRole角色鉴权、统一 Result 返回DTO 分层隔离公开信息、完整信息、分页信息分别对应不同返回对象按需脱敏典型设计问题敏感接口缺鉴权/actual/{username}返回完整用户数据未加权限控制存在敏感信息泄露风险接口契约不规范登录、校验登录等接口返回MapString,Object而非专用 DTO字段不明确协作成本高新增管理员入参粗糙直接接收纯文本请求体不符合 JSON 接口规范无法做参数校验公开接口无防护用户名查重接口可被批量枚举遍历存在信息泄露风险2. Service 层核心业务逻辑深度解析UserServiceImpl是模块业务核心继承 MPServiceImpl复用基础 CRUD串联布隆过滤器、分布式锁、Redis 缓存、MP 分页等全部基建能力。用户注册三层防护架构注册流程是分布式并发场景的经典案例实现了三层防重复校验布隆过滤器前置拦截快速判断用户名是否可能存在拦截绝大多数不存在的请求用户名维度分布式锁控制并发注册防止同一用户名同时提交穿透数据库数据库唯一键兜底捕获DuplicateKeyException处理布隆误判与锁竞争漏网的极端场景配合Transactional事务保证数据一致性finally 释放锁避免死锁层层防护设计严谨。注意hasUsername方法存在语义反转缺陷 —— 方法名字面含义为「用户名是否存在」实际返回值为!布隆.contains()即「true 代表一定不存在」。注册逻辑通过双重否定碰巧可用但极易误导后续业务调用引发 bug。用户登录明文密码与双会话问题登录流程先按用户名 明文密码查询数据库匹配成功后创建登录会话。核心风险点密码明文存储比对数据库直接存明文密码无 BCrypt 等不可逆加密数据库泄露即全量密码泄露属于安全红线问题Redis 存储敏感数据完整 UserDO含密码序列化存入 Redis扩大了泄露面登出逻辑缺陷登出时删除整个用户 Hash key会导致该用户所有端全部下线而非仅退出当前端更新用户横向越权防护强制校验只能修改当前登录用户自身信息禁止传入其他用户名从业务层阻断横向越权攻击是权限校验的标准写法。3. 分页查询标准写法与经典坑点分页查询基于 MP 分页插件实现支持关键词多字段模糊搜索、创建时间排序。核心注意点多字段 OR 查询必须用queryWrapper.and()包裹否则由于 AND 优先级高于 OR会导致逻辑删除等基础条件失效出现数据越权 bug优化建议使用IPage.convert()内置方法简化 DO → DTO 分页转换代码更简洁不易出错限制分页大小防止恶意大分页拖垮数据库大数据量下全模糊查询替换为 Elasticsearch 全文检索4. DAO 层持久层复用实体继承BaseDO自动拥有 ID、创建时间、更新时间、逻辑删除等公共字段由 MP 自动填充Mapper 继承BaseMapper获得单表 CRUD 能力由启动类MapperScan统一扫描注册严格遵守单表操作原则不掺杂业务逻辑五、持久层核心baseMapper 原理baseMapper是 MPServiceImpl父类中自动注入的持久层成员变量本质就是业务 Mapper 接口的代理实例。工作原理ServiceImplM extends BaseMapperT, T通过泛型约束绑定 Mapper 与实体父类内部通过Autowired自动注入 Mapper 并赋值给protected修饰的baseMapper。子类可以直接访问该变量无需手动注入 Mapper。能力边界拥有 MP 提供的全部单表 CRUD 方法查询、新增、更新、删除、分页、统计支持调用自定义 Mapper 方法多表查询、复杂 SQL 同样可以通过 baseMapper 执行与IService层方法的关系save、getById等高阶方法底层全部委托baseMapper实现两者无性能差异仅封装粒度不同六、整体链路串联一次完整的用户登录请求串联起 Day1 全部基建能力请求进入 Controller参数校验通过Service 层校验用户名密码完成身份认证LoginSessionService 门面层调用 Sa-Token 创建会话写入 Redis返回结果前调用 PermissionService 判断管理员身份统一封装 Result 返回异常则走全局异常处理器后续访问管理员接口Sa-Token 回调 StpInterfaceImpl 完成角色校验布隆过滤器、分布式锁、MP 持久层、Redis 缓存、线程池、WebSocket 等组件共同构成了业务模块运行的完整基础设施底座。七、总结本篇补充了分布式客户端、认证权限体系、并发线程池、启动初始化等基建组件并通过用户模块完整落地了标准三层架构。整套项目基建完善、分层清晰大量复用公共组件符合企业级项目开发规范同时也存在密码明文、双会话冗余、接口鉴权缺失等典型设计问题既是学习规范写法的范本也是架构评审、代码优化的典型案例。
返回列表