当前位置: 首页 > news >正文

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/sumpublic 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/loginpublic boolean login(String userName,String password,HttpServletRequest request){//当用户输入空字符或者没有输入,返回falseif(!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;}//其他情况,返回falsereturn false;}//getUser方法,负责第4个事务的完成@RequestMapping("/getUser") //访问路径:user/getUserpublic String  getUserName(HttpServletRequest request){HttpSession session=request.getSession();//从请求报文中获取SessionString userName=(String) session.getAttribute("userName");//从Session中获取userNamereturn 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/logindata:{//获取标签的值,赋值给后端指定的参数//左边的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){//用户名和密码正确,后端返回truelocation.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。

相关文章:

Spring Web MVC综合案例

承接上篇文章——Spring Web MVC探秘&#xff0c;在了解Spring Web MVC背后的工作机制之后&#xff0c;我们接下来通过三个实战项目&#xff0c;来进一步巩固一下前面的知识。 一、计算器 效果展示&#xff1a;访问路径&#xff1a;http://127.0.0.1:8080/calc.html 前端代码&a…...

微软预测 AI 2025,AI Agents 重塑工作形式

1月初&#xff0c;微软在官网发布了2025年6大AI预测&#xff0c;分别是&#xff1a;AI模型将变得更加强大和有用、AI Agents将彻底改变工作方式、AI伴侣将支持日常生活、AI资源的利用将更高效、测试与定制是开发AI的关键以及AI将加速科学研究突破。 值得一提的是&#xff0c;微…...

lvgl性能调优

LV_USE_PERFORMANCE lvgl_performance 是 LVGL 提供的性能分析工具&#xff0c;可以帮助开发者评估和优化图形库的性能。在一些特定的版本中&#xff0c;lvgl_performance 是一个宏或者工具&#xff0c;用来分析性能瓶颈&#xff0c;特别是图形渲染的效率。 下面是如何使用 l…...

CSS实现实现票据效果 mask与切图方式

一、“切图”的局限性 传统的“切图”简单暴力,但往往缺少适应性。 适应性一般有两种,一是尺寸自适应,二是颜色可以自定义。 举个例子,有这样一个优惠券样式 关于这类样式实现技巧,之前在这篇文章中有详细介绍: CSS 实现优惠券的技巧 不过这里略微不一样的地方是,两个…...

STL--list(双向链表)

目录 一、list 对象创建 1、默认构造函数 2、初始化列表 3、迭代器 4、全0初始化 5、全值初始化 6、拷贝构造函数 二、list 赋值操作 1、赋值 2、assign&#xff08;迭代器1&#xff0c;迭代器2&#xff09; 3、assign&#xff08;初始化列表&#xff09; 4、assig…...

ZooKeeper 中的 ZAB 一致性协议与 Zookeeper 设计目的、使用场景、相关概念(数据模型、myid、事务 ID、版本、监听器、ACL、角色)

参考Zookeeper 介绍——设计目的、使用场景、相关概念&#xff08;数据模型、myid、事务 ID、版本、监听器、ACL、角色&#xff09; ZooKeeper 设计目的、特性、使用场景 ZooKeeper 的四个设计目标ZooKeeper 可以保证如下分布式一致性特性ZooKeeper 是一个典型的分布式数据一致…...

“深入浅出”系列之C++:(11)推荐一些C++的开源项目

1. SQLiteCpp - 简单易用的Sqlite C封装库 仓库地址&#xff1a;https://github.com/SRombauts/SQLiteCpp 简介&#xff1a;SQLiteCpp是一个对Sqlite数据库进行C封装的开源库&#xff0c;代码行数约2,500行。它提供了简洁易用的接口&#xff0c;使得在C项目中操作Sqlite数据库…...

《重生到现代之从零开始的C++生活》—— 类和对象2

类的默认成员函数 默认成员函数就是用户没有显示实现&#xff0c;编译器会自动生成的成员函数&#xff0c;一个类会默认生成6个成员函数 构造函数 构造函数时特殊的成员函数&#xff0c;构造函数的初始化对象 函数名与类名相同 没有返回值 对象实例化的时候胡自动调用构造…...

“UniApp的音频播放——点击视频进入空白+解决视频播放器切换视频时一直加载的问题”——video.js、video-js.css

今天&#xff0c;又解决了一个单子“UniApp的音频播放——点击视频进入空白解决视频播放器切换视频时一直加载的问题” 一、问题描述 在开发一个基于 video.js 的视频播放器时&#xff0c;用户通过上下滑动切换视频时&#xff0c;视频一直处于加载状态&#xff0c;无法正常播放…...

【Pandas】pandas Series transform

Pandas2.2 Series Function application, GroupBy & window 方法描述Series.apply()用于将一个函数应用到 Series 的每个元素或整个 SeriesSeries.agg()用于对 Series 数据进行聚合操作Series.aggregate()用于对 Series 数据进行聚合操作Series.transform()用于对 Series…...

【博客之星2024年度总评选】年度回望:我的博客之路与星光熠熠

【个人主页】Francek Chen 【人生格言】征途漫漫&#xff0c;惟有奋斗&#xff01; 【热门专栏】大数据技术基础 | 数据仓库与数据挖掘 | Python机器学习 文章目录 前言一、个人成长与盘点&#xff08;一&#xff09;机缘与开端&#xff08;二&#xff09;收获与分享 二、年度创…...

飞牛 使用docker部署Watchtower 自动更新 Docker 容器

Watchtower是一款开源的Docker容器管理工具&#xff0c;其主要功能在于自动更新运行中的Docker容器 Watchtower 支持以下功能&#xff1a; 自动拉取镜像并更新容器。 配置邮件通知。 定时执行容器更新任务。 compose搭建Watchtower 1、新建文件夹 先在任意位置创建一个 w…...

【Block总结】TAdaConv时序自适应卷积,轻量高效的时间建模卷积|即插即用

论文解读&#xff1a;Temporally-Adaptive Models for Efficient Video Understanding 论文信息 标题&#xff1a;Temporally-Adaptive Models for Efficient Video Understanding 发表时间&#xff1a;2023年 作者&#xff1a;黄子渊等 论文链接&#xff1a;arXiv 论文 代…...

Spring Boot 项目启动报错 “找不到或无法加载主类” 解决笔记

一、问题描述 在使用 IntelliJ IDEA 开发基于 Spring Boot 框架的 Java 程序时&#xff0c;原本项目能够正常启动。但在后续编写代码并重建项目后&#xff0c;再次尝试运行却出现了 “错误&#xff1a;找不到或无法加载主类 com.example.springboot.SpringbootApplication” 的…...

CSS 网络安全字体

适用于 HTML 和 CSS 的最佳 Web 安全字体 下面列出了适用于 HTM L和 CSS 的最佳 Web 安全字体&#xff1a; Arial (sans-serif)Verdana (sans-serif)Helvetica (sans-serif)Tahoma (sans-serif)Trebuchet MS (sans-serif)Times New Roman (serif)Georgia (serif)Garamond (se…...

Linux高并发服务器开发 第十五天(fork函数)

目录 1.fork 函数 1.1创建子进程 1.2getpid 函数 1.3getppid 函数 1.4getgid函数 1.5循环创建 n 个子进程 1.6fork后父子进程异同 1.6.1读时共享&#xff0c;写时复制 1.6.2fork后父子进程共享 1.6.3gdb调试父子进程 1.fork 函数 pid_t fork(void); 成功&#xff1a;…...

【人工智能】Python中的自动化机器学习(AutoML):如何使用TPOT优化模型选择

《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门&#xff01; 解锁Python编程的无限可能&#xff1a;《奇妙的Python》带你漫游代码世界 随着机器学习在各行业的广泛应用&#xff0c;模型选择和优化成为了数据科学家面临的主要挑战之一。自动化机器学习&am…...

探秘自然地理:从太阳到地球的奇妙之旅与灾害预警

在浩瀚无垠的宇宙中&#xff0c;我们的地球与太阳紧密相连&#xff0c;它们的奥秘和变化&#xff0c;时刻影响着我们的生活。今天&#xff0c;就让我们一同深入探索自然地理的基础知识&#xff0c;揭开太阳与地球的神秘面纱&#xff0c;同时了解那些可能给我们带来巨大影响的自…...

go语言zero框架通过chromedp实现网页在线截图的设计与功能实现

在 GoZero 框架中实现网页在线截图的功能&#xff0c;可以通过集成 chromedp 库来控制 Chrome 浏览器进行截图。chromedp 是一个基于 Chrome DevTools 协议的 Go 包&#xff0c;可以用来在 Go 程序中模拟浏览器操作&#xff0c;如页面截图、DOM 操作、表单提交等。 下面是一个…...

AI发展困境:技术路径与实践约束的博弈

标题&#xff1a;AI发展困境&#xff1a;技术路径与实践约束的博弈 文章信息摘要&#xff1a; AI技术发展路径主要受实践约束驱动&#xff0c;而非纯理论优势。大型AI实验室的成功更依赖优质执行力和资源优势&#xff0c;而非独特技术创新。当前AI发展面临评估体系与实际应用脱…...

SkyWalking 10.2.0 SWCK 配置过程

SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外&#xff0c;K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案&#xff0c;全安装在K8S群集中。 具体可参…...

全球首个30米分辨率湿地数据集(2000—2022)

数据简介 今天我们分享的数据是全球30米分辨率湿地数据集&#xff0c;包含8种湿地亚类&#xff0c;该数据以0.5X0.5的瓦片存储&#xff0c;我们整理了所有属于中国的瓦片名称与其对应省份&#xff0c;方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

(二)原型模式

原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

基于SpringBoot在线拍卖系统的设计和实现

摘 要 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统&#xff0c;主要的模块包括管理员&#xff1b;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...

Vue ③-生命周期 || 脚手架

生命周期 思考&#xff1a;什么时候可以发送初始化渲染请求&#xff1f;&#xff08;越早越好&#xff09; 什么时候可以开始操作dom&#xff1f;&#xff08;至少dom得渲染出来&#xff09; Vue生命周期&#xff1a; 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...

DeepSeek源码深度解析 × 华为仓颉语言编程精粹——从MoE架构到全场景开发生态

前言 在人工智能技术飞速发展的今天&#xff0c;深度学习与大模型技术已成为推动行业变革的核心驱动力&#xff0c;而高效、灵活的开发工具与编程语言则为技术创新提供了重要支撑。本书以两大前沿技术领域为核心&#xff0c;系统性地呈现了两部深度技术著作的精华&#xff1a;…...

鸿蒙(HarmonyOS5)实现跳一跳小游戏

下面我将介绍如何使用鸿蒙的ArkUI框架&#xff0c;实现一个简单的跳一跳小游戏。 1. 项目结构 src/main/ets/ ├── MainAbility │ ├── pages │ │ ├── Index.ets // 主页面 │ │ └── GamePage.ets // 游戏页面 │ └── model │ …...

智能职业发展系统:AI驱动的职业规划平台技术解析

智能职业发展系统&#xff1a;AI驱动的职业规划平台技术解析 引言&#xff1a;数字时代的职业革命 在当今瞬息万变的就业市场中&#xff0c;传统的职业规划方法已无法满足个人和企业的需求。据统计&#xff0c;全球每年有超过2亿人面临职业转型困境&#xff0c;而企业也因此遭…...