【SpringBoot】从零开始全面解析SpringMVC (三)
本篇博客给大家带来的是SpringBoot的知识点, 本篇是SpringBoot入门, 介绍SpringMVC相关知识.
🐎文章专栏: JavaEE进阶
🚀若有问题 评论区见
❤ 欢迎大家点赞 评论 收藏 分享
如果你不知道分享给谁,那就分享给薯条.
你们的支持是我不断创作的动力 .
王子,公主请阅🚀
- 要开心
- 要快乐
- 顺便进步
- 1. 综合练习
- 1.1 留言板
- 1.1.1 准备工作
- 1.1.2 约定前后端交互接口
- 1.1.3 实现服务器代码:
- 1.2 图书管理系统
- 1.2.1 准备工作
- 1.2.2 约定前后端交互接口
- 1.2.3 服务器代码
- 调整前端页面代码
- 2. 应用分层
- 2.1 分层结构介绍
- 2.2 代码重构
- 2.3 应用分层的好处
- 3. 总结
- 3.1 注解
- 3.2 Cookie 和 Session
要开心
要快乐
顺便进步
1. 综合练习
1.1 留言板
需求:
界面如上图所示👆
1. 输入留言信息, 点击提交. 后端把数据存储起来.
2. 页面展示输入得表白墙的信息.
1.1.1 准备工作
码云链接: 薯条不要番茄酱
1.1.2 约定前后端交互接口
Ⅰ 发布留言
url : /message/publish .
param(参数) : from,to,say .
return : true / false .
Ⅱ 查询留言
url : /message/getList.
param : 无
return : form 对 to 说了 say
1.1.3 实现服务器代码:
Ⅰ 写代码之前,介绍一个新的工具包 lombok.
Lombok是一个Java工具库,通过添加注解的方式简化Java的开发.
① 引入依赖
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>
② 使用
lombok 通过一些注解的方式, 可以帮助我们消除一些冗长代码, 使代码看起来简洁一些. 就比如: 上面写的 Student 对象, 无需自己写 get , set , toString方法. 只需写一个注解 @Data就可以了.
import lombok.Data;@Data
public class Student {private String name;private Integer id;private int age;
}
③ 原理解释
加了 @Data 注解之后, Idea 反编译的class文件.
这不是真正的字节码文件, 而是Idea根据字节码进行反编译后的文件.
反编译是将可执行的程序代码转换为某种形式的高级编程语言, 使其具有更易读的格式. 反编译是一种逆向工程,它的作用与编译器的作用相反.
④ 更多使用
如果觉得 @Data生成的方法太多, lombok 也提供了一些更精细粒度的注解.
Ⅱ 更快捷引入依赖
① 安装插件EditStarter, 重启Idea.
② 在pom.xml 文件中, 单击右键, 选择Generate, 操作如下图所示
③ 进入 Edit Starters的编辑界面, 添加对应依赖即可.
Ⅲ 实现服务器代码
定义留言对象
import lombok.Data;@Data
public class MessageInfo {private String from;private String to;private String say;
}
创建 MessageController 类
import org.springframework.util.StringUtils;
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 MessageController {List<MessageInfo> messageInfos = new ArrayList<>();@RequestMapping("/publish")public Boolean publish(MessageInfo messageInfo) {//校验信息if(!StringUtils.hasLength(messageInfo.getFrom())|| !StringUtils.hasLength(messageInfo.getTo())|| !StringUtils.hasLength(messageInfo.getSay())) {return false;}//把信息存起来方便下一个方法获取messageInfos.add(messageInfo);return true;}@RequestMapping("/getList")public List<MessageInfo> getList() {return messageInfos;}
}
前端页面代码
<!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>A 对 B 说: hello</div> --></div><script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script><script>function submit() {$.ajax({url: "/message/publish",type: "get",data: {from: $("#from").val(),to: $("#to").val(),say: $("#say").val()},//http响应成功success:function(result) {if(result == false) {alert("输入不合法");}else {//展示信息//1. 构造节点var divE = "<div>"+from+ "对" + to + "说:" + say + "</div>";//2. 把节点添加到页面上$(".container").append(divE);//3. 清空输入框的值$("#from").val("");$("#to").val("");$("#say").val("");}}});}</script>
</body></html>
1.2 图书管理系统
需求:
1. 登录: 用户输入账号,密码完成登录功能.
2. 列表展示: 展示图书.
1.2.1 准备工作
创建新项目,引入依赖.
将前端代码复制到 static 目录下.
1.2.2 约定前后端交互接口
先实现其中的两个功能: 用户登录 和 图书列表展示.
需求分析:
1. 用户登录
url : /user/login
param : userName 和 password
return : String(提示)
2. 图书列表展示 1. url : /book/getBookList
2. param : 无
3. return : 图书列表
1.2.3 服务器代码
创建图书类
import lombok.Data;import java.math.BigDecimal;@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;
}
创建UserController, 实现登录验证接口.
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 UserController {@RequestMapping("/login")public String login(String userName, String password, HttpSession session) {//校验用户信息是否合法.if(!StringUtils.hasLength(userName) || !StringUtils.hasLength(password)) {return "用户名或密码为空";}//判断用户名和密码是否正确//理论上应该从数据库中获取, 但是目前还没学习 mybatis, 所以先这么写.if(!"admin".equals(userName) || !"admin".equals(password)) {return "用户名或密码错误";}session.setAttribute("userName",userName);return "";}
}
创建BookController, 获取图书列表
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;@RequestMapping("/book")
@RestController
public class BookController {@RequestMapping("/getBookList")public List<BookInfo> getBookList() {List<BookInfo> bookInfos = new ArrayList<>();//mock(模拟) 数据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;}
}
调整前端页面代码
登录页面:
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><link rel="stylesheet" href="css/bootstrap.min.css"><link rel="stylesheet" href="css/login.css"><script type="text/javascript" src="js/jquery.min.js"></script>
</head><body><div class="container-login"><div class="container-pic"><img src="pic/computer.png" width="350px"></div><div class="login-dialog"><h3>登陆</h3><div class="row"><span>用户名</span><input type="text" name="userName" id="userName" class="form-control"></div><div class="row"><span>密码</span><input type="password" name="password" id="password" class="form-control"></div><div class="row"><button type="button" class="btn btn-info btn-lg" onclick="login()">登录</button></div></div></div><script src="js/jquery.min.js"></script><script>function login() {$.ajax({url : "/user/login",type : "post",data : {userName : $("#userName").val(),password : $("#password").val(),},success:function(result) {if(result != "") {alert("用户名或密码错误,请重新输入");}else {location.href = "book_list.html";}}});}</script>
</body></html>
图书列表展示:
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>图书列表展示</title><link rel="stylesheet" href="css/bootstrap.min.css"><link rel="stylesheet" href="css/list.css"><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/bootstrap.min.js"></script><script src="js/jq-paginator.js"></script></head><body><div class="bookContainer"><h2>图书列表展示</h2><div class="navbar-justify-between"><div><button class="btn btn-outline-info" type="button" onclick="location.href='book_add.html'">添加图书</button><button class="btn btn-outline-info" type="button" onclick="batchDelete()">批量删除</button></div></div><table><thead><tr><td>选择</td><td class="width100">图书ID</td><td>书名</td><td>作者</td><td>数量</td><td>定价</td><td>出版社</td><td>状态</td><td class="width200">操作</td></tr></thead><tbody></tbody></table><div class="demo"><ul id="pageContainer" class="pagination justify-content-center"></ul></div><script>getBookList();function getBookList() {$.ajax({url:"/book/getBookList",type:"get",success:function(books) {var finnalHtml = "";for(var book of books) {finnalHtml += '<tr>';finnalHtml += '<td><input type="checkbox" name="selectBook" value="1" id="selectBook" class="book-select"></td>';finnalHtml += '<td>'+book.id+'</td>';finnalHtml += '<td>'+book.bookName+'</td>';finnalHtml += '<td>'+book.author+'</td>';finnalHtml += '<td>'+book.num+'</td>';finnalHtml += '<td>'+book.price+'</td>';finnalHtml += '<td>'+book.publishName+'</td>';finnalHtml += '<td>'+book.statusCN+'</td>';finnalHtml += '<td>';finnalHtml += '<div class="op">';finnalHtml += '<a href="book_update.html?bookId='+book.id+'">修改</a>';finnalHtml += '<a href="javascript:void(0)" onclick="deleteBook('+book.id+')">删除</a>';finnalHtml += '</div>';finnalHtml += '</td>';finnalHtml += '</tr>';}$("tbody").html(finnalHtml);}});}//翻页信息$("#pageContainer").jqPaginator({totalCounts: 100, //总记录数pageSize: 10, //每页的个数visiblePages: 5, //可视页数currentPage: 1, //当前页码first: '<li class="page-item"><a class="page-link">首页</a></li>',prev: '<li class="page-item"><a class="page-link" href="javascript:void(0);">上一页<\/a><\/li>',next: '<li class="page-item"><a class="page-link" href="javascript:void(0);">下一页<\/a><\/li>',last: '<li class="page-item"><a class="page-link" href="javascript:void(0);">最后一页<\/a><\/li>',page: '<li class="page-item"><a class="page-link" href="javascript:void(0);">{{page}}<\/a><\/li>',//页面初始化和页码点击时都会执行onPageChange: function (page, type) {console.log("第"+page+"页, 类型:"+type);}});function deleteBook(id) {var isDelete = confirm("确认删除?");if (isDelete) {//删除图书alert("删除成功");}}function batchDelete() {var isDelete = confirm("确认批量删除?");if (isDelete) {//获取复选框的idvar ids = [];$("input:checkbox[name='selectBook']:checked").each(function () {ids.push($(this).val());});console.log(ids);alert("批量删除成功");}}</script></div>
</body></html>
2. 应用分层
通过上面的练习, 我们学习了Spring MVC简单功能的开发, 但是我们也发现了一些问题。
目前我们程序的代码有点"杂乱", 然而当前只是"一点点功能"的开发. 如果我们把整个项目功能完成代码会更加的"杂乱无章"(文件乱, 代码内容也乱)。
基于此, 咱们接下来学习应用分层.
2.1 分层结构介绍
Ⅰ 什么是应用分层?
应用分层 是一种软件开发设计思想, 它将应用程序分成N个层次, 这N个层次分别负责各自的职责, 多个层次之间协同提供完整的功能. 根据项目的复杂度, 把项目分成三层, 四层或者更多层.
常见的MVC设计模式, 就是应用分层的一种具体体现.
Ⅱ 应用分层的目的
在最开始的时候,为了让项目快速上线,我们通常是不考虑分层的. 但是随着业务越来越复杂,大量的
代码混在一起,会出现逻辑不清晰、各模块相互依赖、代码扩展性差、改动一处就牵动全局的问题。 所以学习对项进行分层就是我们程序员的必修课了.
Ⅲ 如何分层
“MVC” 就是把整体的系统分成了 Model(模型), View(视图)和 Controller(控制器)三个层次,也就是将用户视图和业务处理隔开,并且通过控制器连接起来,很好地实现
了表现和逻辑的解耦,是一种标准的软件分层架构。
目前更主流的开发方式是 “前后端分离” 的方式, 后端开发工程师不再需要关注前端的实现, 对于Java后端开发者, 又有了一种新的分层架构: 把整体架构分为表现层、业务逻辑层和数据层. 这种分层方式也称之为"三层架构".
1. 表现层: 就是展示数据结果和接受用户指令的,是最靠近用户的一层;
2. 业务逻辑层: 负责处理业务逻辑, 里面有复杂业务的具体实现;
3. 数据层: 负责存储和管理与应用程序相关的数据。
按照上面的层次划分, Spring MVC 站在后端开发人员的角度上, 也进行了支持, 把上面的代码划分为三个部分:
请求处理、响应数据:负责,接收页面的请求,给页面响应数据.
逻辑处理: 负责业务逻辑处理的代码.
数据访问: 负责业务数据的维护操作,包括增、删、改、查等操作.
这三个部分, 在Spring的实现中, 均有体现:
Controller:控制层。接收前端发送的请求,对请求进行处理,并响应数据。
Service:业务逻辑层。处理具体的业务逻辑。
Dao:数据访问层,也称为持久层。负责数据访问操作,包括数据的增、删、改、查。
2.2 代码重构
使用上面的分层思想, 来对代码进行改造。
先创建对应的包路径, 并把代码移到对应的目录
com.fhao.book.controller
com.fhao.book.service
com.fhao.book.dao
com.fhao.book.model
在dao 目录下创建 BookDao文件 在service 目录下创建 BookService文件:
将 BookController 中的代码改写成👇:
@RequestMapping("/getBookList")public List<BookInfo> getBookList() {BookService bookService = new BookService();return bookService.getBookList();}
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;}
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;}
2.3 应用分层的好处
1. 降低层与层之间的依赖, 结构更加的明确, 利于各层逻辑的复用.
2. 开发人员可以只关注整个结构中的其中某一层, 极大地降低了维护成本和维护时间.
3. 可以很容易的用新的实现来替换原有层次的实现.
4. 有利于标准化.
3. 总结
3.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 返回数据
3.2 Cookie 和 Session
Cookie 和Session都是会话机制, Cookie是客户端机制, Session是服务端机制. 二者通过 SessionId来关联. Spring MVC内置 HttpServletRequest 和HttpServletResponse 两个对象. 需要使用时, 直接在方法中添加对应参数即可, Cookie 和 Session 可以从HttpServletRequest 中来获取, 也可以直接使用 HttpServletResponse 设置Http响应状态码.
本篇博客到这里就结束啦, 感谢观看 ❤❤❤
🐎期待与你的下一次相遇😊😊😊