Spring Boot 后端分层开发实战:从 MVC 到三层架构详解

Spring Boot 后端分层开发实战:从 MVC 到三层架构详解

应用分层

通过上面的练习,我们学习了 Spring MVC 简单功能的开发,但是我们也发现了一些问题。目前我们程序的代码有点 “杂乱”,然而当前只是 “一点点功能” 的开发。如果我们把整个项目功能完成呢?代码会更加的 “杂乱无章”(文件乱,代码内容乱)。

也基于此,咱们接下来学习应用分层。类似公司的组织架构:公司初创阶段,一个人身兼数职,既做财务,又做人事,还有行政。随着公司的逐渐壮大,会把岗位进行细分,划分为财务部门,人事部门,行政部门等。各个部门内部还会再进行细分。

项目开发也是类似,最开始功能简单时,我们前后端放在一起开发,随着项目功能的复杂,我们分为前端和后端不同的团队,甚至更细粒度的团队。后端开发也会根据功能再进行细分。MVC 就是其中的一种拆分方式。但是随着后端人员不再涉及前端,后端开发又有了新的分层方式。

4.1 介绍

阿里开发手册中,关于工程结构部分,定义了常见工程的应用分层结构:

那么什么是应用分层呢?应用分层是一种软件开发设计思想,它将应用程序分成 N 个层次,这 N 个层次分别负责各自的职责,多个层次之间协同提供完整的功能。根据项目的复杂度,把项目分成三层,四层或者更多层。常见的 MVC 设计模式,就是应用分层的一种具体体现。

为什么需要应用分层?在最开始的时候,为了让项目快速上线,我们通常是不考虑分层的。但是随着业务越来越复杂,大量的代码混在一起,会出现逻辑不清晰、各模块相互依赖、代码扩展性差、改动一处就牵一发而动全身等问题。所以学习对项目进行分层就是我们程序员的必修课了。

如何分层(三层架构)

咱们上一节中学习的 “MVC”,就是把整体的系统分成了 Model(模型),View(视图)和 Controller(控制器)三个层次,也就是将用户视图和业务处理隔离开,并且通过控制器连接起来,很好地实现了表现和逻辑的解耦,是一种标准的软件分层架构。

目前现在更主流的开发方式是 “前后端分离” 的方式,后端开发工程师不再需要关注前端的实现,所以对于 Java 后端开发者,又有了一种新的分层架构:把整体架构分为表现层、业务逻辑层和数据层。这种分层方式也称之为 “三层架构”。

  1. 表现层:就是展示数据结果和接受用户指令的,是最靠近用户的一层;
  2. 业务逻辑层:负责处理业务逻辑,里面有复杂业务的具体实现;
  3. 数据层:负责存储和管理与应用程序相关的数据。

可以看到,咱们前面的代码,并不符合这种设计思想,而是所有的代码堆砌在一起。

这三个部分,在Spring的实现中,均有体现:

按照上面的层次划分,Spring MVC 站在后端开发人员的角度上,也进行了支持,把上面的代码划分为三个部分:

  • 请求处理、响应数据:负责,接收页面的请求,给页面响应数据。
  • 逻辑处理:负责业务逻辑处理的代码。
  • 数据访问:负责业务数据的维护操作,包括增、删、改、查等操作。

这三个部分,在 Spring 的实现中,均有体现:

  • Controller:控制层。接收前端发送的请求,对请求进行处理,并响应数据。
  • Service:业务逻辑层。处理具体的业务逻辑。
  • Dao:数据访问层,也称为持久层。负责数据访问操作,包括数据的增、删、改、查。

MVC 和三层架构的区别和联系

关于二者的关系,一直存在不同的观点。有人认为三层架构是 MVC 模式的一种实现,也有人认为 MVC 是三层架构的替代方案,等等各种说法都有。根本原因是大家站在不同的角度来看待这个问题的。

JavaEE 部分的学习重在 “实践”,大家根据自己的理解,能够自圆其说,说出自己的观点即可,也不建议大家去背书。

从概念上来讲,二者都是软件工程领域中的架构模式。

  • MVC 架构模式由三部分组成,分别是:模型 (Model),视图 (View) 和控制器 (Controller)。
  • 三层架构将业务应用划分为:表现层,业务逻辑层,数据访问层。

MVC 中,视图和控制器合起来对应三层架构中的表现层。模型对应三层架构中的业务逻辑层、数据层,以及实体类。

二者其实是从不同角度对软件工程进行了抽象。

  • MVC 模式强调数据和视图分离,将数据展示和数据处理分开,通过控制器对两者进行组合。
  • 三层架构强调不同维度数据处理的高内聚和低耦合,将交互界面、业务处理和数据库操作的逻辑分开。

角度不同也就谈不上互相替代了,在日常的开发中可以经常看到两种共存的情况,比如我们设计模型层的时候往往也会拆分出业务逻辑层(Service 层)和数据访问层(Dao 层)。

但是二者的目的是相同的,都是 “解耦,分层,代码复用”。

软件设计原则:高内聚低耦合

  • 高内聚:指的是一个模块中各个元素之间的联系的紧密程度,如果各个元素(语句、程序段)之间的联系程度越高,则内聚性越高,即 “高内聚”。
  • 低耦合:指的是软件中各个层、模块之间的依赖关联程序越低越好。修改一处代码,其他模块的代码改动越少越好。

高内聚低耦合矛盾吗?不矛盾,高内聚指的是一个模块中各个元素之间的联系的紧密程度,低耦合指的是各个模块之间的紧密程度。

这就好比一个企业,包含很多部门,各个部门之间的关联关系要尽可能的小,一个部门发生问题,要尽可能对降低对其他部门的影响,就是耦合。但是部门内部员工关系要尽量紧密,遇到问题一起解决,克服。这叫做内聚。

比如邻里邻居,楼上漏水,楼下遭殃,就是耦合。家庭一个成员生病,其他成员帮忙照顾,就叫内聚。一个家庭内部的关系越紧密越好,一个家庭尽可能少的影响另一个家庭,就是低耦合。

4.2 代码重构

我们使用上面的分层思想,来对代码进行改造

  1. 先创建对应的包路径,并把代码移到对应的目录
    • com.example.demo.controller
    • com.example.demo.service
    • com.example.demo.dao
    • com.example.demo.model

1. 代码拆分

控制层(Controller)

接收前端发送的请求,对请求进行处理,并响应数据。

package com.example.demo.controller; import com.example.demo.model.BookInfo; import com.example.demo.service.BookService; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RequestMapping("/book") @RestController public class BookController { @RequestMapping("/getList") public List<BookInfo> getList() { BookService bookService = new BookService(); // 获取数据 List<BookInfo> books = bookService.getBookList(); return books; } } 
业务逻辑层(Service)

处理具体的业务逻辑。

import com.example.demo.dao.BookDao; import com.example.demo.model.BookInfo; import java.util.List; public class BookService { public List<BookInfo> getBookList() { BookDao bookDao = new BookDao(); List<BookInfo> books = bookDao.mockData(); for (BookInfo book : books) { if (book.getStatus() == 1) { book.setStatusCN("可借阅"); } else { book.setStatusCN("不可借阅"); } } return books; } } 
数据访问层(Dao)

负责数据访问操作,包括数据的增、删、改、查。

import com.example.demo.model.BookInfo; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import java.util.Random; public class BookDao { /** * 数据Mock 获取图书信息 * @return */ public List<BookInfo> mockData() { List<BookInfo> books = new ArrayList<>(); for (int i = 0; i < 5; i++) { BookInfo book = new BookInfo(); book.setId(i); book.setBookName("书籍"+i); book.setAuthor("作者"+i); book.setCount(i*5+3); book.setPrice(new BigDecimal(new Random().nextInt(100))); book.setPublish("出版社"+i); book.setStatus(1); books.add(book); } return books; } } 

4.3 应用分层的好处

  • 降低层与层之间的依赖,结构更加明确,利于各层逻辑的复用
  • 开发人员可以只关注整个结构中的其中某一层,极大地降低了维护成本和维护时间
  • 可以很容易的用新的实现来替换原有层次的实现
  • 有利于标准化

4.4  企业规范

课件中出现的企业规范,适用于多数企业,均不做强制要求。具体以所在企业为准。
  1. 类名使用大驼峰风格,但以下情形例外:DO/BO/DTO/VO/AO
  2. 方法名、参数名、成员变量、局部变量统一使用小驼峰风格
  3. 包名统一使用小写,点分隔符之间有且仅有一个自然语义的英语单词。
常见命名风格介绍
  • 大驼峰:所有单词首字母都需要大写,又叫帕斯卡命名法,比如: UserController
  • 小驼峰:除了第一个单词,其他单词首字母大写,比如: userController
  • 蛇形:用下划线 (_) 作用单词间的分隔符,一般小写,又叫下划线命名法,比如: user_controller
  • 串形:用短横线 (-) 作用单词间的分隔符,又叫脊柱命名法,比如: user-controller

4.5 总结

  1. 学习 Spring MVC,其实就是学习各种 Web 开发需要用到的注解:
    • @RequestMapping:路由映射
    • @RequestParam:后端参数重命名
    • @RequestBody:接收 JSON 类型的参数
    • @PathVariable:接收路径参数
    • @RequestPart:上传文件
    • @ResponseBody:返回数据
    • @CookieValue:从 Cookie 中获取值
    • @SessionAttribute:从 Session 中获取值
    • @RequestHeader:从 Header 中获取值
    • @Controller:定义一个控制器,Spring 框架启动时加载,把这个对象交给 Spring 管理。默认返回视图。
    • @RestController@ResponseBody + @Controller,返回数据
  2. Cookie 和 Session 都是会话机制,Cookie 是客户端机制,Session 是服务端机制。二者通过 SessionId 来关联。Spring MVC 内置HttpServletRequestHttpServletResponse两个对象。需要使用时,直接在方法中添加对应参数即可,Cookie 和 Session 可以从HttpServletRequest中来获取,也可以直接使用HttpServletResponse设置 Http 响应状态码。
  3. Java EE 学习阶段会涉及较多工具、插件的学习,来帮助我们提高开发效率。比如 Postman、lombok、EditStarter,后面还会继续学习其他的工具或插件。

注意事项:

Spring , SpringBoot , SpringMVC 之间的关系以及区别?

名称定位核心作用
Spring Framework基础框架提供 IoC(控制反转)、DI(依赖注入)、AOP(面向切面编程)等核心能力,是整个 Spring 生态的基石。
Spring MVCWeb 框架基于 Spring 的 Web 层解决方案,专注于处理 HTTP 请求、路由、视图渲染等 Web 开发任务。
Spring Boot快速开发框架基于 Spring 和 Spring MVC,通过 “约定大于配置” 的思想,简化配置、内置服务器、自动装配,让开发者快速搭建可独立运行的应用。

二、它们之间的联系

  1. Spring 是基础Spring MVC 和 Spring Boot 都构建在 Spring Framework 之上,依赖它的核心功能(如 IoC 容器)。
  2. Spring MVC 是 Spring 的 Web 模块早期开发 Web 应用时,需要手动配置大量 XML,整合 Spring 和 Spring MVC,步骤繁琐。
  3. Spring Boot 是对 Spring 和 Spring MVC 的封装与简化
    • 它自动配置了 Spring MVC 的常用组件(如 DispatcherServlet、视图解析器)。
    • 内置了 Tomcat 等 Web 服务器,无需单独部署。
    • 通过 starter 依赖,一键引入 Spring MVC 等模块,大幅减少配置和依赖管理的工作量。

三、它们之间的区别

维度Spring FrameworkSpring MVCSpring Boot
核心目标提供企业级 Java 开发的通用解决方案专注于 Web 层开发简化 Spring 应用的开发和部署
配置方式大量 XML 或 JavaConfig 配置依赖 Spring 的配置,需额外配置 Web 相关组件自动配置(Auto-Configuration),极少手动配置
部署方式需要部署到外部 Web 服务器需要部署到外部 Web 服务器内置服务器,可直接运行 JAR 包
依赖管理手动管理依赖,易出现版本冲突手动管理依赖通过 starter 自动管理依赖和版本
使用场景所有需要 IoC、AOP 等能力的 Java 应用传统的 Spring Web 应用开发快速开发微服务、独立应用、RESTful API

四、一句话总结

  • Spring 是 “地基”,提供了最核心的编程模型和能力。
  • Spring MVC 是 “房子的框架”,专门用来盖 Web 应用这栋楼。
  • Spring Boot 是 “精装修套餐”,把地基和框架都准备好了,你只需要拎包入住,快速开发。

Read more

python之知识图谱(networkx)

NetworkX 库介绍与使用指南 NetworkX 是 Python 中用于创建、操作和分析复杂网络(图结构) 的核心库,支持无向图、有向图、加权图、多重图等多种图类型,内置丰富的图算法(路径分析、连通性、中心性、社区检测等),广泛应用于社交网络分析、网络拓扑研究、路径规划等场景。 一、安装 使用 pip 安装最新版本: pip install networkx # 基础安装 pip install networkx[all]# 包含所有依赖(如可视化、算法扩展) 验证安装:我使用的版本是 3.6.1 import networkx as nx print(nx.__version__)# 输出版本号,

By Ne0inhk
Python快速落地的临床知识问答与检索项目(2025年9月教学配置部分)

Python快速落地的临床知识问答与检索项目(2025年9月教学配置部分)

项目概述与技术选型 本项目定位为临床辅助决策支持工具,而非替代临床诊断的独立系统,旨在解决医疗行业两大核心痛点:一是医学知识更新速率加快,2025 年临床指南年均更新量较 2020 年增长 47%,传统知识管理方式难以同步;二是科室规范呈现碎片化分布,不同院区、亚专科的诊疗流程存在差异,导致知识检索效率低下。技术路线采用 RAG 知识库 + ChatFlow 多轮对话 + 工具节点对接 的三层架构,通过整合指南文献、临床路径和院内 SOP 文档,满足门诊快速问诊、病房随访问答及科室知识库精准检索需求,最终实现医疗信息可及性提升 30%、基层医生决策效率提高 25% 的核心价值目标[1]。 技术栈选型分析 1. 大语言模型:领域专精与多模态融合 临床知识问答核心模型需兼顾专业性与部署灵活性。2025 年主流选型包括: * Chimed - GPT:基于 Ziya - V2 架构,通过预训练、

By Ne0inhk
Python(28)Python循环语句指南:从语法糖到CPython字节码的底层探秘

Python(28)Python循环语句指南:从语法糖到CPython字节码的底层探秘

目录 * 引言 * 一、推导式家族全解析 * 1.1 基础语法对比 * 1.2 性能对比测试 * 二、CPython实现揭秘 * 2.1 字节码层面的秘密 * 2.2 临时变量机制 * 三、高级特性实现 * 3.1 嵌套推导式优化 * 3.2 条件表达式处理 * 四、性能优化指南 * 4.1 内存使用对比 * 4.2 执行时间优化技巧 * 五、最佳实践建议 * 六、总结 * 🌈Python爬虫相关文章(推荐) 引言 在Python编程中,循环语句是控制流程的核心工具。传统for循环虽然直观,但在处理大数据时往往面临性能瓶颈。本文将深入解析Python推导式(列表/字典/集合推导式)的底层实现机制,

By Ne0inhk
【Python基础:语法第三课】Python 函数详解:定义、参数、返回值与作用域

【Python基础:语法第三课】Python 函数详解:定义、参数、返回值与作用域

🎬 个人主页:艾莉丝努力练剑 ❄专栏传送门:《C语言》《数据结构与算法》《C/C++干货分享&学习过程记录》 《Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享》 ⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平 🎬 艾莉丝的简介: 文章目录 * 1 ~> 什么是函数? * 1.1 函数的概念 * 1.2 代码示例 * 1.2.1 代码示例:求数列的和,不使用函数 * 1.2.2 代码示例:求数列的和,使用函数 * 1.3 最佳实践:针对上面的示例 * 2 ~> 语法格式 * 2.

By Ne0inhk