🌸个人主页:https://blog.csdn.net/2301_80050796?spm=1000.2115.3001.5343
🏵️热门专栏:
🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm=1001.2014.3001.5482
🍕 Collection与数据结构 (92平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm=1001.2014.3001.5482
🧀Java EE(96平均质量分) https://blog.csdn.net/2301_80050796/category_12643370.html?spm=1001.2014.3001.5482
🍭MySql数据库(93平均质量分)https://blog.csdn.net/2301_80050796/category_12629890.html?spm=1001.2014.3001.5482
🍬算法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12676091.html?spm=1001.2014.3001.5482
🍃 Spring(97平均质量分)https://blog.csdn.net/2301_80050796/category_12724152.html?spm=1001.2014.3001.5482
感谢点赞与关注~~~

目录
- 1. 加法计算器
- 1.1 约定前后端交互的接口(接口文档)
- 1.2 前端代码
- 1.3 后端代码
- 2. 用户登录
- 3. 留言板
- 4. 图书管理系统
- 5. 应用分层
1. 加法计算器
需求:输入两个整数,点击"点击相加"按钮,显示计算结果.
1.1 约定前后端交互的接口(接口文档)
这是Web开发中的关键一环.接口又叫API,我们一般讲到的API或者接口,指的都是同一个东西.如今我们的开发一般采用前后端分离的方式,所以我们在开发之前,前端开发人员和后端开发人员会约定好前后端交互的方式.我们一般会把约定的内容写在文档上,就是"接口文档".接口文档可以理解为是应用程序中的"操作说明书".
在项目开发之前.我们需要先更具需求拟写接口文档,前后端必须都准寻接口文档中的标准.**接口文档通常由服务提供方来写,有服务使用方确认,也就是客户端.**关于接口文档怎么写,每个公司有不同的标准,一般是需求分析和接口定义(接口名称,URL),传递参数,返回参数下面我们来拟写这个案例的简单接口文档:
需求分析: 输入两个整数,点击"点击相加"按钮,显示计算结果.
接口定义:
请求路径:calc/sum,请求方式:GET/POST,接口描述:计算两个整数相加
请求参数:
参数名 | 类型 | 是否必须 | 备注 |
---|
num1 | Integer | 是 | 参与计算的第⼀个数 |
num2 | Integer | 是 | 参与计算的第⼆个数 |
响应数据: | | | |
Content-Type: text/html响应内容:计算机计算的结果
1.2 前端代码
首先,我们需要准备前端的代码.把前端的代码calc.html放在项目的Static目录中.

DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>Documenttitle>head><body><formaction="calc/sum"method="post"><h1>计算器h1>数字1:<inputname="num1"type="text"><br>数字2:<inputname="num2"type="text"><br><inputtype="submit"value="点击相加 ">form>body>html>
1.3 后端代码
packagecom.example.demo;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;@RequestMapping("/calc")@RestControllerpublicclassCalc{@RequestMapping("/sum")publicStringsum(Integernum1,Integernum2){Integersum =num1 +num2;return"加和结果
"+sum;}}
首先使用查询字符串来给参数传递值来测试后端代码的正确性.后端代码的逻辑没有问题.

之后我们连带前端代码一起运行起来.


如果前后端交互的时候出现了一些问题的时候,我们一般按照下面这样的步骤来解决:
- 首先清理前端(Ctrl+f5刷新页面)缓存,和后端(pom:clean)缓存.
- 首先看错误日志
- 确认后端接口是否有问题(可以通过浏览器或者Postman访问)
- 前端请求时,Fiddler抓包或者Debug,观察接参数或者URL是否有问题.
2. 用户登录
需求:用户输入账号和密码,后端进行校验密码是否正确.
- 如果正确,跳转到首页,首页显示当前登录用户的用户名
- 如果错误,前端进行用户告知.
- 后续在访问首页,可以获取到登录用户信息.
2.1 接口文档
需求分析:
用户输入账号和密码,后端进行校验密码是否正确.
- 如果正确,跳转到首页,首页显示当前登录用户的用户名
- 如果错误,前端进行用户告知.
- 后续在访问首页,可以获取到登录用户信息.
登录页面
接口定义:
请求路径: /user/login请求方式: POST接口描述: 校验账号和密码的正确性.
请求参数:
参数名 | 类型 | 是否必须 | 备注 |
---|
userName | String | 是 | 校验的账号 |
password | String | 是 | 校验的密码 |
响应数据:
Content-Type : text/html响应内容: 账号密码正确:true账号密码错误:false
主页
接口定义:
请求路径: /user/getLoginuser请求方式: GET接口描述: 显示当前登录用户的主页,主页上显示用户名.
请求参数:
无
响应数据:
Content-Type:text/html响应内容: 登录的用户名.
2.2 前端代码
对于前端而言,点击登录按钮的时候,需要把用户传递的信息传递到后端进行校验,后端校验成功之后,则跳转到首页:index.html,后端校验失败之后,直接弹窗.
2.2.1 登录页面
DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>登录页面title>head><body><h1>用户登录h1>用户名:<inputname="userName"type="text"id="userName"><br>密码:<inputname="password"type="password"id="password"><br><inputtype="button"value="登录"onclick="login()"><scriptsrc="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js">script><script>functionlogin(){$.ajax({type:"post",url:"/user/login",data:{"username":$("#userName").val(),"password":$("#password").val()},success:function(result){if(result){location.href ="/index.html"}else{alert("账号或密码有误");}}});}script>body>html>
- 这里我们使用ajax来进行信息传递,不用form表单的原因,是为了在输入错误的时候,不让页面发生跳转,如果使用form表单的话,页面一定会发生跳转.再者,因为ajax是异步调用的,在ajax的头部把信息先留下,之后再说对信息如何处理以及如何做.
何为异步?比如我们去街道处办事,我们需要先提交我们的资料,但是给我办事的那个人不在,同步操作就是一直等,等到那个人来,异步就是先把资料留下,先回家,等事情办好之后,给你打电话.
success: function (result)
其中的success表示的是接口返回结果的成功和失败,而不是业务结果返回true或者是false.
比如我们去银行办理业务,有三种可能:
- 银行没开门
- 忘记带身份证了,业务办理失败
- 证件携带齐全,业务办理成功
第一种就是接口返回了错误信息,第二种就是业务逻辑返回false,第三种就是业务逻辑返回true.
- window.location.href=index.html
- window.location.assign(“index.html”)
- window.location.replace(“index.html”)
我们一般把window省略.1,2是等价的,在进入新的页面之后,都可以回退回上一个页面,而3无法回退到上一个页面.
2.2.2 首页
doctypehtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"><metahttp-equiv="X-UA-Compatible"content="ie=edge"><title>用户登录首页title>head><body>登录人: <spanid="loginUser">span><scriptsrc="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js">script><script>$.ajax({type:"get",url:"/user/getLoginUser",success:function(result){$("#loginUser").text(result);}})script>body>html>
2.3 后端代码
2.3.1 登录页面
packagecom.example.demo;importjakarta.servlet.http.HttpSession;importorg.springframework.util.StringUtils;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;@RequestMapping("/user")@RestControllerpublicclassLogin{@RequestMapping("/login")publicBooleanlogin(StringuserName,Stringpassword,HttpSessionsession){if(!StringUtils.hasLength(userName)||!StringUtils.hasLength(password)){returnfalse;}if(!"zhangsan".equals(userName)||!"123456".equals(password)){returnfalse;}session.setAttribute("userName",userName);returntrue;}}
其中StringUtils.hasLength()
方法是Spring中提供的一个工具方法,判断字符串是否有值.字符串为null或者是""时,返回false,其他返回true.
publicstaticbooleanhasLength(@NullableStringstr){returnstr !=null&&!str.isEmpty();}
2.3.2 主页
packagecom.example.demo;importjakarta.servlet.http.HttpSession;importorg.springframework.util.StringUtils;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;@RequestMapping("/user")@RestControllerpublicclassGetUserLogin{@RequestMapping("/getUserLogin")publicStringgetUserLogin(HttpSessionhttpSession){StringuserName =(String)httpSession.getAttribute("userName");if(StringUtils.hasLength(userName)){returnuserName;}returnnull;}}
运行代码:

登录成功:

登录失败:

3. 留言板
3.1 接口文档
需求分析:
- 提交留言:用户输⼊留言信息之后,后端需要把留言信息保存起来
- 展示留言:页面展示时,需要从后端获取到所有的留言信息
接口定义:
- 获取全部留言
全部留言信息,我们用List来表示,可以用JSON来描述这个List数据.
请求:GET /message/getList
响应:JSON格式[ { "from": "黑猫", "to": "白猫", "message": "喵"},{ "from": "黑狗", "to": "白狗", "message": "汪" }, //...]
浏览器给服务器发送⼀个GET /message/getList
这样的请求,就能返回当前⼀共有哪些留言记录.结果以json的格式返回过来. - 发表新留言
请求:body也为JSON格式.POST /message/publish{ "from": "黑猫", "to": "白猫", "message": "喵"}响应:JSON格式.{ ok: 1}
我们期望浏览器给服务器发送⼀个POST /message/publish
这样的请求,就能把当前的留言提交给服务器.
3.2 前端代码
DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>留言板title><style>.container{width:350px;height:300px;margin:0 auto;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><divclass="container"><h1>留言板h1><pclass="grey">输入后点击提交, 会将信息显示下方空白处p><divclass="row"><span>谁:span><inputtype="text"name=""id="from">div><divclass="row"><span>对谁:span><inputtype="text"name=""id="to">div><divclass="row"><span>说什么:span><inputtype="text"name=""id="say">div><inputtype="button"value="提交"id="submit"onclick="submit()">div><scriptsrc="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js">script><script>load();functionload(){$.ajax({type:"get",url:"message/getList",success:function(result){for(varmessage ofresult){vardivE =""+message.from +"对"+message.to +"说:"+message.say+"
";$(".container").append(divE);}}});}functionsubmit(){varfrom =$('#from').val();varto =$('#to').val();varsay =$('#say').val();if(from==''||to ==''||say ==''){return;}$.ajax({type:"post",url:"message/publish",contentType:"application/json",data:JSON.stringify({from:from,to:to,say:say}),success:function(result){if(result){vardivE =""+from +"对"+to +"说:"+say+"
";$(".container").append(divE);$('#from').val("");$('#to').val("");$('#say').val("");}else{alert("提交留言失败")}}});}script>body>html>
3.3 后端代码
packagecom.example.demo;importorg.springframework.util.StringUtils;importorg.springframework.web.bind.annotation.RequestBody;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importjava.util.ArrayList;importjava.util.List;@RequestMapping("/message")@RestControllerpublicclassMessageWall{publicList<MessageInfo>messageInfoList =newArrayList<>();@RequestMapping("/publish")publicBooleanmessageController(@RequestBodyMessageInfomessageInfo){System.out.println(messageInfo);if(StringUtils.hasLength(messageInfo.from)&&StringUtils.hasLength(messageInfo.to)&&StringUtils.hasLength(messageInfo.say)){messageInfoList.add(messageInfo);returntrue;}returnfalse;}@RequestMapping("/getList")publicList<MessageInfo>getList(){returnmessageInfoList;}}
packagecom.example.demo;importlombok.Data;@DatapublicclassMessageInfo{publicStringfrom;publicStringto;publicStringsay;}
3.3.1 lombok介绍
Lombok是⼀个Java工具库,通过添加注解的方式,简化Java的开发.
- 引入依赖
<dependency><groupId>org.projectlombokgroupId><artifactId>lombokartifactId><optional>trueoptional>dependency>
- 使用
lombok通过使用一些注释的方式,可以帮我们消除一些冗长的代码,让代码看起来更简洁.
比如我们之前的Person对象就可以简化为:
packagecom.example.demo;importlombok.Data;@DatapublicclassPerson{publicStringname;publicintage;publicStringsex;}
其中,@Data
注解会帮助我们自动⼀些方法,包含getter/setter,equals,toString等.
3. 更多使用方法
@Data
生成的方法太多,lombok页为我们提供了一些颗粒度更细的注解.
注解 | 作用 |
---|
@Getter | 自动添加getter方法 |
@Setter | 自动添加setter方法 |
@ToString | 自动添加toString方法 |
@EqualsAndHashCode | 自动添加equals和hashCode方法 |
@NoArgsConstructor | 自动添加无参构造方法 |
@AllArgsConstructor | 自动添加全属性构造方法,顺序按照属性的定义顺序 |
@NonNull | 属性不能为null |
@RequiredArgsConstructor | 自动添加必需属性的构造方法,final+@NonNull的属性为必需 |
其中@Data
= @Getter+@Setter+@ToString+@NoArgsConstructor+@RequiredArgsConstructor
下面来测试运行:

4. 图书管理系统
4.1 接口文档
- 需求;
登录:用户输入账号和密码完成登录功能.
列表展示:展示图书 - 接口定义
登录接口[URL]POST /user/login[请求参数]name=admin&password=admin[响应]true //账号密码验证成功false//账号密码验证失败
- 图书列表展示
[URL]POST /book/getList[请求参数]⽆[响应]返回图书列表[ { "id": 1, "bookName": "活着", "author": "余华", "count": 270, "price": 20, "publish": "北京⽂艺出版社", "status": 1, "statusCN": "可借阅" }, ...
字段说明: id | 图书ID |
---|
bookName | 图书名称 |
author | 作者count 数量 |
price | 定价 |
publish | 图书出版社 |
status | 图书状态 1-可借阅,2-不可借阅 |
statusCN | 图书状态中文含义 |
4.2 前端代码
DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>Documenttitle><linkrel="stylesheet"href="css/bootstrap.min.css"><linkrel="stylesheet"href="css/login.css"><scripttype="text/javascript"src="js/jquery.min.js">script>head><body><divclass="container-login"><divclass="container-pic"><imgsrc="pic/computer.png"width="350px">div><divclass="login-dialog"><h3>登陆h3><divclass="row"><span>用户名span><inputtype="text"name="userName"id="userName"class="form-control">div><divclass="row"><span>密码span><inputtype="password"name="password"id="password"class="form-control">div><divclass="row"><buttontype="button"class="btn btn-info btn-lg"onclick="login()">登录button>div>div>div><scriptsrc="js/jquery.min.js">script><script>functionlogin(){$.ajax({type:"post",url:"/user/login",data:{name:$("#userName").val(),password:$("#password").val()},success:function(result){if(result){location.href ="book_list.html";}else{alert("账号或密码错误")}}});}script>body>html>
DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>图书列表展示title><linkrel="stylesheet"href="css/bootstrap.min.css"><linkrel="stylesheet"href="css/list.css"><scripttype="text/javascript"src="js/jquery.min.js">script><scripttype="text/javascript"src="js/bootstrap.min.js">script><scriptsrc="js/jq-paginator.js">script>head><body><divclass="bookContainer"><h2>图书列表展示h2><divclass="navbar-justify-between"><div><buttonclass="btn btn-outline-info"type="button"onclick="location.href='book_add.html'">添加图书button><buttonclass="btn btn-outline-info"type="button"onclick="batchDelete()">批量删除button>div>div><table><thead><tr><td>选择td><tdclass="width100">图书IDtd><td>书名td><td>作者td><td>数量td><td>定价td><td>出版社td><td>状态td><tdclass="width200">操作td>tr>thead><tbody>tbody>table><divclass="demo"><ulid="pageContainer"class="pagination justify-content-center">ul>div><script>getBookList();functiongetBookList(){$.ajax({type:"get",url:"/book/getList",success:function(result){console.log(result);if(result !=null){varfinalHtml ="";for(varbook ofresult){finalHtml +='';finalHtml +='+book.id +'" id="selectBook" class="book-select"> | ';finalHtml +=''+book.id +' | ';finalHtml +=''+book.bookName +' | ';finalHtml +=''+book.author +' | ';finalHtml +=''+book.count +' | ';finalHtml +=''+book.price +' | ';finalHtml +=''+book.publish +' | ';finalHtml +=''+book.statusCN +' | ';finalHtml +=' | ';finalHtml +="
";}$("tbody").html(finalHtml);}}});}$("#pageContainer").jqPaginator({totalCounts:100,pageSize:10,visiblePages:5,currentPage:1,first:'首页',prev:'上一页<\/a><\/li>',next:'下一页<\/a><\/li>',last:'最后一页<\/a><\/li>',page:'{{page}}<\/a><\/li>',onPageChange:function(page,type){console.log("第"+page+"页, 类型:"+type);}});functiondeleteBook(id){varisDelete =confirm("确认删除?");if(isDelete){alert("删除成功");}}functionbatchDelete(){varisDelete =confirm("确认批量删除?");if(isDelete){varids =[];$("input:checkbox[name='selectBook']:checked").each(function(){ids.push($(this).val());});console.log(ids);alert("批量删除成功");}}script>div>body>html>
4.3 后端代码
packagecom.jrj.library;importjakarta.servlet.http.HttpSession;importorg.springframework.util.StringUtils;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;@RequestMapping("/user")@RestControllerpublicclassLogin{@RequestMapping("/login")publicBooleanlogin(Stringname,Stringpassword,HttpSessionsession){if(!StringUtils.hasLength(name)||!StringUtils.hasLength(password)){returnfalse;}if("zhangsan".equals(name)&&"123456".equals(password)){session.setAttribute("userName",name);returntrue;}returnfalse;}}
- 图书列表
创建图书的属性packagecom.jrj.library;importlombok.Data;@DatapublicclassBookInfo{publicIntegerid;publicStringbookName;publicStringauthor;publicIntegercount;publicIntegerprice;publicStringpublish;publicIntegerstatus;publicStringstatusCN;}
返回图书列表:packagecom.jrj.library;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importjava.util.ArrayList;importjava.util.List;importjava.util.Random;@RequestMapping("/book")@RestControllerpublicclassBookController{@RequestMapping("/getList")publicList<BookInfo>getList(){List<BookInfo>list =mockData();for(BookInfobookInfo:list){if(bookInfo.status ==1){bookInfo.setStatusCN("可借阅");}else{bookInfo.setStatusCN("不可借阅");}}returnlist;}privateList<BookInfo>mockData(){List<BookInfo>list2 =newArrayList<>();for(inti =0;i <5;i++){BookInfobookInfo =newBookInfo();bookInfo.setId(i);bookInfo.setBookName("Java编程思想"+i);bookInfo.setCount(1);bookInfo.setPublish("机械工业出版社");bookInfo.setPrice(newRandom().nextInt(100));bookInfo.setAuthor("高斯林");bookInfo.setStatus(1);list2.add(bookInfo);}returnlist2;}}
测试运行:

登录页面正常

可正常登录,图书列表页面展示正确.
5. 应用分层
通过上面的几个案例,我们看到我们的代码平铺在我们的项目中,显得非常杂乱.所以我们要使用应用分层.

4.1 介绍
常见的应用分层结构如下:

我们之前提到的"MVC",就是把整体的系统分成了Model(模型),View(视图)和Controller(控制器)三个层次.现在我们主流开发的方式是"前后端分离"的方式,后端开发不再需要关心前端的实现,所以对java后端开发者,又有了一种新的分层架构:把整体架构分为表现层、业务逻辑层和数据层.这种分层方式也称之为"三层架构".
- 表现层:就是展示数据结果和接受用户指令(接收参数和返回结果)的,是最靠近用户的⼀层;
- 业务逻辑层:负责处理业务逻辑,里面有复杂业务的具体实现(拿到参数之后进行方法的具体实现);
- 数据层:负责存储和管理与应用程序相关的数据(比如数据库交互)
4.2 具体在项目中的体现
在我们创建Spring项目中,具体对分层的实现就是创建一个一个不同的目录,把代码分层管理起来.其中不同层面的目录一般用以下的命名方式:
• Controller:控制层。接收前端发送的请求,对请求进行处理,并响应数据。
• Service:业务逻辑层。处理具体的业务逻辑。
• Dao:数据访问层,也称为持久层。负责数据访问操作,包括数据的增、删、改、查.
• Model: 用于存储对实物属性的描述
下面我们对之前的图书管理的代码进行拆分重构:
packagecom.jrj.library.controller;importcom.jrj.library.service.LoginService;importjakarta.servlet.http.HttpSession;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;@RequestMapping("/user")@RestControllerpublicclassLoginController{@RequestMapping("/login")publicbooleanlogin(Stringname,Stringpassword,HttpSessionsession){LoginServiceloginService =newLoginService();returnloginService.login(name,password,session);}}
packagecom.jrj.library.controller;importcom.jrj.library.BookInfo;importcom.jrj.library.service.BookService;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importjava.util.ArrayList;importjava.util.List;@RequestMapping("/book")@RestControllerpublicclassBookController{BookServicebookService =newBookService();@RequestMapping("/getList")publicList<BookInfo>getList(){List<BookInfo>bookInfos =newArrayList<>();bookInfos =bookService.getList();returnbookInfos;}}
packagecom.jrj.library.service;importcom.jrj.library.BookInfo;importcom.jrj.library.dao.Data;importjava.util.List;publicclassBookService{publicList<BookInfo>getList(){Datadata =newData();List<BookInfo>list =data.mockData();for(BookInfobookInfo:list){if(bookInfo.status ==1){bookInfo.setStatusCN("可借阅");}else{bookInfo.setStatusCN("不可借阅");}}returnlist;}}
packagecom.jrj.library.service;importjakarta.servlet.http.HttpSession;importorg.springframework.util.StringUtils;publicclassLoginService{publicBooleanlogin(Stringname,Stringpassword,HttpSessionsession){if(!StringUtils.hasLength(name)||!StringUtils.hasLength(password)){returnfalse;}if("zhangsan".equals(name)&&"123456".equals(password)){session.setAttribute("userName",name);returntrue;}returnfalse;}}
importjava.util.Random;publicclassData{publicList<BookInfo>mockData(){List<BookInfo>list2 =newArrayList<>();for(inti =0;i <5;i++){BookInfobookInfo =newBookInfo();bookInfo.setId(i);bookInfo.setBookName("Java编程思想"+i);bookInfo.setCount(1);bookInfo.setPublish("机械工业出版社");bookInfo.setPrice(newRandom().nextInt(100));bookInfo.setAuthor("高斯林");bookInfo.setStatus(1);list2.add(bookInfo);}returnlist2;}}
packagecom.jrj.library.model;importlombok.Data;@DatapublicclassBookInfo{publicIntegerid;publicStringbookName;publicStringauthor;publicIntegercount;publicIntegerprice;publicStringpublish;publicIntegerstatus;publicStringstatusCN;}
上面的"三层架构",遵循了一种软件设计的原则,叫做"高内聚,低耦合".
高内聚指的是⼀个模块中各个元素之间的联系比较紧密.如果各个元素(语句、程序段)之间的联系程度越高,则内聚性越高,即"高内聚".
低耦合指的是软件中各个层、模块之间的依赖关联程序越低越好。修改⼀处代码,其他模块的代码改动越少越好.

前面提到的MVC架构模式和三层架构模式有什么区别?
MVC架构模式由三部分组成,分别是:模型(Model),视图(View)和控制器(Controller).
三层架构将业务应用划分为:表现层,业务逻辑层,数据访问层.
MVC模式强调数据和视图分离,将数据展示和数据处理分开,通过控制器对两者进行组合
三层架构强调不同维度数据处理的高内聚和低耦合,将交互界面,业务处理和数据库操作的逻辑分开.
