当前位置: 首页 > 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发展面临评估体系与实际应用脱…...

告别网盘限速烦恼:八大平台直链下载工具完整指南

告别网盘限速烦恼&#xff1a;八大平台直链下载工具完整指南 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 &#xff0c;支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼云盘 …...

G-Helper:华硕笔记本轻量化控制解决方案详解

G-Helper&#xff1a;华硕笔记本轻量化控制解决方案详解 【免费下载链接】g-helper Lightweight, open-source control tool for ASUS laptops and ROG Ally. Manage performance modes, fans, GPU, battery, and RGB lighting across Zephyrus, Flow, TUF, Strix, Scar, and o…...

对比实验:Fish-Speech-1.5与传统TTS模型的性能差异

对比实验&#xff1a;Fish-Speech-1.5与传统TTS模型的性能差异 1. 实验设计与测试环境 为了全面评估Fish-Speech-1.5的实际表现&#xff0c;我们设计了一套严谨的对比测试方案。测试环境选择了业界常见的硬件配置&#xff0c;确保结果具有参考价值。 测试平台采用NVIDIA RTX…...

Jimeng LoRA应用案例:快速测试不同Epoch版本,找到最佳训练效果

Jimeng LoRA应用案例&#xff1a;快速测试不同Epoch版本&#xff0c;找到最佳训练效果 1. 项目背景与核心价值 在LoRA模型训练过程中&#xff0c;我们常常面临一个关键问题&#xff1a;**如何确定哪个训练阶段的模型效果最好&#xff1f;**传统方法需要反复加载不同Epoch版本…...

VSCode下载与配置Starry Night Art Gallery开发环境

VSCode下载与配置Starry Night Art Gallery开发环境 如果你对“Starry Night Art Gallery”这个项目感兴趣&#xff0c;想动手参与开发或者自己搭建一个类似的数字艺术画廊&#xff0c;那么第一步就是准备好趁手的开发工具。Visual Studio Code&#xff08;简称VSCode&#xf…...

营销自动化数据驱动 - 多源数据 OLAP 架构演进们

1. 流图&#xff1a;数据的河流 如果把传统的堆叠面积图想象成一块块整齐堆叠的积木&#xff0c;那么流图就像一条蜿蜒流淌的河流&#xff0c;河道的宽窄变化自然流畅&#xff0c;波峰波谷过渡平滑。 它特别适合展示多个类别数据随时间的变化趋势&#xff0c;尤其是当你想强调整…...

React Native Collapsible高级技巧:10个优化动画性能的方法

React Native Collapsible高级技巧&#xff1a;10个优化动画性能的方法 【免费下载链接】react-native-collapsible Animated collapsible component for React Native, good for accordions, toggles etc 项目地址: https://gitcode.com/gh_mirrors/re/react-native-collaps…...

科研党必备:OpenClaw+Kimi-VL-A3B-Thinking自动解析论文图表数据

科研党必备&#xff1a;OpenClawKimi-VL-A3B-Thinking自动解析论文图表数据 1. 为什么需要自动化论文图表解析 作为一名经常需要阅读大量文献的科研人员&#xff0c;我发现自己花费在论文图表数据提取上的时间越来越多。传统的手动记录数据点、绘制趋势图的方式不仅效率低下&…...

知识竞赛软件如何选择?抢答器功能

知识竞赛软件怎么选&#xff1f;抢答器功能是关键 组织一场精彩、公平、高效的知识竞赛&#xff0c;离不开专业软件的支持。在众多功能中&#xff0c;抢答器功能往往是决定竞赛成败的核心。本文将系统性地探讨如何选择一款合适的知识竞赛软件&#xff0c;并深入分析抢答器功能…...

先进封装中如何判定凸点结合力大小?

在先进封装中&#xff0c;凸点&#xff08;Bump&#xff09;的结合力是决定芯片可靠性的核心指标。如果结合力不足&#xff0c;芯片在后续的倒装焊、底部填充或长期热循环中会出现分层或断路。判定凸点结合力大小&#xff0c;通常采用凸点剪切测试。简单来说&#xff0c;它的原…...