Spring Boot 实战(三):Service 分层 + 统一返回 + 异常处理(工程级写法)
tips: 先学习 ioc和di
Spring 核心思想解析:IoC 与 DI 一文讲透(从入门到工程理解)
一、前言
在前两篇中,我们已经完成:
Controller 接口开发 DTO 参数接收 @Valid 参数校验但当前代码仍然存在明显问题:
Controller 承担了业务逻辑 ❌ 返回结构不统一 ❌ 没有异常处理 ❌ 没有日志 ❌👉 本篇将完成一次工程级升级
二、目标
我们将实现:
Controller → Service 分层 ✔
统一返回结构(Result)✔
统一异常处理 ✔
日志输出 ✔
三、统一返回结构(Result)
创建 Result 类
package org.example.arkbackend.common; import lombok.Data; @Data public class Result<T> { private int code; private String message; private T data; public static <T> Result<T> success(T data) { Result<T> r = new Result<>(); r.setCode(0); r.setMessage("成功"); r.setData(data); return r; } public static <T> Result<T> fail(String message) { Result<T> r = new Result<>(); r.setCode(1); r.setMessage(message); return r; } }👉 返回统一格式:
{ "code": 0, "message": "成功", "data": {} }四、Service 层设计
1️⃣ 接口
package org.example.arkbackend.service; import org.example.arkbackend.dto.UserRegisterDTO; public interface UserService { String register(UserRegisterDTO dto); String getUserById(Long id); void deleteUser(Long id); }2️⃣ 实现类
package org.example.arkbackend.service.impl; import lombok.extern.slf4j.Slf4j; import org.example.arkbackend.dto.UserRegisterDTO; import org.example.arkbackend.service.UserService; import org.springframework.stereotype.Service; @Slf4j @Service public class UserServiceImpl implements UserService { @Override public String register(UserRegisterDTO dto) { log.info("开始注册用户:{}", dto.getUsername()); // 模拟业务逻辑 if ("admin".equals(dto.getUsername())) { throw new RuntimeException("用户名已存在"); } return "注册成功:" + dto.getUsername(); } @Override public String getUserById(Long id) { log.info("查询用户ID:{}", id); return "用户ID:" + id; } @Override public void deleteUser(Long id) { log.info("删除用户ID:{}", id); } }五、Controller 重构
package org.example.arkbackend.controller; import jakarta.validation.Valid; import org.example.arkbackend.common.Result; import org.example.arkbackend.dto.UserRegisterDTO; import org.example.arkbackend.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @PostMapping("/register") public Result<String> register(@Valid @RequestBody UserRegisterDTO dto) { return Result.success(userService.register(dto)); } @GetMapping("/{id}") public Result<String> getUser(@PathVariable Long id) { return Result.success(userService.getUserById(id)); } @DeleteMapping("/{id}") public Result<Void> delete(@PathVariable Long id) { userService.deleteUser(id); return Result.success(null); } }👉 Controller 现在只负责:
接收参数 + 调用 Service + 返回结果六、统一异常处理(非常重要)
创建全局异常处理类
package org.example.arkbackend.exception; import org.example.arkbackend.common.Result; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public Result<?> handleException(Exception e) { return Result.fail(e.getMessage()); } }👉 当异常发生:
{ "code": 1, "message": "用户名已存在" }七、日志(Log)
使用 @Slf4j
@Slf4j使用方式
log.info("注册用户:{}", username); log.error("发生异常:{}", e.getMessage());👉 优点:
✔ 可追踪 ✔ 可定位问题 ✔ 可分析行为八、完整执行流程
请求进入 Controller → 参数校验(@Valid) → 调用 Service → Service 执行业务逻辑 → 返回 Result → 异常统一处理九、当前项目结构
controller/ dto/ service/ service/impl/ common/ exception/👉 已具备:
企业级基础架构 ✔十、一句话总结
通过 Service 分层、统一返回结构和全局异常处理,可以将简单接口升级为具备工程规范的后端系统下一篇:
Spring Boot 实战(四):MySQL + MyBatis 接入,打通用户注册最小闭环
数据库(MySQL) + 持久层(Mapper / JPA)👉 实现真实数据存储
