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.pswp.cn/news/916911.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/916911.shtml
英文地址,请注明出处:http://en.pswp.cn/news/916911.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

镁金属接骨螺钉注册检测:骨科植入安全的科学基石

在骨科治疗领域&#xff0c;镁金属接骨螺钉凭借其可降解性与生物相容性&#xff0c;成为传统金属植入物的革新替代方案。然而&#xff0c;作为Ⅲ类高风险无源植入器械&#xff08;分类编码13-01-01&#xff09;&#xff0c;其注册检测需覆盖生物相容性、化学表征、降解性能、力…

模具开发和管理系统(c#)

以前编写的一个管理模具开发和进度的程序&#xff0c;可以跟踪模具开发进度&#xff0c;可以查询模具具体情况&#xff0c;也可以用水晶报表查询。OS&#xff1a;microsoft windows IDE&#xff1a;microsoft visual studio programming language&#xff1a;C# DataBase&#…

【WRF-Chem 实例1】namelist.input 详解- 模拟CO2

目录 &time_control(时间控制) &physics(物理过程参数化方案) &fdda(四维数据同化) 工作机制简述 &dynamics(WRF 动力核心的数值方法和选项) &bdy_control(边界控制设置) &chem(WRF-Chem 主要化学设置) &namelist_quilt(并行 I/O 控制…

数据中心-时序数据库InfluxDB

目录 一、InfluxDB介绍 1.1 什么是InfluxDB&#xff1f; 1.2 应用场景 1.3 特点 1.4 版本差异 二、数据模型和存储架构 2.1 相关概念 2.2 存储架构 三、InfluxDB基础操作 3.1 数据库操作 3.2 数据表操作 显示所有表 新建表 删除表 3.3 数据保存策略 查看保存策…

webpack-高级配置

多入口文件 如何输出多个html文件 输入位置 需要写两个entryoutput位置也要改一下 加一个name避免重名 在生成html时 要根据每一个入口都写一个插件 并且chunks要写好 当前html引入哪些文件如何抽离压缩css文件 安装插件在rules里面添加插件plugins中添加css抽离代码压缩css抽离…

WinForm组件之Label 控件

Label 控件Label 控件是 WinForm 中最基础、最常用的控件之一&#xff0c;主要用于在界面上显示文本信息&#xff0c;通常作为说明、提示或标题&#xff0c;不直接接受用户输入。它是构建用户界面的基础组件&#xff0c;在引导用户操作、展示状态信息等方面发挥重要作用。Label…

鸿蒙中相册权限弹窗

model.json5配置权限{"name": ohos.permission.READ_MEDIA,"reason":"$string:permission_reason_IMG","usedScene": {}}ui使用const url albumClass.onRequestCameraPermission()类import { abilityAccessCtrl, common, PermissionR…

智能车辆热管理测试方案——提升效能与保障安全

车辆热管理在能源危机出现、汽车排放法规日益严格以及人们对汽车舒适性要求更高的背景下应运而生。将各个系统或部件如冷却系统、润滑系统和空调系统等集成一个有效的热管理系统&#xff1b;控制和优化车辆的热量传递过程&#xff0c;保证各关键部件和系统良好运行&#xff1b;…

如何提升 TCP 传输数据的性能?详解

TCP 会保证每一个报文都能够抵达对方&#xff0c;它的机制是这样&#xff1a;报文发出去后&#xff0c;必须接收到对方返回的确认报文 ACK&#xff0c;如果迟迟未收到&#xff0c;就会超时重发该报文&#xff0c;直到收到对方的 ACK 为止 所以&#xff0c;TCP 报文发出去后&…

WiFi连接简单流程

WiFi连接流程与Debug方法一、WiFi连接全流程与详细日志解读 WiFi连接是一个多阶段、跨层次的复杂过程&#xff0c;涉及物理层、链路层、网络层和应用层的多种协议协作。整个流程包括AP初始化、终端扫描、认证、关联、四次握手、DHCP获取IP、网络可用与后续服务。1. AP初始化与参…

Python——Pandas库,超详细教程

前言1、Python的Pandas是一个基于Python构建的开源数据分析库&#xff0c;它提供了强大的数据结构和运算功能。2、Series&#xff1a;一维数组&#xff0c;类似于Numpy中的一维array&#xff0c;但具有索引标签&#xff0c;可以保存不同类型的数据&#xff0c;如字符串、布尔值…

go语言的gRPC教程-protobuf基础

一、前言 RPC&#xff0c;全称Remote Procedure Call&#xff0c;中文译为远程过程调用。通俗地讲&#xff0c;使用RPC进行通信&#xff0c;调用远程函数就像调用本地函数一样&#xff0c;RPC底层会做好数据的序列化与传输&#xff0c;从而能使我们更轻松地创建分布式应用和服…

Linux基本指令,对路径的认识

引言简单介绍一些Linux的基本指令&#xff0c;快速上手Linux操作系统。一、ls指令语法&#xff1a;ls [选项] [目录或文件]功能&#xff1a;&#xff1a;对于目录&#xff0c;该命令列出该目录下的所有子目录与文件。对于文件件&#xff0c;将列出文件名以及其他信息常用选项&a…

25. html 使用的字符集是什么,有什么特点

总结 utf-8&#xff0c;支持所有语言一、HTML 默认使用的字符集✅ HTML 页面推荐使用 UTF-8 字符集<meta charset"UTF-8" />这是 HTML5 中推荐的标准字符编码&#xff0c;用于定义网页中字符的编码方式。二、什么是字符集&#xff08;Character Encoding&#…

MySQL 读写分离(含示例代码)

背景 面对日益增加的系统访问量,数据库的吞吐量面临着巨大瓶颈。对于同一时刻有大量并发读操作和较少写操作类型的应用系统来说,将数据库拆分为主库和从库,主库负责处理事务性的增删改操作,从库负责处理查询操作,能够有效的避免由数据更新导致的行锁,使得整个系统的查询性…

C#中Visual Studio平台按照OfficeOpenXml步骤

找到包的地址&#xff1a; NuGet Gallery | DocumentFormat.OpenXml.Framework 3.3.0 https://nuget.info/packages 报错&#xff1a; 严重性 代码 说明 项目 文件 行 禁止显示状态 错误 无法解析依赖项“EPPlus”。使用的源: Officeopenxml, Mic…

【Linux】重生之从零开始学习运维之备份恢复

备份恢复准备工作16主机-ubuntu系统准备日志目录mkdir -p /data/mysql/logs/ chown mysql:mysql -R /data/mysql定制日志配置vim /etc/mysql/mariadb.conf.d/50-server.cnf log_bin/data/mysql/logs/binlog systemctl restart mariadb删除db1数据库drop database db1;13主机-ub…

VoIP技术全面深度学习指南:从原理到实践的认知进化

一、VoIP技术的本质认知与历史演进 1.1 技术本质的深层理解 VoIP&#xff08;Voice over Internet Protocol&#xff0c;IP语音传输&#xff09;从根本上代表了通信技术的范式转换。这不仅仅是将模拟语音信号数字化那么简单&#xff0c;而是将传统的电路交换模式彻底转向包交换…

CentOS Nginx 1.13.9 部署文档

以下是 Nginx 1.13.9 的详细安装步骤&#xff08;基于 CentOS/Ubuntu 系统&#xff09;&#xff1a;1. 安装依赖 CentOS/RHEL sudo yum install -y gcc pcre pcre-devel zlib zlib-devel openssl openssl-develUbuntu/Debian sudo apt update && sudo apt install -y b…

CSS-in-JS 动态主题切换与首屏渲染优化

动态主题切换的实现方式1. 使用 CSS 变量&#xff08;CSS Custom Properties&#xff09;CSS 变量是实现主题切换最直接的方式&#xff1a;:root {--primary-color: #4285f4;--background-color: #ffffff;--text-color: #333333; }[data-theme"dark"] {--primary-col…