应用分层和企业规范
目录
一、应用分层
1、介绍
(1)为什么需要应用分层?
(2)如何分层?(三层架构)
MVC 和 三层架构的区别和联系
高内聚:
低耦合:
2、代码重构
controller:表现层
service:业务逻辑层
dao:数据层
model:实体类
3、应用分层的好处
二、企业规范
三、学习Spring MVC的总结
之前写了几个简单的练习(图书管理系统、留言板...),这些只是一点简单的开发,但代码也显得比较乱,下图是几个类的分区,如图:

那如果要把完整的图书管理系统开发完了呢?那就会更加乱了。所以下面要学习应用分层,把代码管理好。
应用分层类似公司的组织架构:
公司初创阶段,人比较少,一个人会身兼数职,即做财务,又做人事等等。随着公司的逐渐壮大,会把岗位进行细分,会划为财务部门、人事部门、行政部门等等。
项目开发也是类似,最开始功能简单时,前后端放在一起开发,但随着项目功能的复杂,我们分为前端和后端不同的团队,甚至更细粒度的团队。后端开发也会根据功能再进行细分。MVC就是其中的一种拆分方式。
随着后端人员不再涉及前端,后端开发又有了新的分层方式。
一、应用分层
1、介绍
阿里开发手册中,关于工程结构部分,定义了常见工程的应用分层结果,如图:

应用分层 是一种软件开发设计思想,它将应用程序分成N个层次,这N个层次分别负责各自的职责,多个层次之间协同提供完整的功能。根据项目的复杂度,把项目分成三层,四层或者更多层。其中常见的MVC设计模式,就是应用分层的一种具体体现。
(1)为什么需要应用分层?
在最开始的时候,为了让项目快速上线,我们通常是不考虑分层的。但是随着业务越来越复杂,大量的代码混在一起,会出现逻辑不清楚、代码扩展性插、改一处导致处处改等问题。学习对项目的分层也是程序员的必修课。
(2)如何分层?(三层架构)
前面学习了MVC,把整体分成了三个层次:View(视图)、Controller(控制器)、Model(模型),也就是将用户视图和业务处理隔离开,并且通过控制器连接起来,很好的实现了表现和逻辑的解耦。是一种标准的软件分层架构。如图:

目前现在更主流的开发方式是 “前后端分离” 的方式,后端开发工程师不再需要关注前端的实现,所以对于Java后端开发者,又有了一种新的分层架构:把整体架构分为表现层、业务逻辑层、数据层。这种分层方式也称之为 “三层架构”。
1、表现层:就是展示数据结果和接受用户指令的,是最靠近用户的一层。
2、业务逻辑层:负责处理业务逻辑,里面有复杂业务的具体实现。
3、数据层:负责存储和管理应用程序相关的数据。
之前写的图书管理系统,就没有按照上述的设计思想,而是代码大杂烩,如图:

按照上面的层次划分,Spring MVC 站在后端开发人员的角度上,也进行了支持,把上述代码划分为三个部分:
1、请求处理、响应数据:负责接受页面的请求,给页面响应数据。
2、逻辑处理:负责业务逻辑处理的代码。
3、数据访问:负责业务数据的维护操作,包括增、删、改、查。
这三个部分,在Spring的实现中,都有体现,如图:

1、Controller:控制器。接收前端发送的请求,对请求进行处理,并且响应数据。
2、Service:业务逻辑层。处理具体的业务逻辑。
3、Dao:数据访问层,也称为持久层。负责数据访问操作,包括数据的增、删、改、查。
MVC 和 三层架构的区别和联系
从概念上来说,二者都是软件工程领域中的架构模式。
MVC架构模式由三部分组成:View(视图)、Controller(控制器)、Model(模型)
三层架构将业务应用划分为:表现层、业务逻辑层、数据访问层
MVC中的视图和控制器对应三层架构中的表现层。MVC中的模型对应三层架构中的业务逻辑层、数据层、实体类。

二者都是从不同角度对软件工程进行了抽象。
MVC模式强调数据和视图分离,将数据展示和数据处理分开。控制器是它们之间的桥梁,通过控制器对两者进行组合。
三层架构强调不同维度数据处理的高内聚和低耦合,将交互界面、业务处理、数据库操作的逻辑分开。
角度不同也就谈不上互相替代了,在日常的开发中,可以经常看到两种共存的情况。比如我们设计模式的时候往往也会拆分出业务逻辑层(Service层)和数据访问层(到层)。
但两者的目的都是相同的:都是为了“解耦,分层,代码复用”。、
软件设计原则:高内聚低耦合
高内聚:
一个模块中各个元素之间的联系的紧密程度,如果各个元素(语句、程序段)之间的联系程度越高,则内聚性越高,即 “高内聚”。
低耦合:
软件中各个层、模块之间的依赖关联程序越低越好。修改一处代码,其他模块的代码改动越少越好。
那么高内聚和低耦合矛盾吗?其实不矛盾,高内聚是指一个模块中的各个元素之间的紧密程度,低耦合是指各个模块之间的精密程度。如图:

好比在公司里,不同部门之间的关联性要尽可能小,一个小部分发生问题了,要尽可能降低对其他部门的影响,这就是低耦合;而当一个部门里出现问题时,这个部门之间的员工关系要经可能的紧密,遇到问题一起解决、克服,这就是高内聚。
2、代码重构
上篇博客写了图书管理系统,但是代码非常乱,现在进行代码重构,先创建对应包的路径,如图:

controller:表现层
@RestController
@RequestMapping("/book")
public class BookController {@RequestMapping("/getBookList")public List<BookInfo> getBookList() {BookService bookService = new BookService();return bookService.getBookList();}
}
@RestController
@RequestMapping("/user")
public class UserController {@RequestMapping("/login")public String login(String userName, String password, HttpSession session) {//1、校验参数//2、校验密码是否正确//3、返回响应结果System.out.println(userName + " " + password);if(!StringUtils.hasLength(userName) || !StringUtils.hasLength(password)) {return "用户名或者密码为空";}if(!"admin".equals(userName) || !"admin".equals(password)) {return "账号或密码错误";}session.setAttribute("userName", userName);return "";}
}
原本这里面的数据也是要从数据库里拿的,还有逻辑判断,但是还没学到数据库的使用,先不管。
service:业务逻辑层
public class BookService {public List<BookInfo> getBookList() {BookDao bookDao = new BookDao();List<BookInfo> bookInfos = bookDao.mockData();for(BookInfo bookInfo : bookInfos) {if(bookInfo.getStatus() == 2) {bookInfo.setStatusCN("不可借阅");} else {bookInfo.setStatusCN("可借阅");}}return bookInfos;}
}
dao:数据层
public class BookDao {public List<BookInfo> mockData() {//理论上应该从数据库中获取数据,当前采用mock方式List<BookInfo> bookInfos = new ArrayList<>();for (int i = 1; i <= 15; i++) {BookInfo bookInfo = new BookInfo();bookInfo.setId(i);bookInfo.setBookName("图书" + i);bookInfo.setAuthor("作者" + i);bookInfo.setNum(i * 2 + 1);bookInfo.setPrice(new BigDecimal(i * 3));bookInfo.setPublishName("出版社" + i);if(i % 5 == 0) {bookInfo.setStatus(2);
// bookInfo.setStatusCN("不可借阅");} else {bookInfo.setStatus(1);
// bookInfo.setStatusCN("可借阅");}bookInfos.add(bookInfo);}return bookInfos;}
}
model:实体类
@Data
public class BookInfo {private Integer id;private String bookName;private String author;private Integer num;private BigDecimal price;private String publishName;private Integer status;//1-可借阅 2-不可借阅private String statusCN;//状态的中文含义
}
3、应用分层的好处
(1)降低层与层之间的依赖,结构更加的明确,利于各层逻辑的复用。
(2)开发人员可以只关注整个结构中的其中某一层,极大地降低了维护成本和维护时间。
(3)可以很容易的用新的实现来替换原有层次的实现。
(4)有利于标准化。
二、企业规范
1、类名使用大驼峰风格,但以下情形例外:DO / BO / DTO / VO / AO。
2、方法名、参数名、成员变量、局部变量统一使用小驼峰风格。
3、包名统一使用小写,点分隔符之间有且仅有一个自然语义的英语单词。
常见命名风格:
大驼峰:所有单词首字母都需要大写,又叫帕斯卡命名发,比如:UserController。
小驼峰:除了第一个单词,其他单词首字母大写,比如:userController。
蛇形:用下划线(_)作用单词间的分隔符,一般小写,又叫下划线命名法,比如user_controller。
串形:用短横线(-)作用单词间的分隔符,又叫脊柱命名法,例如:user-controller。
三、学习Spring MVC的总结
1、学校Spring MVC,其实就是学习各种Web开发需要用到的注解:
a、@RequestMapping:路由映射
b、@RequestParam:后端参数重命名
c、@RequestBody:接收JSON类型的参数
d、@PathVariable:接收路径参数
e、@RequestPart:上传文件
f、@ResponseBody:返回数据
g、@CookieValue:从Cookie中获取值
h、@SessionAttribute:从Session中获取值
i、@RequestHeader:从Header中获取值
j、@Controller:定义一个控制器,Spring框架启动时加载,把这个对象交给Spring管理。默认返回视图。
k、@RestController:@ResponseBody + @Controller 返回数据
2、Cookie和Session都是会话机制,Cookie是客户端机制,Session是服务端机制。二者通过SessionId来关联。Spring MVC 内置 HttpServletRequest,HttpServletResponse两个对象。需要使用时,直接在方法中添加对应参数即可,Cookie和Session可以从HttpServletRequest中来获取,也可以直接使用HttpServletResponse设置Http响应状态码。
3、JavaEE 学习阶段会涉及较多工具,插件的学习,来帮助我们提高开发效率,比如Postman、lombok、EditStarter,后面还会继续学习其他的工具或插件。
都看到这了,点个赞再走吧,谢谢谢谢谢
相关文章:
应用分层和企业规范
目录 一、应用分层 1、介绍 (1)为什么需要应用分层? (2)如何分层?(三层架构) MVC 和 三层架构的区别和联系 高内聚: 低耦合: 2、代码重构 controlle…...
Flutter笔记:Widgets Easier组件库(1)使用各式边框
Flutter笔记 Widgets Easier组件库(1):使用边框 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite:http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress o…...
OpenHarmony实战开发-上传文件
Web组件支持前端页面选择文件上传功能,应用开发者可以使用onShowFileSelector()接口来处理前端页面文件上传的请求。 下面的示例中,当用户在前端页面点击文件上传按钮,应用侧在onShowFileSelector()接口中收到文件上传请求,在此接…...
外贸企业邮箱是什么?做外贸企业邮箱哪个好?
外贸企业邮箱是什么?外贸企业在进行跨国沟通时必不可少的工具就是外贸企业邮箱,外贸企业邮箱需要具备的条件就是海外邮件抵达率高、安全稳定、多语言沟通。而我们又怎么选择一个适合的外贸企业邮箱呢?小编今天带您一起了解。 一、外贸企业邮…...
写一个简单的程序
思路分析: 1. 导入必要的库 首先,确保你的项目中包含了AWT或Swing库,因为我们将使用它们来创建图形界面。 import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import j…...
CentOS安装Docker指南
Docker安装与配置教程 Docker作为一种轻量级的虚拟化技术,在现代软件开发和运维中扮演着重要的角色。下面,我将以技术博主的身份,向大家详细介绍如何在Linux系统上安装和配置Docker,特别是如何设置Docker的监听地址和端口&#x…...
python绘图(pandas)
matplotlib绘图 import pandas as pd abs_path rF:\Python\learn\python附件\pythonCsv\data.csv df pd.read_csv(abs_path, encodinggbk) # apply根据多列生成新的一个列的操作,用apply df[new_score] df.apply(lambda x : x.数学 x.语文, axis1)# 最后几行 …...
Android(Java)项目支持Kotlin语言开发
Android(Java)项目通过相关Kotlin设置后,允许同时使用Java语言和Kotlin语言进行开发代码的。 示例环境: Android Studio Giraffe | 2022.3.1 Patch 3 Java 8 Kotlin 1.9.20 设置Kotlin选项: 第一步:在项…...
Terraform创建模块
模块就是包含一组Terraform代码的文件夹,可以通过模块直接使用别人编写好的Terraform代码来创建资源。 Terraform模块是编写高质量Terraform代码,提升代码复用性的重要手段,可以说,一个成熟的生产环境应该是由数个可信成熟的模块组…...
《华为鸿蒙:从备胎到主角的崛起之路》
华为鸿蒙操作系统的发展历程可以追溯到 2012 年,当时华为开始规划自有操作系统鸿蒙 OS。然而,直到 2019 年 5 月,鸿蒙才正式进入开发阶段。 2019 年 8 月 9 日,华为正式发布了鸿蒙操作系统。 鸿蒙系统的首个版本是于 2019 年推出…...
FPGA学习笔记(2)——Verilog语法及ModelSim使用
1.1 语法 1、赋值语句 和 < 为阻塞赋值,当该语句结束时,下一个语句才开始执行,串行执行 < 为非阻塞幅值,该语句和整个语句块同时执行,并行执行 1.2 ModelSim使用 1、修改源文件路径:File -> …...
2024年十大AI工具,让你的工作学习效率飞跃
在这个迅速变化的数字时代,人工智能技术正在以前所未有的速度发展和革新。AI技术不仅深入科研、医疗和教育等领域,还广泛应用于日常生活和商业活动中。本文梳理了2024年十款最好用的AI工具,它们各有特色,能极大提升工作效率和生活…...
linux之NAMP
linux之NAMP Nmap(Network Mapper)是一个开源的网络扫描和安全审计工具。它被设计用来快速地扫描大型网络,尽管它也可以对单个主机进行有效的扫描。Nmap利用原始IP数据包以多种方式探测目标网络上的主机、服务(应用程序名称和版本…...
uniapp 禁止截屏(应用内,保护隐私)插件 Ba-ScreenShot
禁止截屏(应用内,保护隐私) Ba-ScreenShot 简介(下载地址) Ba-ScreenShot 是一款uniapp禁止应用内截屏的插件,保护隐私,支持禁止截屏、放开截屏 截图展示 也可关注博客,实时更新最…...
数字电路-5路呼叫显示电路和8路抢答器电路
本内容涉及两个电路,分别为5路呼叫显示电路和8路抢答器电路,包含Multisim仿真原文件,为掌握FPGA做个铺垫。紫色文字是超链接,点击自动跳转至相关博文。持续更新,原创不易! 目录: 一、5路呼叫显…...
C++中的函数签名
前言: 很多C初学者会发现函数签名这一概念在C的学习过程中经常出现,然而很多人往往不太了解函数签名包括些什么,本文章将从一个初学者的角度出发,详细解释函数签名这一概念。 在C中,函数签名用于唯一地识别函数重载。…...
Mac brew安装Redis之后更新配置文件的方法
安装命令 brew install redis 查看安装位置命令 brew list redis #查看redis安装的位置 % brew list redis /usr/local/Cellar/redis/6.2.5/.bottle/etc/ (2 files) /usr/local/Cellar/redis/6.2.5/bin/redis-benchmark /usr/local/Cellar/redis/6.2.5/bin/redis-check-ao…...
安卓应用开发(一):工具与环境
开发工具 Android Studio,用于开发 Android 应用的官方集成开发环境 (IDE)。包括以下功能: 基于Gradle的构建系统 gradle是一个项目构建工具,将源工程打包构建为apk 安卓模拟器统一环境代码编辑模拟器实时更新Github集成Lint功能࿰…...
基于springboot+vue+Mysql的在线动漫信息平台
开发语言:Java框架:springbootJDK版本:JDK1.8服务器:tomcat7数据库:mysql 5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包:…...
C++设计模式-结构型设计模式
写少量的代码来应对未来需求的变化。 单例模式 定义 保证一个类仅有一个实例,并提供一个该实例的全局访问点。——《设计模式》GoF 解决问题 稳定点: 类只有一个实例,提供全局的访问点(抽象) 变化点:…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...
【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...
华为OD机考-机房布局
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...
