分層解耦(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.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…