待办清单项目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)
暂无评论,来发表第一条评论吧!