文章大纲
加载中...

待办清单项目8:注册时验证用户名是否可用

4/24/2025 212 阅读
待办清单项目8:注册时验证用户名是否可用

Ajax简介

请通过下面的网址了解一下Ajax技术

https://blog.csdn.net/ajiaming/article/details/146286953

修改前端注册页,添加Ajax

双击打开register.html文件

将代码改成下面这样:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册页面</title>
    <script>
        function checkUsername() {
            // 获取HTML文档中id为"username"的元素的值,即用户输入的用户名
            var username = document.getElementById("username").value;
            // 创建一个新的XMLHttpRequest对象,用于在浏览器和服务器之间进行异步通信
            var xhr = new XMLHttpRequest();
            // 设置xhr对象的状态改变时的回调函数
            // 该函数会在xhr对象的状态(readyState)改变时被调用
            xhr.onreadystatechange = function() {
                // 当readyState为4(请求已完成且响应已就绪)且status为200(HTTP状态码200表示请求成功)
                // 进行以下操作
                if (xhr.readyState === 4 && xhr.status === 200) {
                    // 获取服务器的响应文本,这里假设服务器返回的是一个字符串"true"或"false"
                    var result = xhr.responseText;
                    // 如果服务器返回的结果为"用户名已存在",表示用户名已存在
                    if (result === "用户名已存在") {
                        // 弹出一个警告框,提示用户“用户名已存在,请重新输入!”
                        alert("用户名已存在,请重新输入!");
                        // 清空用户名输入框的值
                        document.getElementById("username").value = "";
                        // 清空密码输入框的值,确保用户在重新输入用户名时,密码框也会被清空
                        document.getElementById("password").value = "";
                    }
                }
            };
            // 配置xhr对象以发送GET请求到指定的URL
            // 请求的URL是"/TodoList/user/checkUsername",并且附带了查询参数"username",值为用户输入的用户名
            xhr.open("GET", "/TodoList/user/checkUsername?username=" + username, true);
            // 发送请求
            xhr.send();
}

    </script>
</head>
<body>
    <h1>欢迎使用待办事项管理系统!</h1>
    <p>请填写注册信息:</p>
    <form action="/TodoList/user/regist" method="post">
        <label for="username">用户名:</label>
        <input type="text" id="username" name="username" required onblur="checkUsername()"><br><br>
        <label for="password">密码:</label>
        <input type="password" id="password" name="password" required><br><br>
        <input type="submit" value="注册">
        <input type="reset" value="重置">
        <a href="/TodoList/login.html">已有账号?点此登录</a>
    </form>
</body>
</html>

主要改动的地方是在表单的username输入框中添加了onblur事件,即失去焦点事件,当该输入框失去光标焦点后,会触发checkUsername这一段javascript代码,利用AJAX技术访问服务器检测用户输入的用户名是否被占用。

在服务器端添加相关代码

双击SysUserController这个文件,并在最后添加检测用户名是否存在的方法:

添加后,该文件的完整代码如下:

package com.youngshu.todolist.controller;
import com.youngshu.todolist.pojo.SysUser;
import com.youngshu.todolist.service.SysUserService;
import com.youngshu.todolist.service.impl.SysUserServiceImpl;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import com.youngshu.todolist.utils.MD5Utils;

// 该类处理用户相关的请求
@WebServlet("/user/*")
public class SysUserController extends BaseController{
    private SysUserService sysUserService = new SysUserServiceImpl();
    // 注册用户
    protected void regist(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1. 获取请求参数
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        // 2. 调用服务层方法,完成用户注册
        SysUser sysUser = new SysUser(null, username, password);
        int rows = sysUserService.regist(sysUser);
        // 3. 根据注册结果,返回不同的响应
        if (rows > 0) {
            // 注册成功,跳转到注册成功页面
            resp.sendRedirect("/TodoList/registerSuccess.html");
        } else {
            // 注册失败,跳转到注册失败页面
            resp.sendRedirect("/TodoList/registerFail.html");
        }
    }
    // 登录用户
    protected void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1 接收用户名和密码
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        //2 调用服务层方法,根据用户名查询用户信息
        SysUser loginUser = sysUserService.findByUsername(username);
        if(null == loginUser){
            // 跳转到登录失败页面
            resp.sendRedirect("/TodoList/loginError.html");
        }else if(! MD5Utils.md5encode(password).equals(loginUser.getUser_pwd())){
            //3 判断密码是否匹配
            // 跳转到登录失败页面
            resp.sendRedirect("/TodoList/loginError.html");
        }else{
            //4.1 把登录用户设置到session会话里面进行保存
            req.getSession().setAttribute("loginUser", loginUser);
            //4. 跳转到待办事项页面
            resp.sendRedirect("/TodoList/todoList.html");
        }
    }
    // 验证用户名是否存在
    protected void checkUsername(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1. 获取请求参数
        String username = req.getParameter("username");
        // 2. 调用服务层方法,根据用户名查询用户信息
        SysUser sysUser = sysUserService.findByUsername(username);
        // 3. 根据查询结果,返回不同的响应
        if (null == sysUser) {
            // 用户名不存在
            resp.getWriter().write("用户名不存在");
        } else {
            // 用户名已存在
            resp.getWriter().write("用户名已存在");
        }
    }
}

测试

启动服务器,访问http://localhost:8080/TodoList/register.html

输入一个已经存在的用户名,然后点一下输入框以外的任何位置,可以看到浏览器弹窗提示用户名已经存在

若输入一个未注册过的账户,则不会触发相应的提示

修改前后端通讯格式

为了使前后端通讯格式更加规范,将采用JSON格式对通讯信息进行包装

首先,请通过下面的网址简单了解一下JSON

https://blog.csdn.net/sunyctf/article/details/129291675

然后,在com包上单击鼠标右键,新建软件包

取名为common

common包上新建Java类,取名为Result

代码如下:

package com.youngshu.todolist.common;

// 定义一个泛型类 Result<T>,用于封装返回给客户端的结果数据
public class Result<T> {
    // 定义私有变量 code,用于存储返回的状态码
    private Integer code;
    // 定义私有变量 message,用于存储返回的消息描述
    private String message;
    // 定义私有泛型变量 data,用于存储返回的具体数据
    private T data;
    // 定义无参构造函数
    public Result() {}
    // 返回数据,初始化 Result 对象的 data 字段
    // 该方法是 protected 的,意味着它只能在本类及其子类中被调用
    protected static <T> Result<T> build(T data) {
        // 创建一个新的 Result 对象
        Result<T> result = new Result<T>();
        // 如果传入的数据不为空,则设置 result 的 data 字段为传入的数据
        if (data != null)
            result.setData(data);
        // 返回初始化好的 Result 对象
        return result;
    }
    // 返回数据,初始化 Result 对象的 data、code 和 message 字段
    // 该方法是 public 的,可以在任何地方被调用
    public static <T> Result<T> build(T body, Integer code, String message) {
        // 调用 build(T data) 方法初始化 Result 对象的 data 字段
        Result<T> result = build(body);
        // 设置 result 的 code 字段为传入的状态码
        result.setCode(code);
        // 设置 result 的 message 字段为传入的消息描述
        result.setMessage(message);
        // 返回初始化好的 Result 对象
        return result;
    }
    // 返回数据,初始化 Result 对象的 data、code 和 message 字段
    // 该方法使用 ResultCodeEnum 枚举类型来设置 code 和 message
    public static <T> Result<T> build(T body, ResultCodeEnum resultCodeEnum) {
        // 调用 build(T data) 方法初始化 Result 对象的 data 字段
        Result<T> result = build(body);
        // 设置 result 的 code 字段为 ResultCodeEnum 枚举类型中的状态码
        result.setCode(resultCodeEnum.getCode());
        // 设置 result 的 message 字段为 ResultCodeEnum 枚举类型中的消息描述
        result.setMessage(resultCodeEnum.getMessage());
        // 返回初始化好的 Result 对象
        return result;
    }
    // 成功返回数据,初始化 Result 对象的 data 字段和 code 字段
    public static<T> Result<T> ok(T data){
        Result<T> result = build(data);
        return build(data, ResultCodeEnum.SUCCESS);
    }
    // 失败返回数据,初始化 Result 对象的 message 字段和 code 字段
    public Result<T> message(String msg){
        this.setMessage(msg);
        return this;
    }
    // 失败返回数据,初始化 Result 对象的 message 字段和 code 字段
    public Result<T> code(Integer code){
        this.setCode(code);
        return this;
    }
    // 获取 code 字段的值
    public Integer getCode() {
        return code;
    }
    // 设置 code 字段的值
    public void setCode(Integer code) {
        this.code = code;
    }
    // 获取 message 字段的值
    public String getMessage() {
        return message;
    }
    // 设置 message 字段的值
    public void setMessage(String message) {
        this.message = message;
    }
    // 获取 data 字段的值
    public T getData() {
        return data;
    }
    // 设置 data 字段的值
    public void setData(T data) {
        this.data = data;
    }
}

继续在common包上单击右键,选择新建Java类,取名为ResultCodeEnum,然后点一下枚举,最后敲一下回车键

在该文件中粘贴下面的代码:

package com.youngshu.todolist.common;

// 定义一个枚举类型 ResultCodeEnum,用于表示操作结果的不同状态码及其对应的描述信息。
public enum ResultCodeEnum {
    // 表示操作成功,状态码为 200,描述信息为 "success"。
    SUCCESS(200, "success"),
    // 表示用户名错误,状态码为 501,描述信息为 "usernameError"。
    USERNAEM_ERROR(501, "usernameError"), // 注意:这里拼写错误,应该是 USERNAME_ERROR
    // 表示密码错误,状态码为 503,描述信息为 "passwordError"。
    PASSWORD_ERROR(503, "passwordError"),
    // 表示用户未登录,状态码为 504,描述信息为 "notlogin"。
    NOTLOGIN(504, "notlogin"),
    // 表示用户名已被使用,状态码为 505,描述信息为 "usernameUsed"。
    USERNAME_USED(505, "usernameUsed");

    // 私有成员变量 code,用于存储状态码。
    private Integer code;
    // 私有成员变量 message,用于存储描述信息。
    private String message;
    // 私有构造方法 ResultCodeEnum,用于初始化枚举实例的状态码和描述信息。
    private ResultCodeEnum(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
    // 公共方法 getCode,用于获取枚举实例的状态码。
    public Integer getCode() {
        return code;
    }
    // 公共方法 getMessage,用于获取枚举实例的描述信息。
    public String getMessage() {
        return message;
    }
}

双击SysUserController文件,把检查用户名的代码改成下面这样子:

改完之后,该文件的完整代码如下:

package com.youngshu.todolist.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.youngshu.todolist.common.Result;
import com.youngshu.todolist.common.ResultCodeEnum;
import com.youngshu.todolist.pojo.SysUser;
import com.youngshu.todolist.service.SysUserService;
import com.youngshu.todolist.service.impl.SysUserServiceImpl;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import com.youngshu.todolist.utils.MD5Utils;

// 该类处理用户相关的请求
@WebServlet("/user/*")
public class SysUserController extends BaseController{
    private SysUserService sysUserService = new SysUserServiceImpl();
    // 注册用户
    protected void regist(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1. 获取请求参数
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        // 2. 调用服务层方法,完成用户注册
        SysUser sysUser = new SysUser(null, username, password);
        int rows = sysUserService.regist(sysUser);
        // 3. 根据注册结果,返回不同的响应
        if (rows > 0) {
            // 注册成功,跳转到注册成功页面
            resp.sendRedirect("/TodoList/registerSuccess.html");
        } else {
            // 注册失败,跳转到注册失败页面
            resp.sendRedirect("/TodoList/registerFail.html");
        }
    }
    // 登录用户
    protected void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1 接收用户名和密码
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        //2 调用服务层方法,根据用户名查询用户信息
        SysUser loginUser = sysUserService.findByUsername(username);
        if(null == loginUser){
            // 跳转到登录失败页面
            resp.sendRedirect("/TodoList/loginError.html");
        }else if(! MD5Utils.md5encode(password).equals(loginUser.getUser_pwd())){
            //3 判断密码是否匹配
            // 跳转到登录失败页面
            resp.sendRedirect("/TodoList/loginError.html");
        }else{
            //4.1 把登录用户设置到session会话里面进行保存
            req.getSession().setAttribute("loginUser", loginUser);
            //4. 跳转到待办事项页面
            resp.sendRedirect("/TodoList/todoList.html");
        }
    }
    // 验证用户名是否存在
    protected void checkUsername(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1. 获取请求参数
        String username = req.getParameter("username");
        // 2. 调用服务层方法,根据用户名查询用户信息
        SysUser sysUser = sysUserService.findByUsername(username);
        // 3.设置响应信息
        Result result =Result.ok( null);
        if(null != sysUser){
            result= Result.build( null, ResultCodeEnum.USERNAME_USED);
        }
        // 将result对象转换为JSON串响应给客户端
        // ObjectMapper
        ObjectMapper objectMapper =new ObjectMapper();
        String info = objectMapper.writeValueAsString(result);
        // 告诉客户端响应给你的是一个JSON串
        resp.setContentType("application/json;charset=UTF-8");
        resp.getWriter().write(info);
    }
}

复制jackson相关的三个库文件,在lib目录上粘贴

再次修改register.html,把代码改成下面这样:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册页面</title>
    <script>
        function checkUsername() {
            // 获取HTML文档中id为"username"的元素的值,即用户输入的用户名
            var username = document.getElementById("username").value;
            // 创建一个新的XMLHttpRequest对象,用于在浏览器和服务器之间进行异步通信
            var xhr = new XMLHttpRequest();
            // 设置xhr对象的状态改变时的回调函数
            // 该函数会在xhr对象的状态(readyState)改变时被调用
            xhr.onreadystatechange = function() {
                // 当readyState为4(请求已完成且响应已就绪)且status为200(HTTP状态码200表示请求成功)
                // 进行以下操作
                if (xhr.readyState === 4 && xhr.status === 200) {
                    // 解析服务器返回的JSON数据
                    var result = JSON.parse(xhr.responseText);
                    //打印服务器返回的JSON数据
                    console.log(result);
                }
            };
            // 配置xhr对象以发送GET请求到指定的URL
            // 请求的URL是"/TodoList/user/checkUsername",并且附带了查询参数"username",值为用户输入的用户名
            xhr.open("GET", "/TodoList/user/checkUsername?username=" + username, true);
            // 发送请求
            xhr.send();
}

    </script>
</head>
<body>
    <h1>欢迎使用待办事项管理系统!</h1>
    <p>请填写注册信息:</p>
    <form action="/TodoList/user/regist" method="post">
        <label for="username">用户名:</label>
        <input type="text" id="username" name="username" required onblur="checkUsername()"><br><br>
        <label for="password">密码:</label>
        <input type="password" id="password" name="password" required><br><br>
        <input type="submit" value="注册">
        <input type="reset" value="重置">
        <a href="/TodoList/login.html">已有账号?点此登录</a>
    </form>
</body>
</html>

再次启动服务器,访问http://localhost:8080/TodoList/register.html ,然后输入用户名后,点一下其他位置,然后按一下键盘的F12调出调试界面,点一下网络,可以看到触发了网络请求,点一下checkUsername这个网络请求,再点一下响应,可以看到服务器返回过来的json数据。

再一次修改register.html,把代码改成下面这样。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册页面</title>
    <script>
        function checkUsername() {
            // 获取HTML文档中id为"username"的元素的值,即用户输入的用户名
            var username = document.getElementById("username").value;
            // 获取HTML文档中id为"usernameMsg"的元素,用于显示错误信息
            var usernameMsg = document.getElementById("usernameMsg");
            // 创建一个新的XMLHttpRequest对象,用于在浏览器和服务器之间进行异步通信
            var xhr = new XMLHttpRequest();
            // 设置xhr对象的状态改变时的回调函数
            // 该函数会在xhr对象的状态(readyState)改变时被调用
            xhr.onreadystatechange = function() {
                // 当readyState为4(请求已完成且响应已就绪)且status为200(HTTP状态码200表示请求成功)
                // 进行以下操作
                if (xhr.readyState === 4 && xhr.status === 200) {
                    // 解析服务器返回的JSON数据
                    var result = JSON.parse(xhr.responseText);
                    if (result.code == 200) {
                        // 用户名可用,将usernameMsg元素的文本内容设置为"用户名可用"
                        usernameMsg.innerText = "用户名可用";
                    } else {
                        // 用户名已存在,将usernameMsg元素的文本内容设置为"用户名已存在"
                        usernameMsg.innerText = "用户名已存在";
                    }
                }
            };
            // 配置xhr对象以发送GET请求到指定的URL
            // 请求的URL是"/TodoList/user/checkUsername",并且附带了查询参数"username",值为用户输入的用户名
            xhr.open("GET", "/TodoList/user/checkUsername?username=" + username, true);
            // 发送请求
            xhr.send();
}
    </script>
</head>
<body>
    <h1>欢迎使用待办事项管理系统!</h1>
    <p>请填写注册信息:</p>
    <form action="/TodoList/user/regist" method="post">
        <label for="username">用户名:</label>
        <input type="text" id="username" name="username" required onblur="checkUsername()">
        <span id="usernameMsg"></span><br><br>
        <label for="password">密码:</label>
        <input type="password" id="password" name="password" required><br><br>
        <input type="submit" value="注册">
        <input type="reset" value="重置">
        <a href="/TodoList/login.html">已有账号?点此登录</a>
    </form>
</body>
</html>

再一次启动服务器,访问注册页,如果用户输入的用户名已经存在,会在旁边给出提示用户名已存在,若输入的用户名不存在,则会提示用户名可用


评论 (0)

暂无评论,来发表第一条评论吧!