Spring Web MVC综合案例
承接上篇文章——Spring Web MVC探秘,在了解Spring Web MVC背后的工作机制之后,我们接下来通过三个实战项目,来进一步巩固一下前面的知识。
一、计算器
效果展示:访问路径:http://127.0.0.1:8080/calc.html
前端代码:(文件名:calc.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>
</head>
<body>
<!--点击“按钮”后,页面会跳转到calc/sum页面-->
<form action="calc/sum" method="post">
<h1>计算器</h1>
数字1:<input name="num1" type="text"><br>
数字2:<input name="num2" type="text"><br>
<!-- 只有<input>标签且具有name属性的内容才会被作为表单参数,传递给后端-->
<input type="submit" value=" 点击相加 ">
</form>
</body>
</html>
后端代码:
package com.example.mvc_test1;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/calc")
public class CalcController {
@RequestMapping("/sum")//访问路径=类路径+方法路径:/calc/sum
public String sum(Integer num1,Integer num2){
Integer sum= num1+num2;
return "计算的结果是:"+sum;
}
}
代码解析:
前端部分:
当用户在num1和num2输入框中输入数字后,点击 “点击相加” 按钮,浏览器会根据<form>标签的action属性("calc/sum")和method属性("post"),将表单数据以POST请求的方式发送到后端对应的/calc/sum路径。
后端部分:
1、后端的CalcController类被@RestController注解标记,表明它是一个处理 RESTful 请求的控制器,并且被@RequestMapping("/calc")映射到/calc路径下。
2、sum方法被@RequestMapping("/sum")注解,意味着它处理/calc/sum路径的请求。
3、当后端发送请求到calc/sum路径时,后端代码从前端参数表单中获取参数num1和num2,赋值给sum方法的两个名称对应的参数num1、num2
4、Integer sum = num1 + num2;:在后端接收到这两个参数后,将它们相加,得到结果sum。
return "计算的结果是:" + sum;:最后,将计算结果以字符串的形式返回给前端,前端会根据响应进行相应的显示或处理。
二、用户登录界面
效果展示:访问路径:http://127.0.0.1:8080/login.html
用户名错误登录:
用户名和密码正确登录:
后端代码:
我们先来分析一下这个”登录界面”的需求,当用户输入用户名和密码之后,后端服务器需要做两件事:
1、判断用户是否进行合法的输入
2、校验用户名和密码是否正确
3、将用户名存入Session中
4、返回用户名给前端,
我们将这四件事封装到两个方法中:login方法和getUser方法
@RestController
@RequestMapping("/user")
public class UserController {
//login方法:负责1、2、3件事务的完成
@RequestMapping("/login") //访问路径:/user/login
public boolean login(String userName,String password,HttpServletRequest request){
//当用户输入空字符或者没有输入,返回false
if(!StringUtils.hasLength(userName)||!StringUtils.hasLength(password)){
return false;
}else if("admin".equals(userName)&&"admin".equals(password)){//校验用户名和密码是否正确
//用户名和密码这里都设置为admin
//登录成功,将用户名设置到Session中
HttpSession session=request.getSession();
session.setAttribute("userName",userName);
return true;
}
//其他情况,返回false
return false;
}
//getUser方法,负责第4个事务的完成
@RequestMapping("/getUser") //访问路径:user/getUser
public String getUserName(HttpServletRequest request){
HttpSession session=request.getSession();//从请求报文中获取Session
String userName=(String) session.getAttribute("userName");//从Session中获取userName
return userName;
}
}
注:StringUtils.hasLength()是一个工具方法,用于检查字符串是否有长度(即不为null且长度大于0)。
前端代码:登录页面(login.html) 和登录成功的页面(index.html)
由于这两个页面的实现,需要引入一个js文件,我们先来讲一下如何有引入?
1、js下载文件网址: https://code.jquery.com/jquery-3.7.1.min.js
2、将刚刚下载的js文件,赋值粘贴到static文件夹下面:
登录页面:login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
<h1>用户登录</h1>
用户名:<input name="userName" type="text" id="userName"><br>
密码:<input name="password" type="password" id="password"><br>
<input type="button" value="登录" onclick="login()">
<script src="jquery-3.7.1.min.js"></script> <!-- 引入js文件-->
<script>
function login() {
$.ajax({
type:"post",//请求类型
url:"/user/login",//访问后端服务器的user/login
data:{
//获取标签的值,赋值给后端指定的参数
//左边的usrName表示后端/user/login 方法中的参数userName
//右边userName表示id为userName的标签
"userName":$("#userName").val(),//val()获取标签的值
"password":$("#password").val()
},
success:function (result){//访问成功,后端返回一个结果,作为function的参数result
//访问/user/login时,后端会将这个请求交给login方法处理,处理结果返回true或false,表示登录成功与否
if(result==true){//用户名和密码正确,后端返回true
location.href="index.html";
}else{
alert("用户名或者密码错误");
}
}
});
}
</script>
</body>
</html>
登录成功的页面: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="jquery-3.7.1.min.js"></script> <!-- 引入js文件-->
<script>
$.ajax({
type:"get",
url:"/user/getUser",
success:function (userName){//访问成功,后端返回的结果作为function方法的参数
//访问user/getUser时,后端会将这个请求交给getUser方法处理,结果返回用户名
$("#loginUser").text(userName);
}
});
</script>
</body>
</html>
前端代码解析:
或许你有一个疑问,用户在输入用户名和密码后,校验工作是在后端中的login方法完成的,那么校验完成后,前端是如何获取后端检验后的结果呢?这其实借助了一个技术——Ajax。
Ajax(Asynchronous JavaScript and XML)即异步 JavaScript 和 XML,是一种创建快速动态网页的技术。
这里截取了login.html前端代码中使用到Ajax的部分代码(省略注释版):
$.ajax({
type: "post",
url: "/user/login",
data: {
"userName": $("#userName").val(),
"password": $("#password").val()
},
success: function (result) {
if (result == true) {
location.href = "index.html";
} else {
alert("用户名或者密码错误");
}
}
});
1、 $.ajax({...}):这是 jQuery 的 ajax 函数,用于发起HTTP 请求。
2、type: "post":指定请求的类型为 POST。这意味着会向服务器发送一个 POST 请求。
3、url: "/user/login":指定请求的 URL,即要发送请求的后端服务地址,这里会将请求发送到 /user/login 路径。
4、data:这是要发送给服务器的数据,是一个对象。"userName": $("#userName").val():使用 jQuery 的 $("#userName") 选择器选中 id 为 userName 的元素,并通过 val() 方法获取其值,将其赋值给 userName 属性。
5、"password": $("#password").val():同理,获取 id 为 password 的元素的值,并将其赋值给 password 属性。
6、success: function (result) {...}:定义请求成功时的回调函数。result:当请求成功后,服务器返回的数据将作为 result 参数传递给该回调函数。
7、if (result == true) {...} else {...}:根据服务器返回的结果进行不同的操作。location.href = "index.html";:如果结果为 true,说明登录成功,将页面重定向到 index.html。alert("用户名或者密码错误");:如果结果不为 true,弹出一个警告框,提示用户用户名或密码错误。
三、留言板
效果展示:访问路径:http://127.0.0.1:8080/messagewall.html
后端代码:
让我们来分析一下这个“留言板”,首先,在打开这个留言板的时候,留言板会加载历史的留言记录,然后,在用户添加新留言之后,点击“提交”,新的留言会添加到页面上。
根据功能,后端代码需要完成两件事:
1、在前端打开这个页面的时候,返回历史留言内容给前端,用于前端加载历史留言内容
2、在用户添加新的留言的时候,将这条新留言存储在后端服务器中
MessageInfo类:
@Data//会自动生成该类的成员的Getter和Setter等方法,需要在pom.xml引入lombok依赖
public class MessageInfo {
String from;
String to;
String say;
}
在pom.xml中引入lombok依赖(@Data注解使用需要)
MessageController类:
@RestController
@RequestMapping("/message")
public class MessageController {
List<MessageInfo> list=new ArrayList<>();//存放留言内容
//getList方法:返回历史留言内容给前端(访问路径:/message/getList)
@RequestMapping("/getList")
public List<MessageInfo> getList(){
return list;
}
//publish方法:将用户新添加的留言存在后端服务器中(访问路径:/message/publish)
//获取用户输入的内容,添加到list,返回一个json字符串
@RequestMapping(value = "/publish",produces = "application/json")
//指定该方法返回的数据类型为application/json,表明此方法返回的内容是 JSON 格式。告知前端返回的数据是 JSON 格式。
public String publish(@RequestBody MessageInfo message){
if(StringUtils.hasLength(message.from)&&
StringUtils.hasLength(message.to)&&
StringUtils.hasLength(message.say)){
list.add(message);
return "{\"ok\":1}";//1表示添加成功
}
return "{\"ok\":0}";//0表示添加失败
}
}
前端代码: messagewall.html
<!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="jquery-3.7.1.min.js"></script> <!-- 引入js文件-->
<script>
//加载历史留言记录
$.ajax({
type:"get",
url:"/message/getList",
success:function (list){
for(let msg of list){
console.log(1);
let divE = "<div>"+msg.from +"对" +msg.to + "说:" + msg.say+"</div>";//拼接留言
$(".container").append(divE);//把留言内容添加到页面上
}
}
});
function submit(){
//获取留言的内容
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",
data:JSON.stringify({
"from":from,
"to":to,
"say":say
}),
success:function (result){
if(result.ok==1){
alert("添加成功")
//构造节点
let divE = "<div>"+from +"对" + to + "说:" + say+"</div>";
//把节点添加到页面上
$(".container").append(divE);
//清空输入框的值
$('#from').val("");
$('#to').val("");
$('#say').val("");
}else{
alert("添加失败")
}
}
});
}
</script>
</body>
</html>
前端代码解析:
1、注释“传递留言内容给前端部分”代码:
contentType: "application/json":告诉后端,我要传给你一个Json字符串的数据。
data: JSON.stringify({...}):将包含from、to、say的对象转换为 JSON 字符串作为请求数据发送给后端,让后端的publish方法中的message接收。
success:function(result):当后端返回一个json字符串给前端接收时,前端会自动将这个json字符串转换为一个对象,例如这里的publish方法返回的如果是 {“ok”:1} 的json字符串,将其作为参数传送给function时,此时的result就成为了一个包含“ok”属性的对象,其属性值为1。