[Spring] Spring Web MVC案例实战

LileSily 2024-07-18 15:03:01 阅读 50

🌸个人主页: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. 用户登录2.1 接口文档2.2 前端代码2.2.1 登录页面2.2.2 首页

2.3 后端代码2.3.1 登录页面2.3.2 主页

3. 留言板3.1 接口文档3.2 前端代码3.3 后端代码3.3.1 lombok介绍

4. 图书管理系统4.1 接口文档4.2 前端代码4.3 后端代码

5. 应用分层4.1 介绍4.2 具体在项目中的体现

1. 加法计算器

需求:输入两个整数,点击"点击相加"按钮,显示计算结果.

1.1 约定前后端交互的接口(接口文档)

这是Web开发中的关键一环.接口又叫API,我们一般讲到的API或者接口,指的都是同一个东西.如今我们的开发一般采用前后端分离的方式,所以我们在开发之前,前端开发人员和后端开发人员会约定好前后端交互的方式.我们一般会把约定的内容写在文档上,就是"接口文档".接口文档可以理解为是应用程序中的"操作说明书".

在项目开发之前.我们需要先更具需求拟写接口文档,前后端必须都准寻接口文档中的标准.**接口文档通常由服务提供方来写,有服务使用方确认,也就是客户端.**关于接口文档怎么写,每个公司有不同的标准,一般是需求分析和接口定义(接口名称,URL),传递参数,返回参数下面我们来拟写这个案例的简单接口文档:

需求分析: 输入两个整数,点击"点击相加"按钮,显示计算结果.

接口定义:

<code>请求路径:calc/sum,

请求方式:GET/POST,

接口描述:计算两个整数相加

请求参数:

参数名 类型 是否必须 备注
num1 Integer 参与计算的第⼀个数
num2 Integer 参与计算的第⼆个数
响应数据:

Content-Type: text/html

响应内容:计算机计算的结果

1.2 前端代码

首先,我们需要准备前端的代码.把前端的代码calc.html放在项目的Static目录中.

在这里插入图片描述

<code><!DOCTYPE html>

<html lang="en">code>

<head>

<meta charset="UTF-8">code>

<meta name="viewport" content="width=device-width, initial-scale=1.0">code>

<title>Document</title>

</head>

<body>

<form action="calc/sum" method="post">code>

<!--上面的action部分就表示的是与后端交互的接口,可以从这个接口中给前端返回数据-->

<h1>计算器</h1>

数字1:<input name="num1" type="text"><br>code>

数字2:<input name="num2" type="text"><br>code>

<input type="submit" value=" 点击相加 ">code>

</form>

</body>

</html>

1.3 后端代码

package com.example.demo;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/calc")

@RestController

public class Calc {

@RequestMapping("/sum")

public String sum(Integer num1,Integer num2){

Integer sum = num1 + num2;

return "<h1>加和结果</h1>" + sum;

}

}

首先使用查询字符串来给参数传递值来测试后端代码的正确性.后端代码的逻辑没有问题.

在这里插入图片描述

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

在这里插入图片描述

在这里插入图片描述

如果前后端交互的时候出现了一些问题的时候,我们一般按照下面这样的步骤来解决:

首先清理前端(Ctrl+f5刷新页面)缓存,和后端(pom:clean)缓存.首先看错误日志确认后端接口是否有问题(可以通过浏览器或者Postman访问)前端请求时,Fiddler抓包或者Debug,观察接参数或者URL是否有问题.

2. 用户登录

需求:用户输入账号和密码,后端进行校验密码是否正确.

如果正确,跳转到首页,首页显示当前登录用户的用户名如果错误,前端进行用户告知.后续在访问首页,可以获取到登录用户信息.

2.1 接口文档

需求分析:

用户输入账号和密码,后端进行校验密码是否正确.

如果正确,跳转到首页,首页显示当前登录用户的用户名如果错误,前端进行用户告知.后续在访问首页,可以获取到登录用户信息.

登录页面

接口定义:

<code>请求路径: /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 登录页面

<!DOCTYPE html>

<html lang="en">code>

<head>

<meta charset="UTF-8">code>

<title>登录页面</title>

</head>

<body>

<h1>用户登录</h1>

用户名:<input name="userName" type="text" id="userName"><br>code>

密码:<input name="password" type="password" id="password"><br>code>

<input type="button" value="登录" onclick="login()">code>

<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>code>

<script>

function login() {

//使用ajax进行前后端交互

$.ajax({

//小括号中是一个对象,对象用大括号括起来

type:"post",

url:"/user/login",

data:{

"username":$("#userName").val(),

"password":$("#password").val()//通过Id获取值,给后端传递参数

},

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.htmlwindow.location.assign(“index.html”)window.location.replace(“index.html”)

我们一般把window省略.1,2是等价的,在进入新的页面之后,都可以回退回上一个页面,而3无法回退到上一个页面.

2.2.2 首页

<!doctype html>

<html lang="en">code>

<head>

<meta charset="UTF-8">code>

<meta name="viewport"code>

content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">code>

<meta http-equiv="X-UA-Compatible" content="ie=edge">code>

<title>用户登录首页</title>

</head>

<body>

登录人: <span id="loginUser"></span>code>

<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>code>

<script>

$.ajax({

type : "get",

url : "/user/getLoginUser",

success:function (result) {

$("#loginUser").text(result);//给loginUser参数赋值为后端返回的result值

}

})

</script>

</body>

</html>

2.3 后端代码

2.3.1 登录页面

package com.example.demo;

import jakarta.servlet.http.HttpSession;

import org.springframework.util.StringUtils;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/user")

@RestController

public class Login {

@RequestMapping("/login")

public Boolean login(String userName, String password, HttpSession session){

//确保输入的密码和账号都不为空

//也为了保证前端传递信息成功,不会传递一个null过来

if (!StringUtils.hasLength(userName) ||

!StringUtils.hasLength(password)){

return false;

}

if (!"zhangsan".equals(userName) ||

! "123456".equals(password)){

return false;

}

//密码和账号都正确,设置session

session.setAttribute("userName",userName);

return true;

}

}

其中StringUtils.hasLength()方法是Spring中提供的一个工具方法,判断字符串是否有值.字符串为null或者是""时,返回false,其他返回true.

public static boolean hasLength(@Nullable String str) {

return str != null && !str.isEmpty();

}

2.3.2 主页

package com.example.demo;

import jakarta.servlet.http.HttpSession;

import org.springframework.util.StringUtils;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/user")

@RestController

public class GetUserLogin {

@RequestMapping("/getUserLogin")

public String getUserLogin(HttpSession httpSession){

//从session中获取用户名

String userName = (String) httpSession.getAttribute("userName");

if (StringUtils.hasLength(userName)){ //确保userName有值

return userName;

}

return null;

}

}

运行代码:

在这里插入图片描述

登录成功:

在这里插入图片描述

登录失败:

在这里插入图片描述

3. 留言板

3.1 接口文档

需求分析:

提交留言:用户输⼊留言信息之后,后端需要把留言信息保存起来展示留言:页面展示时,需要从后端获取到所有的留言信息

接口定义:

获取全部留言

全部留言信息,我们用List来表示,可以用JSON来描述这个List数据.

请求:

<code>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 前端代码

<!DOCTYPE html>

<html lang="en">code>

<head>

<meta charset="UTF-8">code>

<meta name="viewport" content="width=device-width, initial-scale=1.0">code>

<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">code>

<h1>留言板</h1>

<p class="grey">输入后点击提交, 会将信息显示下方空白处</p>code>

<div class="row">code>

<span>谁:</span> <input type="text" name="" id="from">code>

</div>

<div class="row">code>

<span>对谁:</span> <input type="text" name="" id="to">code>

</div>

<div class="row">code>

<span>说什么:</span> <input type="text" name="" id="say">code>

</div>

<input type="button" value="提交" id="submit" onclick="submit()">code>

<!-- <div>A 对 B 说: hello</div> -->

</div>

<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>code>

<script>

load();//每次在重新加载页面之后,都要从后端的List中调动数据,保证上次添加的数据不会丢失

function load(){

$.ajax({

type: "get",

url:"message/getList",

success:function (result){

for (var message of result){

var divE = "<div>"+message.from +"对" + message.to + "说:" + message.say+"</div>";

$(".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",

//传递的值是json类型,data就是在向后端传递数据

data:JSON.stringify({

from : from,

to : to,

say : say//从前端参数的ID中获取对应的值传递给后端

}),

//后端返回结果

success:function (result) {

if (result){

//2. 构造节点

var divE = "<div>"+from +"对" + to + "说:" + say+"</div>";

//3. 把节点添加到页面上

$(".container").append(divE);

//4. 清空输入框的值

$('#from').val("");

$('#to').val("");

$('#say').val("");

}else{

alert("提交留言失败")

}

}

});

}

</script>

</body>

</html>

3.3 后端代码

package com.example.demo;

import org.springframework.util.StringUtils;

import org.springframework.web.bind.annotation.RequestBody;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;

import java.util.List;

@RequestMapping("/message")

@RestController

public class MessageWall {

public List<MessageInfo> messageInfoList = new ArrayList<>();

@RequestMapping("/publish")

public Boolean messageController(@RequestBody MessageInfo messageInfo){

System.out.println(messageInfo);//打印日志

if (StringUtils.hasLength(messageInfo.from) &&

StringUtils.hasLength(messageInfo.to) &&

StringUtils.hasLength(messageInfo.say)){

messageInfoList.add(messageInfo);

return true;//都有长度,添加成功,返回true

}

//添加失败,返回false

return false;

}

@RequestMapping("/getList")

public List<MessageInfo> getList(){

return messageInfoList;

}

}

package com.example.demo;

import lombok.Data;

@Data

public class MessageInfo {

public String from;

public String to;

public String say;

}

3.3.1 lombok介绍

Lombok是⼀个Java工具库,通过添加注解的方式,简化Java的开发.

引入依赖

<dependency>

<groupId>org.projectlombok</groupId>

<artifactId>lombok</artifactId>

<optional>true</optional>

</dependency>

使用

lombok通过使用一些注释的方式,可以帮我们消除一些冗长的代码,让代码看起来更简洁.

比如我们之前的Person对象就可以简化为:

package com.example.demo;

import lombok.Data;

@Data

public class Person {

public String name;

public int age;

public String sex;

}

其中,@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 接口文档

需求;

登录:用户输入账号和密码完成登录功能.

列表展示:展示图书接口定义

登录接口

<code>[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 前端代码

登录页面

<!DOCTYPE html>

<html lang="en">code>

<head>

<meta charset="UTF-8">code>

<meta name="viewport" content="width=device-width, initial-scale=1.0">code>

<title>Document</title>

<link rel="stylesheet" href="css/bootstrap.min.css">code>

<link rel="stylesheet" href="css/login.css">code>

<script type="text/javascript" src="js/jquery.min.js"></script>code>

</head>

<body>

<div class="container-login">code>

<div class="container-pic">code>

<img src="pic/computer.png" width="350px">code>

</div>

<div class="login-dialog">code>

<h3>登陆</h3>

<div class="row">code>

<span>用户名</span>

<input type="text" name="userName" id="userName" class="form-control">code>

</div>

<div class="row">code>

<span>密码</span>

<input type="password" name="password" id="password" class="form-control">code>

</div>

<div class="row">code>

<button type="button" class="btn btn-info btn-lg" onclick="login()">登录</button>code>

</div>

</div>

</div>

<script src="js/jquery.min.js"></script>code>

<script>

function login() {

$.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>

图书列表

<!DOCTYPE html>

<html lang="en">code>

<head>

<meta charset="UTF-8">code>

<meta name="viewport" content="width=device-width, initial-scale=1.0">code>

<title>图书列表展示</title>

<link rel="stylesheet" href="css/bootstrap.min.css">code>

<link rel="stylesheet" href="css/list.css">code>

<script type="text/javascript" src="js/jquery.min.js"></script>code>

<script type="text/javascript" src="js/bootstrap.min.js"></script>code>

<script src="js/jq-paginator.js"></script>code>

</head>

<body>

<div class="bookContainer">code>

<h2>图书列表展示</h2>

<div class="navbar-justify-between">code>

<div>

<button class="btn btn-outline-info" type="button" onclick="location.href='book_add.html'">添加图书</button>code>

<button class="btn btn-outline-info" type="button" onclick="batchDelete()">批量删除</button>code>

</div>

</div>

<table>

<thead>

<tr>

<td>选择</td>

<td class="width100">图书ID</td>code>

<td>书名</td>

<td>作者</td>

<td>数量</td>

<td>定价</td>

<td>出版社</td>

<td>状态</td>

<td class="width200">操作</td>code>

</tr>

</thead>

<tbody>

</tbody>

</table>

<div class="demo">code>

<ul id="pageContainer" class="pagination justify-content-center"></ul>code>

</div>

<script>

getBookList();

function getBookList() {

$.ajax({

type: "get",

url: "/book/getList",

success: function (result) {

console.log(result);

if (result != null) {

var finalHtml = "";//构造字符串

for (var book of result) {

finalHtml += '<tr>';

finalHtml += '<td><input type="checkbox" name="selectBook" value="' + book.id + '" id="selectBook" class="book-select"></td>';code>

finalHtml += '<td>' + book.id + '</td>';

finalHtml += '<td>' + book.bookName + '</td>';

finalHtml += '<td>' + book.author + '</td>';

finalHtml += '<td>' + book.count + '</td>';

finalHtml += '<td>' + book.price + '</td>';

finalHtml += '<td>' + book.publish + '</td>';

finalHtml += '<td>' + book.statusCN + '</td>';

finalHtml += '<td><div class="op">';code>

finalHtml += '<a href="book_update.html?bookId=' + book.id + '">修改</a>';code>

finalHtml += '<a href="javascript:void(0)"οnclick="deleteBook(' + book.id + ')">删除</a>';code>

finalHtml += '</div></td>';

finalHtml += "</tr>";

}

$("tbody").html(finalHtml);

}

}

});

}

//翻页信息

$("#pageContainer").jqPaginator({

totalCounts: 100, //总记录数

pageSize: 10, //每页的个数

visiblePages: 5, //可视页数

currentPage: 1, //当前页码

first: '<li class="page-item"><a class="page-link">首页</a></li>',code>

prev: '<li class="page-item"><a class="page-link" href="javascript:void(0);">上一页<\/a><\/li>',code>

next: '<li class="page-item"><a class="page-link" href="javascript:void(0);">下一页<\/a><\/li>',code>

last: '<li class="page-item"><a class="page-link" href="javascript:void(0);">最后一页<\/a><\/li>',code>

page: '<li class="page-item"><a class="page-link" href="javascript:void(0);">{ {page}}<\/a><\/li>',code>

//页面初始化和页码点击时都会执行

onPageChange: function (page, type) {

console.log("第"+page+"页, 类型:"+type);

}

});

function deleteBook(id) {

var isDelete = confirm("确认删除?");

if (isDelete) {

//删除图书

alert("删除成功");

}

}

function batchDelete() {

var isDelete = confirm("确认批量删除?");

if (isDelete) {

//获取复选框的id

var ids = [];

$("input:checkbox[name='selectBook']:checked").each(function () { code>

ids.push($(this).val());

});

console.log(ids);

alert("批量删除成功");

}

}

</script>

</div>

</body>

</html>

4.3 后端代码

登录页面

package com.jrj.library;

import jakarta.servlet.http.HttpSession;

import org.springframework.util.StringUtils;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/user")

@RestController

public class Login {

@RequestMapping("/login")

public Boolean login(String name, String password, HttpSession session){

if (!StringUtils.hasLength(name) || !StringUtils.hasLength(password)){

return false;

}

if ("zhangsan".equals(name) && "123456".equals(password)){

session.setAttribute("userName",name);

return true;

}

return false;

}

}

图书列表

创建图书的属性

package com.jrj.library;

import lombok.Data;

@Data

public class BookInfo { //构造一本书所有的属性

public Integer id;

public String bookName;

public String author;

public Integer count;

public Integer price;

public String publish;

public Integer status;//1-可借阅,2-不可借阅

public String statusCN;

}

返回图书列表:

package com.jrj.library;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;

import java.util.List;

import java.util.Random;

@RequestMapping("/book")

@RestController

public class BookController {

@RequestMapping("/getList")

public List<BookInfo> getList(){

List<BookInfo> list = mockData();

for (BookInfo bookInfo:list){

if (bookInfo.status == 1){

bookInfo.setStatusCN("可借阅");

}else{

bookInfo.setStatusCN("不可借阅");

}

}

return list;

}

//模拟数据

private List<BookInfo> mockData(){

List<BookInfo> list2 = new ArrayList<>();

for (int i = 0; i < 5; i++) {

BookInfo bookInfo = new BookInfo();

bookInfo.setId(i);

bookInfo.setBookName("Java编程思想"+i);

bookInfo.setCount(1);

bookInfo.setPublish("机械工业出版社");

bookInfo.setPrice(new Random().nextInt(100));

bookInfo.setAuthor("高斯林");

bookInfo.setStatus(1);

list2.add(bookInfo);

}

return list2;

}

}

测试运行:

在这里插入图片描述

登录页面正常

在这里插入图片描述

可正常登录,图书列表页面展示正确.

5. 应用分层

通过上面的几个案例,我们看到我们的代码平铺在我们的项目中,显得非常杂乱.所以我们要使用应用分层.

在这里插入图片描述

4.1 介绍

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

在这里插入图片描述

我们之前提到的"MVC",就是把整体的系统分成了Model(模型),View(视图)和Controller(控制器)三个层次.现在我们主流开发的方式是"前后端分离"的方式,后端开发不再需要关心前端的实现,所以对java后端开发者,又有了一种新的分层架构:把整体架构分为表现层、业务逻辑层和数据层.这种分层方式也称之为"三层架构".

表现层:就是展示数据结果和接受用户指令(接收参数和返回结果)的,是最靠近用户的⼀层;业务逻辑层:负责处理业务逻辑,里面有复杂业务的具体实现(拿到参数之后进行方法的具体实现);数据层:负责存储和管理与应用程序相关的数据(比如数据库交互)

4.2 具体在项目中的体现

在我们创建Spring项目中,具体对分层的实现就是创建一个一个不同的目录,把代码分层管理起来.其中不同层面的目录一般用以下的命名方式:

• Controller:控制层。接收前端发送的请求,对请求进行处理,并响应数据。

• Service:业务逻辑层。处理具体的业务逻辑。

• Dao:数据访问层,也称为持久层。负责数据访问操作,包括数据的增、删、改、查.

• Model: 用于存储对实物属性的描述

下面我们对之前的图书管理的代码进行拆分重构:

表现层

<code>package com.jrj.library.controller;

import com.jrj.library.service.LoginService;

import jakarta.servlet.http.HttpSession;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/user")

@RestController

public class LoginController {

@RequestMapping("/login")

public boolean login(String name, String password, HttpSession session){

LoginService loginService = new LoginService();

return loginService.login(name,password,session);

}

}

package com.jrj.library.controller;

import com.jrj.library.BookInfo;

import com.jrj.library.service.BookService;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;

import java.util.List;

@RequestMapping("/book")

@RestController

public class BookController {

BookService bookService = new BookService();

@RequestMapping("/getList")

public List<BookInfo> getList(){

List<BookInfo> bookInfos = new ArrayList<>();

bookInfos = bookService.getList();

return bookInfos;

}

}

业务逻辑层

package com.jrj.library.service;

import com.jrj.library.BookInfo;

import com.jrj.library.dao.Data;

import java.util.List;

public class BookService {

public List<BookInfo> getList(){

Data data = new Data();

List<BookInfo> list = data.mockData();

for (BookInfo bookInfo:list){

if (bookInfo.status == 1){

bookInfo.setStatusCN("可借阅");

}else{

bookInfo.setStatusCN("不可借阅");

}

}

return list;

}

}

package com.jrj.library.service;

import jakarta.servlet.http.HttpSession;

import org.springframework.util.StringUtils;

public class LoginService {

public Boolean login(String name, String password, HttpSession session){

if (!StringUtils.hasLength(name) || !StringUtils.hasLength(password)){

return false;

}

if ("zhangsan".equals(name) && "123456".equals(password)){

session.setAttribute("userName",name);

return true;

}

return false;

}

}

数据访问层

import java.util.Random;

public class Data {

//向业务逻辑端提供数据

public List<BookInfo> mockData(){

List<BookInfo> list2 = new ArrayList<>();

for (int i = 0; i < 5; i++) {

BookInfo bookInfo = new BookInfo();

bookInfo.setId(i);

bookInfo.setBookName("Java编程思想"+i);

bookInfo.setCount(1);

bookInfo.setPublish("机械工业出版社");

bookInfo.setPrice(new Random().nextInt(100));

bookInfo.setAuthor("高斯林");

bookInfo.setStatus(1);

list2.add(bookInfo);

}

return list2;

}

}

实物描述

package com.jrj.library.model;

import lombok.Data;

@Data

public class BookInfo { //构造一本书所有的属性

public Integer id;

public String bookName;

public String author;

public Integer count;

public Integer price;

public String publish;

public Integer status;//1-可借阅,2-不可借阅

public String statusCN;

}

上面的"三层架构",遵循了一种软件设计的原则,叫做"高内聚,低耦合".

高内聚指的是⼀个模块中各个元素之间的联系比较紧密.如果各个元素(语句、程序段)之间的联系程度越高,则内聚性越高,即"高内聚".

低耦合指的是软件中各个层、模块之间的依赖关联程序越低越好。修改⼀处代码,其他模块的代码改动越少越好.

在这里插入图片描述

前面提到的MVC架构模式和三层架构模式有什么区别?

MVC架构模式由三部分组成,分别是:模型(Model),视图(View)和控制器(Controller).

三层架构将业务应用划分为:表现层,业务逻辑层,数据访问层.

MVC模式强调数据和视图分离,将数据展示和数据处理分开,通过控制器对两者进行组合

三层架构强调不同维度数据处理的高内聚和低耦合,将交互界面,业务处理和数据库操作的逻辑分开.

在这里插入图片描述



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。