Spring web mvc入门练习

ops/2024/9/18 12:39:30/ 标签: spring, mvc

对于Spring方面的知识重在多练习

目录

一、计算器

1、前端界面

2、约定前后端交互接口

3、服务器代码

二、用户登录

前端代码

服务器代码

三、留言板

后端代码

前端代码


一、计算器

我们需要通过前后端的交互最终完成这样的界面以及完成需求

1、前端界面

因为主要学习的后端内容,所以前端的内容直接给大家

<!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">//action表示接下来要干啥,这里也就是操作后跳转到路径为calc/sum的页面<h1>计算器</h1>数字1:<input name="num1" type="text"><br>//这里表示输入的值赋值在num1数字2:<input name="num2" type="text"><br><input type="submit" value=" 点击相加 "></form>
</body></html>

此时通过浏览器访问前端的界面就是这样的 

url为文件名(calc.html)

2、约定前后端交互接口

接口又称API,是应用程序对外提供的服务的描述,用于交换信息和执行任务

简单来说就是允许客户端给服务器发出什么样的请求并且每种请求预期收到什么样的http响应。

接口文档

项目开发前,前后端先约定交互接口,双方按照接口文档进行开发(接口文档就像双方的协议,双方共同履行协议的内容进行开发,接口文档一旦写好轻易不可以改变,如果要改变必须告知另一方)

需求分析:客户端提供进行加法的两个数字,服务器计算出结果后返回

定义接口

基于需求分析我们来定义接口

请求路径calc/sum
请求方法GET
接口描述计算两个数的和

请求参数

类型变量名
Integernum1
Integer

num2

响应数据

Content-typehtml

这样我们的接口文档就完成了,接口文档的格式是自己定义的,目的是让客户端能看懂就好

3、服务器代码

首先按照我们在接口文档中定义的路径使用注释@RequestMapping来注释类和方法(不要忘了加@RestController)

@RestController
@RequestMapping("/calc")
public class CalcController {@RequestMapping("/sum")public String sum(Integer num1, Integer num2) {Integer sum = num1 + num2;return "<h1>相加后的和为: "+sum+"</h1>";}}

此时用浏览器测试得到的结果就可以直接是html标题

这里对后端方法进行单独测试是很有必要的,在前期学习Spring框架时最好“小步慢跑”,写完一个测试一个,到最后一起测试容易找不出错误

此时后端代码也测试完毕了,我们运行程序看结果

注意看两个url路径的变化

这样一个简单的加法计算器就完成了

二、用户登录

需求:用户输入账户和密码,后端进行校验密码是否正确

如果不正确,前端告知用户

如果正确,跳转到新页面显示用户名

后续再访问首页可以获取到用户信息

前端代码

有两个页面,第一个页面是登陆时的页面需输入账户和密码

依旧是在static的resource中创建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="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script><script>function login() {}</script>
</body></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></script>
</body></html>

 测试结果

约定前后端交互接口

需求分析

对于后端人员不涉及前端的页面展示,只需要提供两个功能:(1)根据用户输入的账户和密码校验密码是否正确并告知前端 (2)在首页时如果有登录用户返回账户名,没有用户返回空

接口定义

登录页面

请求路径/user/login
请求方式POST
接口描述校验密码是否正确

请求参数

passwordString
usernameString

响应数据

Content-Type:html

响应内容:true(密码正确) false(密码错误)

首页

需求分析

请求路径/user/getLoginUser
请求方式GET
接口描述查询当前登录用户

服务器代码

登录页面

按照需求分析将框架建立好

package com.example.demo;import jakarta.servlet.http.HttpSession;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/user")
public class LoginController {@RequestMapping("/login")public boolean login(String username, String password, HttpSession session) {}}

(1)当账户或密码为空时返回false(2)当账户密码不为空时判断对错,由于当前我们并没有学到操作数据库的操作所以暂时把代码写死,密码正确时将账户设置到服务器的session并返回true,

填写相应的逻辑后此时代码:

package com.example.demo;import jakarta.servlet.http.HttpSession;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/user")
public class LoginController {@RequestMapping("/login")public boolean login(String userName, String password, HttpSession session) {if(!StringUtils.hasLength(userName) || !StringUtils.hasLength(password)) {return false;}if("xuhan".equals(userName)&&"0920".equals(password)) {session.setAttribute("userName", userName); //在服务器session添加信息//session.setAttribute("password", password);return true;}return false;}}

 

服务器首页代码

这个页面我们需要在用户发出请求时查询它对应服务器的session是否为空,不为空就返回username,为空就返回空格;url地址也是我们在需求分析中规定的地址

package com.example.demo;import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/getLoginUser")
public class getLoginUser {@RequestMapping("/LoginUser")public String getLoginUser(HttpSession session) {String userName = (String) session.getAttribute("userName");if(StringUtils.hasLength(userName)) {return userName;}return " ";}}

此时我们后端两个界面的代码就写好了,接下来编写前端的代码,达到在前面界面输入账户密码能够跳转到后端页面的效果

在前端login代码的function中写入我们的逻辑,这里使用ajax来编写

<!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="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script><script>function login() {$.ajax({type : "post",url : "user/login",data : {"userName" : $("#userName").val(),"password" : $("#password").val()},success:function(result){ //result可以是任意名字,只表示从url地址的后端代码中返回的结果if(result == true){ //当返回的结果为true代表密码正确,跳转到location的界面location.href = "/index.html"}else{alert("密码错误"); //密码错误时提示密码错误}}});}</script>
</body></html>

测试一下该页面,预期结果是:密码错误时提示密码错误,正确时跳转到首页

这里可以看出两种情况都测试完成没有错误,此时可以再对代码进行进一步完善,比如账户名为空或者账户名重复等情况。

接下来完善首页的前端代码也就是index.html

 <script>$.ajax({type : "get",url : "/getLoginUser/LoginUser",success:function (result){$("#loginUser").text(result);}})</script>

,依旧使用ajax来实现,将从LoginUser获得的结果打印即可

此时测试一下首页

成功显示出了登陆人名字

三、留言板

需求输入留言信息,点击提交后端把数据存储起来,页面展示输入的表白墙信息,例如这样的界

前端页面只有一个,所以这次前端代码也只有一个文件

<!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="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script><script>function submit(){//1. 获取留言的内容var from = $('#from').val();var to = $('#to').val();var say = $('#say').val();if (from== '' || to == '' || say == '') {return;}//2. 构造节点var divE = "<div>"+from +"对" + to + "说:" + say+"</div>";//3. 把节点添加到页面上    $(".container").append(divE);//4. 清空输入框的值$('#from').val("");$('#to').val("");$('#say').val("");}</script>
</body></html>

这样一个示例的界面就展示好了,但需要前端调用后端的操作,所以后续还需在前端代码中添加逻辑

后端代码

需求分析:(1)用户输入留言信息之后后端把留言信息保存 (2)页面展示时需要从后端获取到所有的留言信息

接口定义

获取全部信息可以用List来表示,用Json描述这个List数据

urlMessage/getList
响应Json格式

 发表新留言也为Json格式

urlMessage/publish
响应Json格式

 定义留言对象message类,需要包含from(发送人)to(接收人)msg(要说的话)

package com.example.demo;import lombok.Data;@Data //这里使用的lombok工具包
public class message {private String from;private String to;private String msg;
}

 MessageController类来包含获取留言和发送留言的方法

创建List表来存储msg信息

publish:先校验参数是否为空,为空返回false,不为空则向表中添加信息

getList:直接返回整个表的信息即可

package com.example.demo;import org.apache.logging.log4j.message.Message;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.ArrayList;
import java.util.List;@RestController
@RequestMapping("/Message")
public class MessageController {List<message> messages = new ArrayList<message>();@RequestMapping("/publish")public boolean publish(message mes) {if(StringUtils.hasLength(mes.getFrom())&&StringUtils.hasLength(mes.getTo())&&StringUtils.hasLength(mes.getMsg())) {messages.add(mes);return true;}return false;}@RequestMapping("/getList")public List<message> getMessages() {return messages;}
}

这样后端逻辑就写好了,接下来我们测试一下,用postman发送请求,预期的效果是当三个参数全都不为空时返回true,如果有一个为空则返回false

 

测试成功,符合预期

前端代码

在页面加载时就要获取全部的信息,添加load函数用于在页面加载的时候获得数据

load();function load() {$.ajax({type: "get",url: "/message/getList",success: function (result) {for (var message of result) {var divE = "<div>" + message.from + "对" + message.to + "说:" +message.message + "</div>";$(".container").append(divE);}}});}

修改原来代码中的点击时间,在点击按钮时给服务器发送请求

function submit() {//1. 获取留言的内容var from = $('#from').val();var to = $('#to').val();var say = $('#say').val();if (from == '' || to == '' || say == '') {return;}$.ajax({type: "post",url: "/message/publish",data: {from: from,to: to,message: say},success: function (result) {if (result) {//2. 构造节点var divE = "<div>" + from + "对" + to + "说:" + say + "</div>";//3. 把节点添加到页面上    $(".container").append(divE);//4. 清空输入框的值$('#from').val("");$('#to').val("");$('#say').val("");} else {alert("发送失败");}}});}

这样前后端都写完了,我们进行测试结果成功

 

朋友们在萌新时期编写Spring代码时要学习注释的用法外,在编写时一定要注意前后端的变量名一致的地方要保持一致,否则很容易出现前端赋值变量后端无法收到的情况,我在用户登录这个项目排查了好久才发现原来是一个userName的n没大写 TAT

感谢观看

道阻且长,行则将至


http://www.ppmy.cn/ops/110332.html

相关文章

海鸥相机存储卡格式化如何恢复数据

在摄影的世界里&#xff0c;‌每一张照片都承载着独特的记忆与故事。‌然而&#xff0c;‌当我们不慎将海鸥相机的存储卡格式化后&#xff0c;‌那些珍贵的瞬间似乎瞬间消逝&#xff0c;‌让人心急如焚。‌但请不要绝望&#xff0c;‌数据恢复并非遥不可及。‌本文将详细介绍在…

RAG 聊天机器人:用 Langchain 和 Streamlit开启与 PDF 的智能对话

与大量 PDF 文档的交互如今变得前所未有地便捷与智能。想象一下,您可以轻松与您的笔记、书籍和各种文档进行无缝对话,不再需要繁琐的手动查找和处理。 这篇文章将带您逐步构建一个基于 Multi-RAG 和 Streamlit 的 Web 应用程序,该应用程序通过 AI 驱动的聊天机器人来读取、…

[论文笔记] LLM大模型清洗篇——1、规则清洗去重模型清洗

规则清洗 gopher、C4、Fineweb 论文的规则 算子名称 算子描述 算子来源 应用维度 过滤条件 duplicate_line_fraction 行重复率 Gopher 文档级别 ≤ 0.30 duplicate_paragraph_fraction 自然段重复率 Gopher 文档级别 ≤ 0.30 duplicate_line_character_fraction 行字符重复率 …

LeetCode:64. 最大正方形 动态规划 时间复杂度O(nm)

64. 最大正方形 题目链接 题目描述 给定一个由 0 和 1 组成的二维矩阵&#xff0c;找出只包含 1 的最大正方形&#xff0c;并返回其面积。 示例1: 输入: 1 0 1 0 0 1 0 1 1 1 1 1 1 1 1 1 0 0 1 0输出: 4示例2: 输入: 0 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1输出: 9解题…

java重点学习-集合(List)

七 集合&#xff08;List&#xff09; 7.1 复杂度分析 7.2 数组 1.数组(Array)是一种用连续的内存空间存储相同数据类型 数据的线性数据结构。 2.数组下标为什么从0开始 寻址公式是:baseAddressi*dataTypeSize&#xff0c;计算下标的内存地址效率较高 3.查找的时间复杂度 随机(…

无人机 PX4 飞控 | 如何检测状态估计EKF性能

无人机 PX4 飞控 | 如何检测状态估计EKF性能 前言检查EKF性能缺少pyulog问题解决脚本崩溃没有输出文件生成对应文件 结语 前言 ECL &#xff08;Estimation and Control Library&#xff0c;估计和控制库&#xff09;&#xff0c;其中的状态估计使用扩展卡尔曼滤波算法&#x…

C文件操作

文件的打开和关闭 头函数&#xff1a;#include <stdio.h> fopen FILE* fopen(const char *path,const char *mode) 功能&#xff1a;打开文件并为文件创建缓冲区 path&#xff1a;目标文件路径 mode&#xff1a;-r&#xff0c;-w&#xff0c;-rw 返回值&#xff1a; 成…

c++的单例模式

单例模式 什么是单例模式 只能创建出一个对象的结构、联合、类叫单例模式。 什么时候需要使用单例模式 1、Windows系统的任务管理器。 2、网络或服务器程序的访问计数器。 3、线程池、数据池&#xff0c;一个程序中只能创建一个线程池或数据池。 单例模式的实现原理 1、…

网页时装购物:Spring Boot框架的创新应用

第2章相关技术 2.1 B/S架构 B/S结构的特点也非常多&#xff0c;例如在很多浏览器中都可以做出信号请求。并且可以适当的减轻用户的工作量&#xff0c;通过对客户端安装或者是配置少量的运行软件就能够逐步减少用户的工作量&#xff0c;这些功能的操作主要是由服务器来进行控制的…

半导体芯闻--20240913

1、舜宇光学在2024年上半年业绩表现亮眼&#xff0c;营收和净利润同比大幅增长。公司资产规模维持较高水平&#xff0c;短期偿债能力强。研发投入持续增加&#xff0c;特别是在车载模组领域取得显著成绩&#xff0c;与多家主流平台方案厂商深度合作&#xff0c;巩固了其在车载模…

ArrayList、LinkedList和Vector的区别

ArrayList 容量默认是10&#xff0c;它和 Vector 的底层实现都是基于动态数组&#xff0c;ArrayList 的内部元素可以通过 get 和 set 方法进行访问&#xff1b;LinkedList的底层实现是基于双向链表&#xff0c;当数据量很大或者操作很频繁的情况下&#xff0c;插入和删除元素时…

用Git把本地仓库上传到远程仓库

用Git把本地仓库上传到远程仓库 GitHub创建远程仓库 在创建新仓库界面里输入你的仓库名后点击Create repository就好了。 创建本地项目 当你已经有一个项目后在命令行输入如下指令即可 git init git commit -m "first commit" git branch -M main git remote a…

关于武汉芯景科技有限公司的IIC电平转换芯片XJ4300开发指南(兼容LTC4300)

一、芯片引脚介绍 1.芯片引脚 2.引脚描述 二、系统结构图 三、功能描述 1.电平转换

数据结构-----栈、队列

一、栈 1、栈(stack)是限定仅在表尾进行插入和删除操作的线性表。 把允许插入和删除的一端称为栈顶&#xff08;top)&#xff0c;另一端称为栈底&#xff08;bottom)&#xff0c;不含任何数据元素的栈称为空栈。栈又称为后进先出&#xff08;Last In First Out)的线性表,简称L…

SpringMVC基于注解使用:上传下载

01-文件下载 基于servlet api的文件下载 注意一点content-disposition是以文件下载的方式打开意思是客户端地址栏不会改变&#xff0c; 如果注销了那句话就会跳转到下载图片的图片里面去&#xff0c;就在网页中显示了 基于spring ResponseEntity的文件下载 不支持缓冲区 一次…

【C语言】归并排序递归和非递归——动图演示

目录 一、归并排序思想1.1 基本思想1.2 大体思路 二、实现归并排序&#xff08;递归&#xff09;三、实现归并排序&#xff08;非递归&#xff09;3.1 实现思路&#xff1a;3.2 越界处理3.3 时间复杂度和空间复杂度 总结 一、归并排序思想 1.1 基本思想 归并排序&#xff08;M…

统一建模语言UML之类图(Class Diagram)(表示|关系|举例)

文章目录 1.UML2.Class Diagram2.1 类图的表示2.2 类间的关系2.2.1 关联2.2.2 聚合2.2.3 组合2.2.4 泛化&#xff08;继承&#xff09;2.2.5 实现&#xff08;接口实现&#xff09;2.2.6 依赖 2.3 类图的作用 参考&#xff1a;Class Diagram | Unified Modeling Language (UML)…

如何正确复盘带货直播间?

如何正确复盘带货直播间&#xff1f;其实&#xff0c;直播复盘可以分为四个关键步骤。首先&#xff0c;如果你的直播间没有人进来&#xff0c;核心问题往往是曝光率太低。观众不愿意点击进入你的直播间&#xff0c;那还谈什么卖货呢&#xff1f;平台也不会给予推荐流量。那么&a…

python绘制3D瀑布图

成品&#xff1a; 代码&#xff1a; import matplotlib.pyplot as plt import matplotlib.ticker as ticker from mpl_toolkits.mplot3d.art3d import Poly3DCollection import numpy as npdef line_3d(x, y, z, x_label_indexs):"""在y轴的每个点&#xff0c;…

了解可重入锁

1.基本概念&#xff1a; 可重入锁&#xff08;Reentrant Lock&#xff09;&#xff0c;又称递归锁&#xff08;Recursive Lock&#xff09;&#xff0c;是一种在多线程编程中使用的锁机制。它允许同一个线程在持有锁的情况下再次获取它&#xff0c;而不会引起死锁。这在处理递归…