分层解耦(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. 资源层:存放文件或数据库,提供原始数据。

原代码:

java 复制代码
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. 职责分离(单一职责原则)

原代码

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

优化后

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

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

    (如从文件到数据库):

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

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

    java 复制代码
    @SpringBootTest
    public class UserControllerTest {
        @Autowired private MockMvc mockMvc;
        @MockBean private UserService userService;
        
        @Test
        public 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 层复用示例:

    java 复制代码
    // 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 层

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

2. Service 层

java 复制代码
// 接口定义
public interface UserService {
    List<User> findAllUser();
}

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

3. DAO 层

java 复制代码
// 接口定义
public interface UserDao {
    List<String> findAll();
}

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

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

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

    java 复制代码
    @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)解耦模块
相关推荐
_oP_i3 小时前
RabbitMQ 队列配置设置 RabbitMQ 消息监听器的并发消费者数量java
java·rabbitmq·java-rabbitmq
Monkey-旭3 小时前
Android Bitmap 完全指南:从基础到高级优化
android·java·人工智能·计算机视觉·kotlin·位图·bitmap
我爱996!3 小时前
SpringMVC——响应
java·服务器·前端
小宋10213 小时前
多线程向设备发送数据
java·spring·多线程
天若有情6734 小时前
【python】Python爬虫入门教程:使用requests库
开发语言·爬虫·python·网络爬虫·request
大佐不会说日语~5 小时前
Redis高频问题全解析
java·数据库·redis
寒水馨5 小时前
Java 17 新特性解析与代码示例
java·开发语言·jdk17·新特性·java17
启山智软5 小时前
选用Java开发商城的优势
java·开发语言
秃然想通5 小时前
掌握Python三大语句:顺序、条件与循环
开发语言·python·numpy