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

分层解耦(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.dtcms.com/a/306316.html

相关文章:

  • RHCA - CL260 | Day03:配置 RHCS 集群
  • 城市内涝淹水体积估算工作流程(QGIS)
  • 开疆智能Mpdbus转Profinet网关连接电磁流量计配置案例
  • 20250730在荣品的PRO-RK3566开发板的Android13下调通敦泰的FT8206触控芯片【I2C的挂载】
  • IBM Watsonx BI:AI赋能的下一代商业智能平台
  • 八股文场景题
  • 企业微信API接口发消息实战:从0到1的技术突破之旅
  • MySQL 读写分离
  • 论文阅读|NeurIPS 2024|Mamba进一步研究|MSVMamba
  • 飞算科技:原创技术重塑 Java 开发,引领行业数智化新浪潮
  • 网络的学习 2 Socket
  • 面记 | android 应用开发(某半导体公司)
  • LoRaWAN协议,提升公用事业能源效率的“隐形引擎”
  • 动态规划Day5学习心得
  • windows本地使用conda部署Open-webui
  • 【硬件-笔试面试题】硬件/电子工程师,笔试面试题-48,(知识点:BUCK电路的损耗,开关损耗,导通损耗,电感损耗、驱动损耗)
  • BeeWorks Meet:私有化部署,重塑高安全需求行业的视频会议体验
  • ubuntu自动搭建Android平台NDK编译环境
  • C++11 std::function 详解:通用多态函数包装器
  • nav2--安装/教程
  • 中大网校社会工作师培训持续发力,多维度提升服务效能
  • 论文阅读|ArxiV 2024|Mamba进一步研究|VSSD
  • 【AI 数据管理】Text2SQL:当AI成为你和数据库之间的金牌“翻译官”
  • 亚马逊Kiro重塑AI编程:从“氛围编码”到规范驱动的革命
  • 排序算法入门:直接插入排序详解
  • 应用宝(MediaRouteProviderService)媒体路由保活思路研究
  • 从 “内容篮子” 到 “生态平台”:融媒体 App 靠什么打破服务边界?
  • 在 Mac 上用 Vagrant 安装 K8s
  • JavaScript语法、关键字和变量
  • 提高建筑舒适度与能源效率,楼宇自控系统意义重大