目录
1.前言
"学习完SpringMVC的理论知识后,如何真正掌握它的核心用法?"本文将通过4个由浅入深的综合案例,其中包括简单计算器,登陆页面,留言板,简单图书管理系统。并在最后介绍下应用分层,那么话不多说让我们开始吧。
2.正文
在正式讲解之前,所有的源代码都在博主本人的gitee中,网址附上:
爱吃烤鸡翅的酸菜鱼 (crjs-hao) - Gitee.comhttps://gitee.com/crjs-hao
2.1计算器
2.1.1约定前后端接口
介绍API文档:
一份完整的API文档需要清晰描述接口功能、使用方法和约束条件,通常包含以下核心模块:
API名称:简明扼要的功能描述(如“用户登录接口”)。
版本号:标识当前API版本(目前咱们用不到)。
接口描述:功能用途、适用场景、特殊限制(如权限要求)。
URL地址:完整的请求路径(如
https://api.example.com/v1/user/login
)。请求方法:GET、POST、PUT、DELETE等。
简单介绍完后,我们开始写我们当前的API文档:
接口定义:
请求路径:calc/sum 请求方式:GET/POST 接口描述:计算两个数加和
请求参数:
参数名 类型 是否必须 备注 num1 Integer 是 参与计算的第一个数 num2 Interger 是 参与计算的第二个数 响应数据:
Content-Type: text/html response:计算结果为:..
2.1.2核心代码讲解
@RequestMapping("/calc")
@RestController
public class CalcController {
@RequestMapping("/sum")
public String sum(Integer num1,Integer num2){
if(num1 == null || num1 == null){
return "参数非法";
}
Integer sum = num1 + num2;
return "<h1>计算结果: " + sum + "</h1>";
}
}
核心逻辑:接收两个整数参数
num1
和num2
,返回它们的和。请求路径:
类级别路径:
/calc
方法级别路径:
/sum
完整访问路径:
http://localhost:8080/calc/sum?num1=10&num2=20
返回结果:
成功:HTML 格式的字符串(如
<h1>计算结果: 30</h1>
)。失败:参数为 null 时返回
"参数非法"
。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="calc/sum" method="post">
<h1>计算器</h1>
数字1:<input name="num1" type="text"><br>
数字2:<input name="num2" type="text"><br>
<input type="submit" value=" 点击相加 ">
</form>
</body>
</html>
功能:实现一个简单的网页计算器,用于输入两个数字并相加。
表单:
包含两个输入框,分别用于输入数字1和数字2。
提交按钮触发表单提交。
提交方式:
使用
POST
方法将数据发送到服务器的calc/sum
路径。处理逻辑:
服务器接收
num1
和num2
参数,进行相加操作。返回计算结果。
运行结果:
2.2登陆页面
2.2.1约定前后端接口
接口定义:
请求路径:/user/login 请求方式:POST 接口描述:校验账号密码是否正确
请求参数:
参数名 类型 是否必须 备注 userName String 是 校验的账号 password String 是 校验的密码 响应数据:
Content-Type: text/html 响应内容:
2.2.2后端核心代码讲解
@RequestMapping("/user")
@RestController
public class UserController {
@RequestMapping("/login")
public boolean login(String name, String password, HttpSession session){
if(!StringUtils.hasLength(name) || !StringUtils.hasLength(password)){
return false;
}
if("admin".equals(name) && "admin".equals(password)){
session.setAttribute("name",name);
return true;
}
return false;
}
@RequestMapping("/getLoginUser")
public String getLoginUser(HttpSession session){
String name = (String) session.getAttribute("name");
return name;
}
}
类定义:
类名为
UserController
。使用
@RestController
注解,表示这是一个RESTful控制器。使用
@RequestMapping("/user")
注解,将类中的方法映射到/user
路径下。方法定义:
login
方法:
映射到
/user/login
路径。接受用户名(
name
)和密码(password
)作为参数。检查用户名和密码是否为空。
如果用户名和密码都为
admin
,则将用户名存入会话(session
)并返回true
。否则返回
false
。
getLoginUser
方法:
映射到
/user/getLoginUser
路径。从会话中获取存储的用户名并返回。
功能:
提供用户登录功能,验证用户名和密码。
获取当前登录用户的用户名。
2.2.3介绍Ajax
在正式讲解前端代码前,需要先介绍下js中的Ajax:
1. 什么是Ajax?
定义:Ajax是异步JavaScript和XML,其是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。通过在后台与服务器进行数据交换,实现页面的异步更新。
2. Ajax的工作原理
- 用户在网页上触发某个事件(如点击按钮、输入文本等)。
- JavaScript通过
XMLHttpRequest
对象向服务器发送异步请求。- 服务器接收到请求后,处理数据并返回响应。
- JavaScript接收服务器响应,并根据返回的数据更新网页内容。
5. Ajax的基本流程
创建
XMLHttpRequest
对象:
- 用于与服务器进行通信。
配置请求:
- 指定请求方法(如
GET
、POST
)和URL。设置请求头(可选):
- 定义请求的内容类型等信息。
发送请求:
- 使用
send()
方法发送请求,可以附带请求数据(如表单数据)。处理响应:
- 通过监听
onreadystatechange
事件或使用fetch
的.then()
方法,处理服务器返回的数据。
下文会有详细的Ajax代码的展示。
2.2.4前端核心代码讲解
index.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>用户登录首页</title>
</head>
<body>
登录人: <span id="loginUser"></span>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script>
$.ajax({
url: "/user/getLoginUser",
type: "get",
success: function(name){
$("#loginUser").text(name);
}
});
</script>
</body>
</html>
功能:实现一个简单的用户登录状态显示功能,用于在网页上显示当前登录的用户名。
表单:
页面上有一个
<span>
元素,用于显示用户名。无需用户输入,直接通过AJAX从服务器获取用户名。
提交方式:
使用GET方法将请求发送到服务器的
/user/getLoginUser
路径。处理逻辑:
服务器接收请求,查询当前登录的用户名。
返回查询到的用户名。
login.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
<h1>用户登录</h1>
用户名:<input name="name" type="text" id="name"><br>
密码:<input name="password" type="password" id="password"><br>
<input type="button" value="登录" onclick="login()">
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script>
function login(){
$.ajax({
type: "post",
url: "/user/login",
data: {
name: $("#name").val(),
password: $("#password").val()
},
success: function(result){
if(result){
//true
location.href = "index.html";
}else{
//false
alert("密码错误,请确认")
}
}
})
}
</script>
</body>
</html>
功能:实现一个简单的用户登录页面,用户输入用户名和密码后点击登录按钮进行验证。
表单:
包含两个输入框,分别用于输入用户名和密码。
包含一个按钮,点击后触发登录操作。
提交方式:使用POST方法将数据发送到服务器的
/user/login
路径。处理逻辑:
服务器接收
name
和password
参数,进行登录验证。返回验证结果。
运行结果:
2.3留言板
2.3.1约定前后端接口
接口1:获取全部留言:
请求:
GET/message/getList
响应:JSON格式
[ { "from": "tom", "to": "kerry", "message": "hello" } ]
接口2:发表新留言:
请求:
POST/message/publish { "from": "tom", "to": "kerry", "message": "hello" }
响应:JSON
{ ok: 1 }
2.3.2介绍Lombok
我们在写代码的时候发现,如果每一次创建对象时都要写构造方法以及成员变量的相关方法,将会让代码显得十分臃肿,于是乎我们就引入了个工具——Lombok。
Lombok 是一种 Java 库,通过注解的形式简化 Java 代码,减少样板代码(boilerplate code)的编写。它可以自动为类生成 getter 和 setter 方法、构造函数、equals 和 hashCode 方法等。以下是 Lombok 的详细介绍及其常见注解的用法:
1. Lombok 的核心优势
减少样板代码:自动生成 getter/setter、构造函数、toString 等方法,避免手动编写重复代码。
提高开发效率:专注于业务逻辑,减少机械性的代码输入。
增强代码可读性:代码更简洁,逻辑更清晰。
与 IDE 集成良好:支持主流 IDE(如 IntelliJ IDEA、Eclipse 等),提供实时代码补全和错误检查。
2. Lombok 的安装与配置
需要在maven中配置好相关信息:
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.30</version> <scope>provided</scope> </dependency>
记得刷新maven,重启项目。
3. 常见注解及其用法
@Getter
和@Setter
自动生成类属性的 getter 和 setter 方法。
可以对单个属性或整个类应用。
import lombok.Getter; import lombok.Setter; @Setter @Getter public class User { private String name; private int age; }
@ToString
自动生成
toString()
方法,默认包含所有字段。可通过
exclude
属性排除特定字段。import lombok.ToString; @ToString(exclude = "id") public class User { private Long id; private String name; private int age; }
@EqualsAndHashCode
自动生成
equals()
和hashCode()
方法,默认比较所有字段。支持
exclude
属性排除特定字段。import lombok.EqualsAndHashCode; @EqualsAndHashCode(exclude = "age") public class User { private String name; private int age; }
@Data
综合注解,等同于
@Getter + @Setter + @ToString + @EqualsAndHashCode + @AllArgsConstructor
。适用于简单的 POJO(Plain Old Java Object)类。
import lombok.Data; @Data public class User { private String name; private int age; }
操作示例:
package com.example.demo; import lombok.Data; @Data public class MessageInfo { private String From; private String To; private String Message; }
我去target文件中去寻找编译后的文件:
![]()
2.3.3后端核心代码讲解
@RequestMapping("/message")
@RestController
public class messageController {
private final List<MessageInfo> messageInfoList = new ArrayList<>();
@PostMapping(value = "/publish",produces = "application/json")
public String publish(@RequestBody MessageInfo messageInfo){
if((!StringUtils.hasLength(messageInfo.getFrom()) )||
!StringUtils.hasLength(messageInfo.getTo()) ||
!StringUtils.hasLength(messageInfo.getMessage())){
return "{\"ok\": 0}";
}
messageInfoList.add(messageInfo);
return "{\"ok\": 1}";
}
@GetMapping("/getList")
public List<MessageInfo> getList(){
return messageInfoList;
}
}
类定义:定义了一个名为
messageController
的类,使用@RestController
注解,标识这是一个控制器类。成员变量:声明了一个
messageInfoList
列表,用于存储MessageInfo
对象。publish 方法:
使用
@PostMapping
注解映射 HTTP POST 请求到/publish
路径。接收一个 JSON 格式的
MessageInfo
对象,并检查其from
、to
和message
属性是否非空。如果检查通过,将
MessageInfo
对象添加到messageInfoList
列表中,并返回{"ok": 1}
表示成功。如果检查不通过,返回
{"ok": 0}
表示失败。getList 方法:
使用
@GetMapping
注解映射 HTTP GET 请求到/getList
路径。返回
messageInfoList
列表中的所有MessageInfo
对象。
2.3.4前端核心代码讲解
<script>
load();
function load(){
$.ajax({
type: "get",
url: "/message/getList",
success: function(messages){
if(messages != null && messages.length > 0){
var finalHtml = "";
for(var m of messages){
var item = "<div>"+m.from +"对" + m.to + "说:" + m.message+"</div>"
finalHtml += item;
}
$(".container").append(finalHtml);
}
}
});
}
function submit(){
//1. 获取留言的内容
var from = $('#from').val();
var to = $('#to').val();
var say = $('#say').val();
if (from== '' || to == '' || say == '') {
return;
}
var data = {
from: from,
to: to,
message: say
};
$.ajax({
type: "post",
url: "/message/publish",
data: JSON.stringify(data),
contentType: "application/json",
success: function(result){
if(result.ok == 1){
//yes
//2. 构造节点
var divE = "<div>"+from +"对" + to + "说:" + say+"</div>";
//3. 把节点添加到页面上
$(".container").append(divE);
//4. 清空输入框的值
$('#from').val("");
$('#to').val("");
$('#say').val("");
}else{
//no
alert("留言发布失败");
}
}
});
}
</script>
功能:实现留言板功能,用户输入留言并提交,成功后留言显示在页面上。
load 函数:
发起 GET 请求到
/message/getList
获取留言列表。如果获取到留言列表,遍历列表生成 HTML 元素,并追加到页面的
.container
元素中。submit 函数:
获取用户输入的留言内容(留言人、收件人、留言内容)。
检查输入框是否为空,为空则不执行操作。
将留言内容封装成 JSON 数据格式,发起 POST 请求到
/message/publish
。请求成功且服务器返回
ok
为1
时,将留言内容添加到页面.container
元素中,并清空输入框。如果请求失败,弹出警告框提示“留言发布失败”。
运行结果:
2.4图书管理系统
2.4.1约定前后端接口
接口1:登录接口
URL:
POST /user/login
请求参数:
name=admin
&password=admin
响应:
true
// 账号密码验证成功
false
// 账号密码验证失败
接口2:图书列表展示
URL:
POST /book/getList
请求参数:无
响应:返回图书列表:
[ { "id": 1, "bookName": "活着", "author": "余华", "count": 270, "price": 20, "publish": "北京文艺出版社", "status": 1, "statusCN": "可借阅" }, ... ]
2.4.2后端核心代码讲解
代码分配:
@RequestMapping("/user")
@RestController
public class UserController {
@RequestMapping("/login")
public boolean login (String name, String password, HttpSession session){
if(!StringUtils.hasLength(name) || !StringUtils.hasLength(password)){
return false;
}
if("admin".equals(name) && "admin".equals(password)){
session.setAttribute("userName", name);
return true;
}
return false;
}
}
类定义:定义了一个名为
UserController
的类,并使用@RestController
注解,标识这是一个控制器类。方法
login
:
使用
@RequestMapping("/login")
注解映射 HTTP POST 请求到/user/login
路径。接收用户名 (
name
) 和密码 (password
) 作为参数,并使用HttpSession
存储会话信息。检查用户名和密码是否非空。
如果用户名和密码都是 "admin",则将用户名存储在会话中,并返回
true
表示登录成功。如果用户名或密码不匹配,则返回
false
表示登录失败。
@RequestMapping("/book")
@RestController
public class BookController {
@RequestMapping("/getList")
public List<BookInfo> getList(){
//mock数据
List<BookInfo> bookInfos = mockData();
for (BookInfo bookInfo : bookInfos){
if(bookInfo.getStatus() == 1){
bookInfo.setStatusCN("可借阅");
}else{
bookInfo.setStatusCN("不可借阅");
}
}
return bookInfos;
}
public List<BookInfo> mockData(){
List<BookInfo> bookInfos = new ArrayList<>();
for(int i = 1;i <= 15;i++){
BookInfo bookInfo = new BookInfo();
bookInfo.setBookid(i);
bookInfo.setBookname("book" + i);
bookInfo.setAuthor("author" + i);
bookInfo.setPublish("publish" + i);
bookInfo.setNum(new Random().nextInt(100));
bookInfo.setPrice(new BigDecimal(new Random().nextInt(100)));
bookInfo.setStatus(i % 5 == 0 ? 2 : 1);//1可借阅,2不可借阅
bookInfos.add(bookInfo);
}
return bookInfos;
}
}
类定义:定义了一个名为
BookController
的类,并使用@RestController
注解,标识这是一个控制器类。方法
getList
:
使用
@RequestMapping("/getList")
注解映射 HTTP 请求到/book/getList
路径。返回一个
BookInfo
对象的列表,表示图书列表。列表中的每个
BookInfo
对象根据其status
属性设置statusCN
属性为 "可借阅" 或 "不可借"。方法
mockData
:
用于生成模拟图书数据。
创建一个包含15个
BookInfo
对象的列表,每个对象的属性使用循环变量i
和随机数生成。将生成的
BookInfo
对象添加到列表中并返回。
2.4.3前端核心代码讲解
<script>
function add() {
//请求后端
$.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>
功能:实现用户登录功能,提交用户名和密码到服务器进行验证。
请求方式:使用POST方法将数据发送到服务器的
/user/login
路径。数据:从页面上的
userName
和password
输入框中获取用户名和密码。成功处理:如果服务器返回
true
(账号密码验证成功),则跳转到book_list.html
页面。失败处理:如果服务器返回
false
(账号密码验证失败),则弹出警告框提示“账号或密码有误”。
<script>
getBookList();
function getBookList() {
$.ajax({
type: "get",
url: "/book/getList",
success:function(books){
var finalHtml = "";
for(var book of books){
finalHtml += '<tr>';
finalHtml += '<td><input type="checkbox" name="selectBook" value="'+ book.bookid +'" id="selectBook" class="book-select"></td>';
finalHtml += '<td>'+book.bookid+'</td>';
finalHtml += '<td>'+book.bookname+'</td>';
finalHtml += '<td>'+book.author+'</td>';
finalHtml += '<td>'+book.num+'</td>';
finalHtml += '<td>'+book.price+'</td>';
finalHtml += '<td>'+book.publish+'</td>';
finalHtml += '<td>'+book.statusCN+'</td>';
finalHtml += '<td>';
finalHtml += '<div class="op">';
finalHtml += '<a href="book_update.html?bookId='+book.bookid+'">修改</a>';
finalHtml += '<a href="javascript:void(0)" onclick="deleteBook('+book.bookid+')">删除</a>';
finalHtml += '</div>';
finalHtml += '</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>',
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) {
//获取复选框的id
var ids = [];
$("input:checkbox[name='selectBook']:checked").each(function () {
ids.push($(this).val());
});
console.log(ids);
alert("批量删除成功");
}
}
</script>
功能:从服务器获取图书列表并在网页上显示,提供分页功能和删除图书功能。
AJAX请求:
使用GET方法请求
/book/getList
路径获取图书列表。成功后,遍历图书列表,为每本图书生成HTML表格行,并更新到页面的
<tbody>
元素中。分页功能:
使用
.jqPaginator
插件实现分页功能。配置总记录数、每页记录数、可视页数等参数。
为分页组件的导航按钮(首页、上一页、下一页、最后一页)和页码项设置点击事件处理器,点击时打印当前页码和类型。
删除图书:
deleteBook
函数:弹出确认对话框询问用户是否删除图书,如果用户确认,则显示删除成功的提示。
batchDelete
函数:弹出对话框询问用户是否批量删除选中的图书,如果用户确认,则获取所有选中的图书ID并打印到控制台,显示批量删除成功的提示。
3.小结
今天的分享到这里就结束了,喜欢的小伙伴点点赞点点关注,需要所有的源代码可以去我的gitee上就可以啦~你的支持就是对我最大的鼓励,大家加油!
爱吃烤鸡翅的酸菜鱼 (crjs-hao) - Gitee.comhttps://gitee.com/crjs-hao