[SpringBoot]Spring MVC(6.0)----图书管理系统(初)
图书管理系统
需求:
1. 登录: 用户输入账号,密码完成登录功能.
2. 列表展示: 展示图书.
准备工作
将前端代码复制到 static 目录下.
约定前后端交互接口
两个功能: 用户登录 和 图书列表展示.
需求分析:
1. 用户登录
url : /user/login
param : userName 和 password
return : String(提示)
2. 图书列表展示url : /book/getBookList
param : 无
return : 图书列表
后端代码
创建图书类
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;}
}
前端页面代码
登录页面:login.html
<!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>
图书列表展示:book_list.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>
效果展示
当账号密码错误时候
密码正确时候
应用分层
通过上面的练习, 我们学习了Spring MVC简单功能的开发, 但是我们也发现了一些问题。
目前我们程序的代码有点"杂乱", 然而当前只是"一点点功能"的开发. 如果我们把整个项目功能完成代码会更加的"杂乱无章"(文件乱, 代码内容也乱)。
分层结构介绍
什么是应用分层?
应用分层 是一种软件开发设计思想, 它将应用程序分成N个层次, 这N个层次分别负责各自的职责, 多个层次之间协同提供完整的功能. 根据项目的复杂度, 把项目分成三层, 四层或者更多层.
常见的MVC设计模式, 就是应用分层的一种具体体现.
应用分层的目的
在最开始的时候,为了让项目快速上线,我们通常是不考虑分层的. 但是随着业务越来越复杂,大量的
代码混在一起,会出现逻辑不清晰、各模块相互依赖(高耦合)、代码扩展性差、改动一处就牵动全局的问题。 所以学习对项进行分层就是我们程序员的必修课了.
如何分层
“MVC” 就是把整体的系统分成了 Model(模型), View(视图)和 Controller(控制器)三个层次,也就是将用户视图和业务处理隔开,并且通过控制器连接起来,很好地实现
了表现和逻辑的解耦,是一种标准的软件分层架构。
目前更主流的开发方式是 “前后端分离” 的方式, 后端开发工程师不再需要关注前端的实现, 对于Java后端开发者, 又有了一种新的分层架构: 把整体架构分为表现层、业务逻辑层和数据层. 这种分层方式也称之为"三层架构".
1. 表现层: 就是展示数据结果和接受用户指令的,是最靠近用户的一层;
2. 业务逻辑层: 负责处理业务逻辑, 里面有复杂业务的具体实现;
3. 数据层: 负责存储和管理与应用程序相关的数据。
按照上面的层次划分, Spring MVC 站在后端开发人员的角度上, 也进行了支持, 把上面的代码划分为三个部分:
请求处理、响应数据:负责,接收页面的请求,给页面响应数据.
逻辑处理: 负责业务逻辑处理的代码.
数据访问: 负责业务数据的维护操作,包括增、删、改、查等操作
这三个部分, 在Spring的实现中, 均有体现:
Controller:控制层。接收前端发送的请求,对请求进行处理,并响应数据。
Service:业务逻辑层。处理具体的业务逻辑。
Dao:数据访问层,也称为持久层。负责数据访问操作,包括数据的增、删、改、查。
代码重构
使用上面的分层思想, 来对代码进行改造。
先创建对应的包路径, 并把代码移到对应的目录
在dao 目录下创建 BookDao文件 在service 目录下创建 BookService文件:
将 BookController 中的代码改写成:
@RequestMapping("/getBookList")public List<BookInfo> getBookList() {BookService bookService = new BookService();return bookService.getBookList();}
应用分层的好处
1. 降低层与层之间的依赖, 结构更加的明确, 利于各层逻辑的复用.
2. 开发人员可以只关注整个结构中的其中某一层, 极大地降低了维护成本和维护时间.
3. 可以很容易的用新的实现来替换原有层次的实现.
4. 有利于标准化.
Spring MVC总结
学习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 返回数据
注释是Spring MVC的关键,但是我们还需要关注的是与前端进行交互的思想。这对我们开发网页有很大的作用