应用分层

通过上面的练习,我们学习了 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 MVC Web 框架 基于 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 Framework Spring MVC Spring 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 是 “精装修套餐”,把地基和框架都准备好了,你只需要拎包入住,快速开发。

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐