本节不罗列完整源码,而是按“整体流程 → 模块职责 → 关键步骤 → 边界处理”的顺序,说明核心功能的代码实现思路,便于后续维护与二次开发直接定位逻辑。
(1)总体架构与调用链
系统采用常规分层结构,一次典型请求的处理链路如下:Controller(参数接收/返回)→ Service(业务规则)→ Mapper/DAO(数据持久化)→ Database。
各层之间通过 DTO/VO 传输数据,异常统一上抛,由全局异常拦截器(GlobalExceptionHandler)封装为统一响应格式,避免在业务代码里写过多 try-catch。
(2)核心流程示例:以用户登录为例
登录模块的代码逻辑按以下步骤执行:
① 入参校验:Controller 接收 LoginDTO,利用 @Valid 注解校验账号、密码非空及格式;校验失败直接返回 400,不进入后续流程。
② 身份查询:Service 层根据账号查询数据库;若结果为空,抛出自定义异常 BusinessException(“账号或密码错误”),不区分“账号不存在”还是“密码错误”,防止账号被枚举。
③ 密文比对:使用 BCrypt.checkpw() 将前端传入的明文密码与数据库哈希值比对;匹配失败同样返回上述模糊提示。
④ 会话生成:比对通过后,生成 JWT(有效期 2 小时),同时将该 token 写入 Redis 并设置相同过期时间,用于后续接口鉴权与单点登录控制。
⑤ 响应前端:将 token 与必要的用户基本信息(如 userId、role)封装为 LoginVO 返回;前端后续请求在 Header 中携带该 token,由拦截器统一校验。
(3)关键技巧与边界处理
- 空指针防护:数据库查询结果统一使用
Optional.ofNullable(...)包装,避免链式调用出现 NPE。 - 事务一致性:涉及多表更新的操作(如下单时扣库存、写订单主表、写日志表),在 Service 方法上标注
@Transactional,任一环节抛出异常即自动回滚。 - 幂等控制:对于重复提交敏感接口(如支付、下单),前端需传入唯一幂等键
Idempotency-Key,后端先查 Redis:若键存在则直接返回上次结果,若不存在则执行业务并写缓存(过期 30 秒),防止网络重试导致重复数据。 - 敏感操作日志:在 Service 关键节点(如修改密码、删除数据)通过切面
@Aspect异步记录操作日志,不影响主流程性能。
写作提示:如果你的项目不是 Web 后端(如 Python 爬虫、嵌入式 C、算法脚本等),只需替换分层名称(如
main()→parse()→save()),并保留“先校验、再处理、最后兜底”的叙述结构即可。