应用分层
应用分层是一种软件开发设计思想, 它将应用程序分成N个层次, 这N个层次分别负责各自的功能, 多个层次之间协同提供完整的功能
常见的MVC设计模式, 就是应用分层的一种具体体现
为什么需要应用分层?
一开始,为了让项目快速上线,我们通常是不考虑分层的。但是随着业务越来越复杂,大量的代码混在一起,会出现逻辑不清晰、各模块相互依赖、代码扩展性差、牵一发而动全身等问题。
如何分层
MVC 就是把系统分成了 Model(模型), View(视图)和 Controller(控制器)三个层次,也就是将用户视图和业务处理隔离开,并且通过控制器连接起来,很好地实现了表现和逻辑的解耦,是一种标准的软件分层架构

目前主流的开发方式是 “前后端分离” 的方式, 后端开发工程师不再需要关注前端的实现, 所以对于Java后端开发者, 又有了一种新的分层架构: 把整体架构分为表现层、业务逻辑层和数据层。这种分层方式也称为”三层架构”
- 表现层: 是最靠近用户的一层,负责接收页面的请求,给页面响应数据
- 业务逻辑层: 负责处理业务逻辑
- 数据层: 负责存储和管理与应用程序相关的数据,负责业务数据的维护操作,包括增、删、改、查等操作
这三个部分, 在Spring的实现中, 均有体现:
- Controller:控制层。接收前端发送的请求,对请求进行处理,并响应数据。
- Service:业务逻辑层。处理具体的业务逻辑。
- Dao:数据访问层,也称为持久层。负责数据访问操作,包括数据的增、删、改、查
MVC 和 三层架构 的区别和联系
从概念上来讲, 二者都是软件工程领域中的架构模式.
- MVC架构模式由三部分组成, 分别是: 模型(Model), 视图(View)和控制器(Controller)
- 三层架构将业务应用划分为:表现层, 业务逻辑层, 数据访问层

MVC中, 视图和控制器合起来对应三层架构中的表现层,模型对应三层架构中的业务逻辑层, 数据层以及实体类
二者其实是从不同角度对软件工程进行了抽象
- MVC模式强调数据和视图分离, 将数据展示和数据处理分开, 通过控制器对两者进行组合
- 三层架构强调不同维度数据处理的高内聚和低耦合, 将交互界面, 业务处理和数据库操作的逻辑分开
角度不同也就谈不上互相替代了,在日常的开发中可以经常看到两种共存的情况,但是二者的目的是相同的, 都是”解耦,分层,代码复用”
软件设计原则:高内聚低耦合
- 高内聚:实现某个功能的时候,如果和这个功能相关的代码是集中放在一起的,就认为是”高内聚”; 如果是散落在项目的各个文件,各个角落中就认为是”低内聚”。高内聚就非常方便找到并修改代码
- 低耦合:软件中各个层、模块之间的依赖关联越小越好。修改一处代码, 其他模块的代码改动越少越好
内聚和耦合并没有必然的联系
- 内聚描述的是模块内部的事情(也有可能是模块之间)
- 耦合描述的是模块之间的事情
高内聚低耦合矛盾吗?
不矛盾, 高内聚指的是一个模块中各个元素之间的联系紧密程度, 低耦合指的是各个模块之间的紧密程度
这就好比一个企业, 包含很多部门, 各个部门之间的关联关系要尽可能的小, 一个部门发生问题, 要尽可能对降低对其他部门的影响, 这就是”低耦合”; 但是部门内部员工关系要尽量紧密,遇到问题一起解决克服,这叫做”高内聚”。又比如邻里邻居, 楼上漏水, 楼下遭殃, 就是”高耦合”;一个家庭内部的关系越紧密越好,一个家庭成员生病, 其他成员帮忙照顾, 就叫”高内聚”,一个家庭尽可能减少对另一个家庭的影响,就是”低耦合”
项目示例

- controller包下是控制层: 接收前端发送的请求,对请求进行处理,并响应数据
import com.example.messagewall.model.MessageInfo;
import com.example.messagewall.service.MessageInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RequestMapping("/message")
@RestController
public class MessageController {
@Autowired
private MessageInfoService messageInfoService;
@RequestMapping(value = "/publish", method = RequestMethod.POST)
public Boolean publish(@RequestBody MessageInfo messageInfo) {
//添加到数据库
messageInfoService.insert(messageInfo);
return true;
}
@RequestMapping("/getList")
public ListMessageInfo> getList() {
//从数据库查
return messageInfoService.query();
}
}
- service包下是业务逻辑层: 处理具体的业务逻辑
import com.example.messagewall.mapper.MessageInfoMapper;
import com.example.messagewall.model.MessageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class MessageInfoService {
@Autowired
private MessageInfoMapper messageInfoMapper;
public Integer insert(MessageInfo messageInfo) {
return messageInfoMapper.insert(messageInfo);
}
public ListMessageInfo> query() {
return messageInfoMapper.query();
}
}
- mapper包下是数据访问层: 负责数据访问操作,包括数据的增、删、改、查
import com.example.messagewall.model.MessageInfo;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface MessageInfoMapper {
//添加留言
@Insert("insert into message_info (`from`,`to`, `message`) values " +
"(#{from}, #{to}, #{message})")
Integer insert(MessageInfo messageInfo);
//查询留言
@Select("select * from message_info where delete_flag=0")
ListMessageInfo> query();
}
- model包下是实体类通常对应数据库中的表,包含该事物的属性(数据)和行为(方法),是数据存储和业务逻辑的基础载体
import lombok.Data;
@Data
public class MessageInfo {
private Integer id;
private String from;
private String to;
private String message;
private Integer deleteFlag;
private String createTime;
private String updateTime;
}
前端messagewall.html代码:
DOCTYPE html>
html lang="en">
head>
meta charset="UTF-8">
meta name="viewport" content="width=device-width, initial-scale=1.0">
title>留言板title>
style>
.container {
width: 350px;
height: 300px;
margin: 0 auto;
/* border: 1px black solid; */
text-align: center;
}
.grey {
color: grey;
}
.container .row {
width: 350px;
height: 40px;
display: flex;
justify-content: space-between;
align-items: center;
}
.container .row input {
width: 260px;
height: 30px;
}
#submit {
width: 350px;
height: 40px;
background-color: orange;
color: white;
border: none;
margin: 10px;
border-radius: 5px;
font-size: 20px;
}
style>
head>
body>
div class="container">
h1>留言板h1>
p class="grey">输入后点击提交, 会将信息显示下方空白处p>
div class="row">
span>谁:span> input type="text" name="" id="from">
div>
div class="row">
span>对谁:span> input type="text" name="" id="to">
div>
div class="row">
span>说什么:span> input type="text" name="" id="say">
div>
input type="button" value="提交" id="submit" onclick="submit()">
div>
script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js">script>
script>
$.ajax({
type: "get",
url: "/message/getList",
success: function(messages) {
if(messages!=null) {
for(let message of messages) {
var divE = ""+message.from +"对" + message.to + "说:" + message.message +"
";
$(".container").append(divE);
}
}
}
});
function submit(){
//1. 获取留言的内容
var from = $('#from').val();
var to = $('#to').val();
var say = $('#say').val();
if (from== '' || to == '' || say == '') {
return;
}
//调用后端接口,发表留言
$.ajax({
type: "post",
url: "/message/publish",
contentType: "application/json",
data: JSON.stringify({
"from": from,
"to": to,
"message": say
}),
success: function(result) {
if(result) {
//成功
//2. 构造节点
var divE = ""+from +"对" + to + "说:" + say+"
";
//3. 把节点添加到页面上
$(".container").append(divE);
//4. 清空输入框的值
$('#from').val("");
$('#to').val("");
$('#say').val("");
} else {
//失败
alert("发布失败");
}
}
});
}
script>
body>
html>
配置文件application.yml:
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
username: root
password: '123456'
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
configuration: # 配置打印 MyBatis日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true #配置驼峰自动转换
pom文件引入依赖部分:
dependencies>
dependency>
groupId>org.springframework.bootgroupId>
artifactId>spring-boot-starter-webartifactId>
dependency>
dependency>
groupId>org.springframework.bootgroupId>
artifactId>spring-boot-starter-testartifactId>
scope>testscope>
dependency>
dependency>
groupId>org.projectlombokgroupId>
artifactId>lombokartifactId>
optional>trueoptional>
dependency>
dependency>
groupId>org.mybatis.spring.bootgroupId>
artifactId>mybatis-spring-boot-starterartifactId>
version>3.0.3version>
dependency>
dependency>
groupId>com.mysqlgroupId>
artifactId>mysql-connector-jartifactId>
scope>runtimescope>
dependency>
dependencies>
按我配置的话,MySQL建库建表语句是这样的:
CREATE DATABASE IF NOT EXISTS mybatis_test;
USE mybatis_test;
CREATE TABLE message_info (
id INT AUTO_INCREMENT PRIMARY KEY COMMENT '消息ID',
`from` VARCHAR(255) COMMENT '发送者',
`to` VARCHAR(255) COMMENT '接收者',
message VARCHAR(255) COMMENT '消息内容',
delete_flag TINYINT DEFAULT 0 COMMENT '逻辑删除标志:0=有效,1=无效',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
);
全部搞定之后访问http://127.0.0.1:8080/messagewall.html就能交互啦!
应用分层的好处
- 降低层与层之间的依赖, 结构更加明确, 利于各层逻辑的复用
- 开发人员可以只关注整个结构中的其中某一层, 极大地降低了维护成本和维护时间
- 可以很容易的用新的实现来替换原有层次的实现
- 有利于标准化
企业规范
适用于多数企业, 均不做强制要求. 具体以所在企业为准
- 类名使用大驼峰风格,但以下情形例外:DO/BO/DTO/VO/AO
- 方法名、参数名、成员变量、局部变量统一使用小驼峰风格
- 包名统一使用小写,点分隔符之间有且仅有一个自然语义的英语单词
常见命名风格介绍
- 大驼峰: 所有单词首字母都需要大写, 又叫帕斯卡命名法, 比如: UserController
- 小驼峰:除了第一个单词,其他单词首字母大写,比如: userController
- 蛇形:用下划线 (_) 作为单词间的分隔符,一般小写,又叫下划线命名法,比如: user_controller
- 串形:用短横线 (-) 作为单词间的分隔符,又叫脊柱命名法,比如: user-controller
文章来源于互联网:掌握应用分层:高内聚低耦合的艺术
5bei.cn大模型教程网










