当前位置: 首页 > ops >正文

分层解耦(Controller,Service,Dao)

1. 三层架构核心职责
层级职责说明关键技术 / 注解
Controller(控制器)1. 接收前端请求(HTTP) 2. 封装参数、校验 3. 调用 Service 处理业务 4. 返回视图 / 数据给前端@Controller@GetMapping
Service(业务层)1. 封装复杂业务逻辑 2. 协调 Mapper 完成数据库操作 3. 事务管理、权限校验等@Service@Transactional
Dao(Data Access Object)(数据访问(持久)层)1. 直接操作数据库(增删改查)(SQL 执行) 2. 封装 CRUD 操作 3. 结果映射为 Java 对象@Mapper、XML 映射或注解(@Select

在这里插入图片描述

基于 MVC 三层架构,流程说明:

  1. 前端:发起 HTTP 请求(如浏览器访问 /list)。
  2. Controller 层:接收请求,调用 Service 处理,最终返回 JSON 响应。
  3. Service 层:封装业务逻辑(解析文件、数据处理),依赖 Dao 获取原始数据。
  4. Dao 层:专注数据访问(本例读 user.txt,未来可扩展数据库操作)。
  5. 资源层:存放文件或数据库,提供原始数据。

原代码:

package com.itxiaoli.controller;import cn.hutool.core.io.IoUtil;
import com.itxiaoli.pojo.User;
import lombok.Data;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;/*** 用户信息controller*/
@RestController
public class UserController {@RequestMapping("/list")public List<User> list() throws FileNotFoundException {//1.加载并读取user.txt文件来获取用户数据//InputStream in= new FileInputStream("绝对路径"); 不推荐,打包之后绝对目录会找不到InputStream in = this.getClass().getClassLoader().getResourceAsStream("user.txt");ArrayList<String> lines = IoUtil.readLines(in, StandardCharsets.UTF_8, new ArrayList<>());//2.解析用户信息,封装成用户对西昂 ->list集合List<User> userList = lines.stream().map(line -> {String[] parts = line.split(",");Integer id = Integer.parseInt(parts[0]);String username = parts[1];String password = parts[2];String name = parts[3];Integer age = Integer.parseInt(parts[4]);LocalDateTime updateTime = LocalDateTime.parse(parts[5], DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));return new User(id, username, password, name, age, updateTime);}).toList();//3.将list集合中的数据返回为(json)格式return userList;}
}
2.分层解耦优势详解
1. 职责分离(单一职责原则)

原代码

// UserController承担多重职责(文件读取、数据解析、HTTP处理)
public List<User> list() throws FileNotFoundException {InputStream in = ...;        // DAO职责List<String> lines = ...;    // 文件操作User user = parseUser(lines);// Service职责return user;                 // Controller职责
}

优化后

// Controller层 - 仅负责请求分发
@RestController
public class UserController {@Autowired private UserService userService;@RequestMapping("/list")public List<User> list() {return userService.findAllUser(); // 单一职责}
}
2. 高内聚低耦合
  • Service 依赖抽象而非实现:

    @Service
    public class UserServiceImpl implements UserService {@Autowired private UserDao userDao; // 依赖接口而非实现类
    }
    
  • DAO 层可无缝切换实现

    (如从文件到数据库):

    // 原文件实现
    public class FileUserDaoImpl implements UserDao {...}// 新增数据库实现
    public class JdbcUserDaoImpl implements UserDao {...}
    
3. 可扩展性增强
  • 开闭原则实践:

    // 新增缓存功能,无需修改原有代码
    @Service
    public class CachedUserServiceImpl implements UserService {@Autowired private UserDao userDao;@Autowired private CacheManager cacheManager;@Overridepublic List<User> findAllUser() {// 优先从缓存获取List<User> users = cacheManager.get("users");if (users == null) {users = userDao.findAll();cacheManager.put("users", users);}return users;}
    }
    
4. 可测试性提升
  • Controller 单元测试示例:

    @SpringBootTest
    public class UserControllerTest {@Autowired private MockMvc mockMvc;@MockBean private UserService userService;@Testpublic void testListUsers() throws Exception {// Mock Service返回值when(userService.findAllUser()).thenReturn(List.of(new User()));// 验证Controller响应mockMvc.perform(get("/list")).andExpect(status().isOk()).andExpect(jsonPath("$.size()").value(1));}
    }
    
5. 代码复用性
  • DAO 层复用示例:

    // UserService和AdminService均可复用UserDao
    @Service
    public class AdminService {@Autowired private UserDao userDao;public User lockUser(Long userId) {User user = userDao.findById(userId);// 业务逻辑...return userDao.update(user);}
    }
    
3.分层解耦后代码结构

1. Controller 层

@RestController
public class UserController {@Autowired private UserService userService;@RequestMapping("/list")public List<User> list() {return userService.findAllUser();}
}

2. Service 层

// 接口定义
public interface UserService {List<User> findAllUser();
}// 实现类
@Service
public class UserServiceImpl implements UserService {@Autowired private UserDao userDao;@Overridepublic List<User> findAllUser() {List<String> lines = userDao.findAll();return lines.stream().map(this::parseUser).collect(Collectors.toList());}private User parseUser(String line) {// 数据解析逻辑}
}

3. DAO 层

// 接口定义
public interface UserDao {List<String> findAll();
}// 文件实现
@Repository
public class FileUserDaoImpl implements UserDao {@Overridepublic List<String> findAll() {InputStream in = getClass().getResourceAsStream("/user.txt");return IoUtil.readLines(in, StandardCharsets.UTF_8);}
}
4. 分层解耦实践建议
1. 依赖注入最佳实践
  • 使用构造器注入替代字段注入:

    @Service
    public class UserServiceImpl implements UserService {private final UserDao userDao;@Autowired // 可省略,Spring 4.3+支持public UserServiceImpl(UserDao userDao) {this.userDao = userDao;}
    }
    
2. 事务管理
  • 在 Service 层声明式管理事务:

    @Service
    public class UserServiceImpl implements UserService {@Transactional(rollbackFor = Exception.class)public void transferPoints(Long fromId, Long toId, int points) {// 业务逻辑}
    }
    
3. 异常处理
  • 在 Controller 层统一处理异常:

    @RestControllerAdvice
    public class GlobalExceptionHandler {@ExceptionHandler(FileNotFoundException.class)public ResponseEntity<String> handleFileNotFound(Exception e) {return ResponseEntity.status(404).body("文件未找到");}
    }
    
5.分层解耦的挑战与应对
挑战解决方案
代码量增加使用 Lombok 减少样板代码,合理使用接口默认方法简化实现
性能开销层间调用开销可忽略,避免过度分层(如简单项目可合并 Service 和 DAO)
过度设计根据项目规模选择架构(如小型项目可采用两层架构),优先满足当前需求
调试复杂度使用 AOP 记录层间调用日志,结合 IDE 调用链分析工具
6. 分层架构演进路径
  1. 简单项目(初期)
    • Controller → Service(与 DAO 合并)
  2. 中等规模项目
    • Controller → Service → DAO
  3. 大型复杂项目
    • Controller → Facade → Service → Manager → DAO
    • 增加领域模型层(Domain Model)
    • 引入事件总线(Event Bus)解耦模块
http://www.xdnf.cn/news/16639.html

相关文章:

  • [Agent开发平台] API网关 | 业务领域 | DTO格式 | 分页令牌
  • 当人生低谷无人帮助时,如何独自奏响人生乐章
  • Abaqus2022下载与保姆级安装教程!!
  • 人工智能通信协议三种协议:MCP协议、A2A协议、AG-UI协议是什么
  • spark入门-helloword
  • CMS框架GetShell
  • 自动驾驶车辆的敏捷安全档案
  • 使用HaiSnap做了一款取件码App(一键生成)
  • 力扣热题100---------35.搜索插入为位置
  • 查询账户余额
  • 9.项目起步(3)
  • Scala实现常用排序算法
  • 第十二天:C++ 标准库函数分类总结
  • 【AI】开源项目整理
  • [Python] -进阶理解10- 用 Python 实现简易爬虫框架
  • 【同济大学】双速率自动驾驶架构LeAD:端到端+LLM,CARLA实测93%路线完成率,性能SOTA!
  • 基于 Hadoop 生态圈的数据仓库实践 —— OLAP 与数据可视化(四)
  • 机器学习之线性回归的入门学习
  • 语音识别dolphin 学习笔记
  • Linux 日志管理与时钟同步
  • 51单片机入门:数码管原理介绍及C代码实现
  • python快速复习篇(一)
  • Mysql事务基础
  • 7. 传输层协议 TCP
  • 国内数据集成厂商有哪些?如何选择最适合的数据集成平台?
  • Smart #5 Brabus使用45天(7500KM+)初步体验
  • 《Java 程序设计》第 12 章 - 异常处理
  • YOLO融合MogaNet中的ChannelAggregationFFN模块
  • Python 的 match-case
  • Windows管理用户脚本