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

【SpringMVC】深入解析基于Spring MVC与AJAX的用户登录全流程——参数校验、Session管理、前后端交互与安全实践

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


用户登录


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

  1. 如果不正确,前端进行用户告知
  2. 如果正确,跳转到首页。首页显示当前登录用户
  3. 后续再访问首页,可以获取到登录用户信息

在这里插入图片描述


1. 准备工作


把前端页面放在项目中

码云地址: JavaEE进阶课程资料包

在这里插入图片描述


2. 约定前后端交互接口


2.1 需求分析


对于后端开发人员而言,不涉及前端页面的展示,只需要提供两个功能

  1. 登录页面:通过账号和密码,校验输入的账号密码是否正确,并告知前端
  2. 首页:告知前端当前登录用户。如果当前已有用户登录,返回登录的账号,如果没有,返回空

2.2 接口定义


(1) 校验接口

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

请求参数

在这里插入图片描述


响应数据

Content-Type: text/html
    
响应内容:
    
true //账号密码验证成功
    
false //账号密码验证失败

(2) 查询登录用户接口

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

请求参数


响应数据

Content-Type: text/html
    
响应内容:
zhangsan

返回当前登录的用户


3. 服务器代码


(1) 校验接口


参数输入合法性校验

在这里插入图片描述


但是上面的校验,写法比较麻烦,我们可以使用 Spring 提供的一个工具类 StringUtils底下的 hasLength() 方法:

在这里插入图片描述


比起StringUtils.hasLength(),也可以使用StringUtils.hasText(),后者可以只输入判断空格时也为 false:

在这里插入图片描述


在这里插入图片描述


密码校验

注意

  • 比较字符串是否相等,需要用到 equals(),并且遵循 常量.equals(变量) 的比较规则;
  • a.equals(b)会因为 a 的值为 null 而报空指针异常,但是 b 的值为 null 不会报空指针异常;
  • 在当前逻辑中,虽然变量的值为 null ,会在第一轮校验中筛除这种情况;
  • 但是在以后写代码时,可能会文件写第一轮校验,常量.equals(变量)的写法更符合开发规范;
  • 因为我们还没有学关于校验的数据库操作,所以这里先指定账号密码:

在这里插入图片描述

对于上述方法,这两个 if 建议不要嵌套;


密码验证成功,把用户名存储在Session中

在这里插入图片描述


对该接口进行测试

我们重新运行程序,使用 Postman 进行测试:

在这里插入图片描述


在这里插入图片描述


(2) 查询登录用户接口


在刚刚的校验接口中,每次成功登录后,都会先把用户名存储在 Session 中;

在这个接口里,我们需要完成查询登录用户的功能,就需要使用刚刚存储好的 session 拿到用户信息;

在这里插入图片描述


在这里插入图片描述


对该接口进行测试

重新运行程序,使用 Postman 进行测试:


登录成功的情况:

在这里插入图片描述


在这里插入图片描述


登录失败的情况:需要先重新运行程序

在这里插入图片描述


在这里插入图片描述


4. 调整前端页面代码


(1) 调整登录页面 login.html


如果使用 vscode 编写代码,不同用于 idea ,前者需要手动保存

对于前端而言,当点击登录按钮时,需要把用户输入的信息传递到后端进行校验

对用户输入的信息传递到后端进行校验的功能,使用 ajax() 请求来完成:

在这里插入图片描述

校验的过程在后端完成,使用 ajax() 是把前端输入的数据传入后端,让后端进行校验;

  • 后端校验成功,则跳转到首页: index.html
  • 后端校验失败,则直接弹窗

在这里插入图片描述


我们在前端使用 succse 关键字,表示发送 HTTP 请求给后端,后端成功返回响应:

在这里插入图片描述


根据后端返回结果,再完成对应要执行的逻辑:

在这里插入图片描述


登录成功,跳转到首页:

在这里插入图片描述


前后端设置的请求参数的名字要一致:

在这里插入图片描述


一定要注意使用的参数的大小写,每个字母都要相同,否则后续前端传参,后端参数无法对应,就无法抓取登录

在这里插入图片描述


页面跳转的三种方式:

  1. window.location.href = “book_list.html”;
  2. window.location.assign(“book_list.html”);
  3. window.location.replace(“book_list.html”);

以上写法,通常把“window.”省略,比如 window.location.href = "book_list.html"; 写成 location.href = "book_list.html";


三者区别参考: location.assign()、location.href、location.replace(urI) 的不同


(2) 调整首页代码


首页代码比较简单,只显示当前登录用户即可。

当前登录用户需要从后端获取,并显示到前端

在这里插入图片描述


对象的属性定义没有先后顺序:

在这里插入图片描述


在这里插入图片描述


对比 login.htmlindex.html

login.html 通过 AJAX 发送 POST 请求 → 后端校验参数 → 返回布尔值 → 前端根据结果跳转或提示。

index.html通过 AJAX 发送 GET 请求 → 后端从 Session 读取用户名 → 动态更新页面。

它们调用 ajax() 请求的方式有所不同:

  • 前者通过点击事件,调用 login() 方法,在方法内部会执行 ajax()
  • 后者利用前端会从上往下加载代码,页面加载的过程中,执行到 ajax() 就会向后端发送请求;

在这里插入图片描述


为了避免下载 jquery 的网址失效,我们对两个页面都修改 src ,使用本地下载的 jquery

在这里插入图片描述


5. 运行测试


我们重新启动程序;


在登录前,我们先打开首页 http://127.0.0.1:8080/index.html,会发现没有登录人的信息:

在这里插入图片描述


打开登录页面:http://127.0.0.1:8080/login.html

在这里插入图片描述


在这里插入图片描述


输入正确密码,登录成功,记住:前后端请求参数名字一定要完全相同

在这里插入图片描述


6. 理解前后端交互流程


你的理解非常正确!下面我会详细解释整个交互流程,并澄清 AJAX 的功能,同时补充一些关键细节帮助你更全面地理解。

以下是登录过程的完整交互步骤:


(1) 用户在前端输入信息并点击登录

  • 前端页面login.html 中的输入框收集用户名和密码。
  • 触发事件:点击按钮调用 login() 函数,通过 AJAX 发送请求。

(2) 前端通过 AJAX 发送请求

  • AJAX 请求:前端将用户名和密码封装成键值对,发送到后端接口 /user/login

    data: {
      userName: $("#userName").val(), // 键名与后端参数名一致
      password: $("#password").val()
    }
    
  • 请求方式POST 方法,适合提交敏感数据(如密码)。


(3) 后端接收请求并校验

  • 参数绑定:Spring MVC 根据参数名 userNamepassword 自动绑定到方法的参数。

    public Boolean login(String userName, String password, HttpSession session) {
      // 校验逻辑
    }
    
  • 校验逻辑

    1. 检查用户名和密码非空。
    2. 验证是否为预设值(kunkunikun2.5)。
    3. 若校验通过,将用户名存入 Session。

(4) 后端返回响应

  • 返回结果true(成功)或 false(失败)。
  • Session 存储:成功时,后端通过 session.setAttribute("userName", userName) 存储登录状态。

(5) 前端处理响应

  • success 回调:根据后端返回的布尔值 result 执行不同逻辑:
    if (result) {
      // 跳转到首页
      location.href = "index.html";
    } else {
      // 提示密码错误
      alert("密码错误, 请重新输入");
    }
    

(6) 跳转至首页后获取登录信息

  • 首页请求index.html 加载时,通过另一个 AJAX 请求 /user/getLoginUser 获取登录用户名。
    $.ajax({
      type: "get",
      url: "/user/getLoginUser",
      success: function(userName) {
        $("#loginUser").text(userName);
      }
    });
    
  • Session 读取:后端从 Session 中取出用户名并返回,前端更新页面显示。

2. AJAX 的功能澄清

你对 AJAX 的理解基本正确,以下是关键点补充:

(1) 异步通信

  • 不刷新页面:AJAX 允许在不重新加载整个页面的情况下,与服务器交换数据并更新部分内容。
  • 用户体验:用户停留在当前页面,仅局部内容变化(如错误提示),适合登录这种需要即时反馈的场景。

(2) 请求与响应

  • 发送请求:通过 $.ajax() 配置请求方法(POST/GET)、URL、数据等。
  • 处理响应success 回调函数处理成功响应,error 处理失败(如网络错误)。

(3) 数据格式

  • 发送数据:可以是键值对(如 userName: "kunkun")或 JSON。
  • 接收数据:后端返回的 true/false 会被自动解析为布尔值,也可返回 JSON 对象。

3. 关键细节补充

(1) Session 的跨页面保持

  • Cookie 机制:当 Session 创建时,后端会自动生成一个 JSESSIONID 并存入 Cookie,浏览器后续请求会携带此 Cookie。
  • 身份识别:后端通过 JSESSIONID 找到对应的 Session,实现跨页面状态保持(如首页显示用户名)。

(2) 安全性注意事项

  • 密码传输:当前代码使用明文传输密码,实际项目中应使用 HTTPS 并加密(如哈希处理)。
  • Session 有效期:默认 Session 在用户关闭浏览器后失效,可手动设置超时时间。

(3) 后端逻辑优化

  • 错误提示细化:当前返回 true/false 只能提示密码错误,实际可返回 JSON 对象包含具体原因(如 {code: 400, message: "用户名不存在"})。
  • 参数校验增强:使用 Spring Validation 进行更专业的参数校验(如长度、格式)。

4. 总结

  • 你的理解完全正确:流程是 前端收集数据 → AJAX 发送 → 后端校验 → 返回结果 → 前端响应
  • AJAX 核心作用:实现异步通信,提升用户体验。
  • 扩展建议:学习 RESTful API 设计、HTTPS 安全、前端路由(如跳转逻辑优化)等。

通过这个流程,你可以清晰地看到数据是如何在前端和后端之间流动的,而 AJAX 是实现这一过程的关键桥梁。


7. 完整前后端代码


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()">
<!--  点击的时候触发 login()-->
  
  <script src="js/jquery-3.7.1.min.js"></script>
  <script>
    function login() {
      // ajax 的参数是一个对象, 使用 { } 包住表示一个对象, 对象的属性是键值对,不同属性用 "," 分割
      $.ajax({
        type : "post" ,
        url : "/user/login",
        data : {
          userName : $("#userName").val(),
          password : $("#password").val()
        },
        // 返回响应成功, 调用回调函数, 使用 result 接收后端返回参数
        success : function (result){
          if(result){
            // 返回 true , 密码正确 , 两种执行跳转页面逻辑
            location.href = "index.html";
          //  location.assign("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="js/jquery-3.7.1.min.js"></script>
    <script>
        $.ajax({
            type : "get" ,
            url : "/user/getLoginUser",

            success : function (userName) {
                $("#loginUser").text(userName);
            }
        })
    </script>
</body>

</html>

UserController

package com.example.springmvc_demo;

import ch.qos.logback.core.util.StringUtil;
import jakarta.servlet.http.HttpSession;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/user")
@RestController
public class UserController {
    @RequestMapping("/login")
    public Boolean login(String userName , String password , HttpSession session){
        // 参数输入合法性校验: 两个 StringUtils.hasText() 返回 ture, 才返回 true
        if(!StringUtils.hasText(userName) || !StringUtils.hasText(password)){
            return false;
        }

        // 校验用户名和密码是否正确
        // 还未学习数据库相关操作,暂且把账号和密码写死 userName: kunkun  password: Ikun2.5
        if(!"kunkun".equals(userName) || !"ikun2.5".equals(password)){
            return false;
        }

        // 密码验证成功,把用户名存储在Session中
        session.setAttribute("userName", userName);
        return true;
    }

    @RequestMapping("/getLoginUser")
    public String getLoginUser(HttpSession session){
        //从Session中获取用户登录信息
        String userName = (String)session.getAttribute("userName");

        //如果用户已经登录,则直接返回用户登录
        if(StringUtils.hasLength(userName)){
            return userName;
        }
        return "";
    }
}

在这里插入图片描述

在这里插入图片描述


http://www.kler.cn/a/591795.html

相关文章:

  • 【eNSP实战】旁挂二层组网—隧道转发
  • 【在数轴上找最优位置,使移动距离最短】
  • 在NET6项目中报错,未能在命名空间System.Data.SqlClient中找到类型名SqlCommand,解决办法
  • Linux系统移植篇(十一)Linux 内核启动流程
  • 33、class
  • [本周五题]Javascript面试常考题手撕场景UR缓存、new关键字、大数相加、最长递增子序列、高并发请求、大文件上传和WebWorks
  • 基于FPGA的3U机箱模拟量高速采样板ADI板卡,应用于轨道交通/电力储能等
  • 精准git动图拆解​
  • React第三十章(css原子化)
  • Android 15 获取网络切片信息的标准接口
  • vue3+elementPlus使用vuedraggable实现照片墙拖拽调整位置
  • 【设计模式】3W 学习法全面解析 7 大结构型模式:Java 实战 + 开源框架应用
  • 合React宝宝体质的自定义防抖hook
  • 安全地自动重新启动 Windows 资源管理器Bat脚本
  • css3有哪些新属性
  • 计算机网络-综合布线系统
  • trae和Spring Boot Java 项目 ruoyi框架
  • STM32---FreeRTOS软件定时器
  • 关于非线性优化小记
  • 半导体制造行业的现状 内检LIMS系统在半导体制造的应用