Spring MVC小案例(1)

一,加法计算器

计算器的前端静态页面代码:

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>
     <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>
java 复制代码
@RestController
public class CalcController {
    @RequestMapping("/calc/sum")
    public String sum(@RequestParam Integer num1, @RequestParam Integer num2){
        int sum=num1+num2;
        return "相加的结果为:"+sum;
    }
}

**代码解释以及注意事项:**前端代码中的name=num1以及name=num2就跟后端代码中的num1和num2相对应,也就是说后端是去收到前端传来的名为num1和num2的参数进行相加返回结果的,如果你后端不想叫这个名字的话也可以通过@RequestParam注解来进行后端代码中的参数的改名,我这里没有写,我这个是用到了这个注解另一个特性,就是参数不能为空,然后前端代码的开头是将用户输入的获取到并且传给calc/sum这个方法,然后就是完成了前后端的一个交互了

那可能会有一个疑问说为什么会跳转到另一个网页,这个是那个机制或者代码实现的呢:关键就在前端代码body中开头的一行,这是HTML表单的默认提交行为,具体的行为如下:

当你点击「点击相加」按钮时,浏览器默认会做三件事:

  1. 收集表单中的 num1、num2 两个参数。

  2. 向 action 指定的 /calc/sum 接口发送 POST 请求。

  3. 用服务器返回的响应替换当前标签页显示的内容。

所以,你看到的效果就是:原来的计算器页面不见了,浏览器地址变成接口地址,页面显示计算结果。

二,用户登录

我们要实现一个页面,当用户输入用户和密码错误的时候,会有个错误的弹窗提示,当正确的时候,我们会跳转到一个显示着登陆人:(正确的登录名字)这样的页面

那我们首先需要第一步就是创建一个登录的接口,根据传入的名字以及密码来判断是正确还是错误来进行返回,这里我们需要注意的是由于我们需要返回的页面要显示名字,但是我们http是无记忆的,所以我们需要用到session来保存正确的用户名

后端登录接口和获取session代码

java 复制代码
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 Userlogin {
    @RequestMapping("/login")
    public Boolean login(String userName, String password, HttpSession session){
        //先验证数据是否有效
        if (!StringUtils.hasLength(userName) || !StringUtils.hasLength(password)){
            return false;
        }
        //判断数据是否匹配,因为我们还没有学习到数据库跟这个结合的内容,所以我们先使用固定的用户名以及密码
        if ("admin".equals(userName)&&"admin".equals(password)){
            //因为http没有记忆,所以得用上session
            session.setAttribute("userName",userName);
            return true;
        }
        return false;
    }
    @RequestMapping("/getUsername")
    public String getUsername(HttpSession session){
        String userName =(String) session.getAttribute("userName");
        return userName==null?"账号或密码错误":userName;
    }

}

接下来是对于接口的测试

第二步就是开始编辑我们的页面,在这里我们使用ajax的方式来编写,在写之前,我们需要引入一个jQuery,这样可以让我们的代码写起来更加的方便,我们通过下面这个链接进去右键下载到桌面,然后将jQuery引入进来

https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js

ajax

ajax的介绍:

简单来说,AJAX 是一种让浏览器能够在不重新加载整个网页的情况下,向后端发送请求并接收响应的技术(这样如果我们在登录一个网站的时候,如果输入错误信息,就不会将网页完全的重新加载一遍,导致账号密码需要完全重新输入,而是可能直接跳出一个提示之类的)

ajax的特点:

异步通信:发送请求后,页面不必一直等待响应,可以继续执行其他操作

局部更新:只更新网页中需要变化的部分,不必重新加载整个页面

减少不必要的数据传输:可以只请求当前需要的数据,而不必重新获取整个页面

前后端交互:可以向后端接口发送请求,接收 JSON、文本等格式的数据

ajax的基础语法:

复制代码
$(选择器).操作();

常见写法举个例子:q

java 复制代码
$.ajax({
    url: "/user",
    type: "GET",
    data: { id: 1 },
    dataType: "json",

    success: function(res) {
        console.log(res);
    },

    error: function() {
        console.log("请求失败");
    }
});

前端用户登录的HTML代码(登录页面)

解析一下这里的代码:

我们通过表单填写的用户名以及密码,在我们的ajax中进行获取,就是data那一部分,前面是请求方式以及要交给的哪一个方法,就是前面的接口的路径(这里也体现了ajax的一个异步的特点,就是不是自己第一时间就返回响应,而是等待我们接口的返回再进行操作),接下来就是成功了(也就是正常返回了http响应,而不是说账号密码正确),这里的result就是前面传入的方法中返回的参数,我们的参数中不是定义了正确返回true,错误返回false,如果是true,就进行跳转其中location.href就是跳转的一种方式,错误就进行弹窗(alter)

html 复制代码
<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.min.js"></script>
<script>
    function login() {
    $.ajax({
      type:"post",
      url:"/user/login",
      data:{
        userName:$("#userName").val(),
        password:$("#password").val()
      },
      success:function(result){
        if(result){
          //账号密码正确就跳转
          location.href="/index.html";
        }else{
          //错误的话就进行弹窗
          alert("账号密码错误");
        }
      }
    })
    }
  </script>
</body>
</html>

正确的话就进行跳转页面,但是这个页面的代码我们还没有写

前端显示用户名的HTML代码(跳转页面)

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.min.js"></script>
<script>
    $.ajax({
        type:"get",
        url:"user/getUsername",
        success:function(Username){
            $("#loginUser").text(Username)
        }
    })
</script>
</body>
</html>

写到这里我讲一下我之前的一个疑惑(关于session是怎么存储的):

我们结合我的代码来理解就是当我们输入错误的时候,我们session中就不会保存name这个属性,当我们正确的时候才会保存,我们后端返回的页面跟session信息关系密切,我们会根据客户端所带的cookie中的sessionid来确认,如果是错误的话,我们后端拿到的session里面就压根没有存任何东西,所以返回的用户名也就是啥都没有的,但是正确时候拿到的sessionid得到的session就是有正确的name的,那我们会想:这个session的使用寿命或者范围是怎么来规定的呢,哪种情况会创建新的session

场景 通常会发生什么
同一浏览器连续发送多个请求 找到同一个 Session
同一浏览器先登录失败,再登录成功 原 Session 仍有效时,通常复用原 Session
同一个 admin 换另一台电脑登录 通常创建或使用另一个 Session
Session 超时或被销毁后再次访问 通常创建新的 Session
两个人共用同一个浏览器和有效会话 可能访问同一个 Session,不能仅凭 Session 区分实际操作者

session是否会重新创建就是上面这张表所说的,所以我们写的代码的情况,session并不会更新,除非你等很长时间或者换一个浏览器,要不短时间在同一个浏览器中session是可能出现问题的,也就是说这个session并不能真正的确认用户是不是正确的,因为错误的话是不写,正确的话是写进去,也就代表了我们写完正确的之后,再写一个错误的,session里面还是存的正确时候的name,但是好在我们弹窗的判断是直接根据输入的是否正确,而不是看session,所以不会出现我上一次是正确的然后跳转,下一次我是错误的也跳转这种情况,但是session不做其他处理的话是"错误的"

三,留言板

我们需要创建一个留言板,里面包含从哪里来,对谁说以及说什么

首先我们先创建后端接口,先是定义一个对象,里面包含我们要传输的数据,并且写出get和set方法,这些get和set方法每一次都写会很麻烦,我们可以通过引入一个依赖来简化我们的代码书写

lombok

这个方法可以帮我们简化一些东西,比如get,set方法,重写等方法,那如何进行引入呢

方法一:在创建spring项目的时候勾选上lombok选项

方法二:下载插件:EditStarters

方法三:在pom文件里添加lombok相关依赖代码

这里我们选择在第三种方式来添加

XML 复制代码
<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>

怎么用:

(直接引入后加注解就可以了)

注解 作用
@Getter 自动生成 Getter 方法,用于获取属性值
@Setter 自动生成 Setter 方法,用于修改属性值
@ToString 自动生成 toString() 方法,方便打印对象信息
@EqualsAndHashCode 自动生成 equals() 和 hashCode() 方法
@Data 综合注解,包含 Getter、Setter、ToString、EqualsAndHashCode 和 RequiredArgsConstructor 等功能

后端留言以及拿取留言代码

我们为了存储数据,一般是内存存储和外存(硬盘),这里我们选择内存,我们选择的是将数据存在list当中

java 复制代码
package com.example.demo;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/MessageController")
public class MessageController {
    //我们将数据存放在内存中,也就是先写一个list存在里面
    List<MessageInfo>list=new ArrayList<>();
    //发布的接口
    @RequestMapping("/publish")
    public Boolean publish(@RequestBody  MessageInfo messageInfo ){
        if (!StringUtils.hasLength(messageInfo.getFrom())||
                !StringUtils.hasLength(messageInfo.getTo())||
                !StringUtils.hasLength(messageInfo.getMes())){
            return false;
        }else {
            list.add(messageInfo);
            return true;
        }
    }
    //加载数据的接口
    @RequestMapping("/getmes")
    public List<MessageInfo> getmes(){
        return list;
    }
}

@RequestBody用来告诉 Spring MVC:从 HTTP 请求体中读取数据,并尝试将其转换成 Java 对象

java 复制代码
package com.example.demo;
import lombok.Data;
@Data
public class MessageInfo {
    private String from;
    private String to;
    private String mes;
}

前端留言板代码

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: 400px;
            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.min.js"></script>
<script>
        getmes();
        function getmes(){
            $.ajax({
                type:"get",
                url:"MessageController/getmes",
                success:function(list){
                    //成功就将列表遍历完写在下面
                    for(let messageInfo of list){
                        //2. 构造节点
                        let divE = "<div>"+messageInfo.from +"对" + messageInfo.to + "说:" + messageInfo.mes+"</div>";
                        //3. 把节点添加到页面上
                        $(".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:"MessageController/publish",
                contentType:"application/json",
                data:JSON.stringify({
                    from:from,
                    to:to,
                    mes: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("发表留言失败");
                    }
                }
            })
        }

    </script>
</body>

</html>

代码中这里前面的from,to,mes是我们后端的数据的命名,后面的那个是我们前端表格中获取的数据的名称

这里的list是我们自己定义的一个变量名,接收ajax成功返回的数据,那么这个返回的也就是由所有留言组成的一个数组,每一个元素都是一整条的留言,下面这个messageInfo也是我们自己定义的,表示拿到的是一整条的留言,再下一行中就是拿到我们每一行留言中的每一个数据了,from,to,mes不是随便定义的,这个是看我们后端怎么命名的

相关推荐
陈随易1 小时前
从今天起,你只需要一个浏览器之Ego lite
前端·后端·程序员
西凉的悲伤1 小时前
Spring Boot 条件装配注解详解
java·springboot·1024程序员节·条件装配
木井巳1 小时前
【动态规划: 路径问题】不同路径
java·算法·leetcode·动态规划
打工仔折腾 AI2 小时前
AI Agent 工程化实战(二):5 分钟跑通 Deep Agent 并逐层拆解底层链路
java·数据库·人工智能·后端·python·langchain·ai agent 实战
秋名RG2 小时前
(二)存储、CPU 与指令执行——程序为什么快,又为什么慢
java·开发语言
BeiGuTing_code2 小时前
Java泛型与Object
java·开发语言
惊讶的猫2 小时前
Tika文档解析
java
HEJOO92 小时前
Java 类加载过程详解:从加载到初始化的完整链路
java·开发语言·firefox
科学熊2 小时前
Java 分布式理论与高并发编程
java·开发语言·分布式