Jquery+Servlet+JDBC实现登录注册功能

前端部分

HTML+CSS部分

引入JQuery包和JQuery.cookie包,前者封装了DOM操作的一些方法,后者封装了对cookie的操作

我们使用cookie主要是为了做登录后页面的跳转时,能存下来这个用户是谁,这样后面可以对单一用户进行操作,比如根据用户id查询等

代码

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户登录</title>
<link rel="stylesheet" href="css/login.css">
<script src="js/dependency/jquery-3.7.1.min.js" defer></script>
<script src="js/dependency/jquery.cookie.js" defer></script>
<script src="js/login.js" defer></script>
</head>
<body>
	<div class="login">
		<div class="inputArea">
			<ul>
				<li>用户名:<input type="text" class="username" id="userName"></input></li>
				<li>密码:<input type="password" class="password" id="passWord"></input></li>
			</ul>
		</div>
		<div class="clickArea">
			<input type="button" value="登录" id="loginBtn" /> 
			<input type="button" value="注册" id="registerBtn" />
		</div>
	</div>
	<div class="register">
		<div class="registerInput">
			<ul>
				<li>用户名:<input type="text" class="username" id="regiestUserName"></input></li>
				<li>密码:<input type="password" class="password" id="resistPassWord"></input></li>
				<li>确认密码:<input type="password" class="password" id="confirmPassWord"></input></li>
			</ul>
		</div>
		<div class="registerArea">
			<input type="button" value="注册" id="doRegister" /> 
			<input type="button" value="取消" id="cancleRegister" />
		</div>
	</div>
</body>
</html>
body{
	margin:0;
	padding:0;
}
/*登录样式*/
.login{
	height: 30vh;
	width: 20vw;
	/*background: red;*/
	margin-top: 10vh;
	margin-left: auto;
	margin-right: auto;
	border: 3px solid red;
	border-radius: 30px;

}
.login .inputArea ul{

	display: flex;
	flex-direction: column;
	margin: 12vh 0 0 0;
	justify-content: center;
	align-items: center;
	
}

.inputArea ul li{
	margin: 0 auto;
	display: flex;
	line-style-type:none;
}
.clickArea{
	display: flex;
	margin: 30px auto;
	justify-content: center;
    align-items: center;
}

/*注册弹框样式*/
.register{
	height: 30vh;
	width: 20vw;
	/*background: red;*/
	margin: 50px auto;
	border: 3px solid blue;
	border-radius: 30px;
	
	display:none;
}
.registerInput ul{
	display: flex;
	flex-direction: column;
	margin: 12vh 0 0 0;
	justify-content: center;
	align-items: center;
}

.registerInput ul li{
	margin: 0 auto;
	display: flex;
	line-style-type:none;
}
.registerArea{
	display: flex;
	margin: 30px auto;
	justify-content: center;
    align-items: center;
}
代码要点
  1. 这里使用的是无序列表,但是实际使用发现很难对齐文字和输入框,就像这样
    在这里插入图片描述

推荐修改为两个无边框表格,会好很多

  1. 注册部分(蓝色边框部分),要设置为display:none,用户点击注册按钮的时候弹出
  2. 弹性盒子模型,我们希望输入框竖着排列,按钮横着排列,注意设置

JS代码部分

代码

let checkInputAndTrim = function(param,value){
	if(!value||value==""){
		alert(param + "为空!");
		return -1;
	}
	return value.trim();
}

// 单击登录按钮的单击事件触发
$("#loginBtn").on("click", function(){
	// trim + 校验用户输入非空
	let username = checkInputAndTrim("用户名", $("#userName").val());
	let password = checkInputAndTrim("密码", $("#passWord").val());

	if(username!=-1 || password!=-1){
		$.ajax({
	        url: "login",
	        type: "post",
	        data:{username, password},
	        success: function (value) {
	        	console.log(value);
				let code = value.code;
				console.log(code);
				if(code!=0){
					let msg = value.msg;
					alert(msg);
				}else{
					alert("登录成功!");
					let userId = value.data[0].id;
					// 获取当前时间
					let expirationTime = new Date();   
					// 在当前时间的基础上增加2小时
					expirationTime.setTime(expirationTime.getTime() + 120 * 60 * 1000);
					$.cookie("userId",userId,{expires: expirationTime, path: "/CommodityManage" });
					// 跳转其他页面
					self.location.href='CommodityManage.html';
				}
	        },
	        error: function () {
	        	alert("登录失败!");
	        }
	    })
	}
	
})

// 单击注册按钮的单击事件触发
$("#registerBtn").on("click", function(){
	
	$(".register").css("display","block");
	
})

// 确认注册
$("#doRegister").on("click", function(){
	
	// trim + 校验用户输入非空
	let username = checkInputAndTrim("用户名", $("#regiestUserName").val());
	let password1 = checkInputAndTrim("密码", $("#resistPassWord").val());
	let password2 = checkInputAndTrim("确认密码", $("#confirmPassWord").val());
	
	if(username!=-1||password1!=-1||password2!=-1){
		if(password1!=password2){
			alert("两次输入的密码不一致!");
			return;
		}
		$.ajax({
	        url: "register",
	        type: "post",
	        data:{username, password1,password2},
	        success: function (value) {
	        	console.log(value);
				let code = value.code;
				console.log(code);
				if(code!=0){
					let msg = value.msg;
					alert(msg);
				}else{
					alert("注册成功!");
					// 清空输入的数值
					$(".registerInput ul li input").val("");
					// 隐藏注册框
					$(".register").css("display","none");
				}
	        },
	        error: function () {
	        	alert("注册失败!");
	        }
	    })
	}

})
// 取消注册
$("#cancleRegister").on("click", function(){
	// 清空输入的数值
	$(".registerInput ul li input").val("");
	// 隐藏注册框
	$(".register").css("display","none");
});

代码要点
  1. 经常需要用到的代码块可以用函数单独拿出来,代码复用可以使代码的逻辑更清晰
// 校验非空+去除用户输入的字符串的前后空格,重复使用,所以提出来
let checkInputAndTrim = function(param,value){
	if(!value||value==""){
		alert(param + "为空!");
		return -1;
	}
	return value.trim();
}
  1. 这里的cookie是后端传给前端的用户id
    cookie最好设置过期时间,并设置保存路径,否则可能会导致无关页面修改/删除本页面的cookie
expirationTime.setTime(expirationTime.getTime() + 120 * 60 * 1000);
$.cookie("userId",userId,{expires: expirationTime, path: "/CommodityManage" });

后端部分

Java代码

这里关于JDBC的部分是经过封装的,不过是无侵入的封装,不改变原有的JDBC,所以具体使用起来没什么特别大的差异,读者可以原地修改为JDBC

登录Servlet部分

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.qcby.db.MysqlUtil;

public class LoginServlet extends HttpServlet {

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		req.setCharacterEncoding("UTF-8");
		resp.setCharacterEncoding("UTF-8");
		String userName = req.getParameter("username");
		String passWord = req.getParameter("password");
		String[] queryParams = { "id", "user_name", "password" };
		String loginSql = "select id, user_name, password from t_entity_user where user_name= \"" + userName + "\"";

		ArrayList<String[]> userList = MysqlUtil.showUtil(loginSql, queryParams);
		for (String[] user : userList) {
			System.out.println("=============查询用户的结果:" + Arrays.toString(user));
		}
		resp.setContentType("application/json;charset=UTF-8");
		PrintWriter pw = resp.getWriter();

		if (userList.size() == 0) {
			pw.write(MysqlUtil.listToFreedomJson("-1", "未找到用户名为" + userName + "的用户!", null, null));
			return;
		} else if (!passWord.equals(userList.get(0)[2])) {
			pw.write(MysqlUtil.listToFreedomJson("-2", "密码错误", null, null));
			return;
		}
		ArrayList<String[]> resultList = new ArrayList<>();
		resultList.add(new String[] { userList.get(0)[0] });
		String[] resultParams = { "id" };
		pw.write(MysqlUtil.listToFreedomJson("0", "success", resultList, resultParams));
	}
}

如果不使用@WebServlet注解的话,就需要在WEB-INF文件夹下的web.xml当中注册Servlet,并配置访问路径
在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
	id="WebApp_ID" version="3.1" metadata-complete="true">
	<display-name>MyFirstServlet</display-name>
	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
		<welcome-file>index.htm</welcome-file>
		<welcome-file>index.jsp</welcome-file>
		<welcome-file>default.html</welcome-file>
		<welcome-file>default.htm</welcome-file>
		<welcome-file>default.jsp</welcome-file>
	</welcome-file-list>
	<!--登录 -->
	<servlet>
		<servlet-name>login</servlet-name>
		<servlet-class>com.qcby.servlet.LoginServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>login</servlet-name>
		<url-pattern>/login</url-pattern>
	</servlet-mapping>
	
	<!--注册 -->
	<servlet>
		<servlet-name>register</servlet-name>
		<servlet-class>com.qcby.servlet.RegisterServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>register</servlet-name>
		<url-pattern>/register</url-pattern>
	</servlet-mapping>
</web-app>
登录要点
  1. 首先校验是否存在用户名对应的用户,然后再判断是否密码错误
  2. 自己封装的错误信息尽量完整
  3. String用equals判断相等时,应该将一定不为null的放在equals的前面,防止出现空指针异常

在这里,用户输入的password经过了前端的非空检验,所以一定不是null,而从数据库中查出来的密码,可能为null

if (!passWord.equals(userList.get(0)[2])) {
		pw.write(MysqlUtil.listToFreedomJson("-2", "密码错误", null, null));
		return;
	}

注册Servlet部分

import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Calendar;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.qcby.db.MysqlUtil;

public class RegisterServlet extends HttpServlet {

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
		req.setCharacterEncoding("UTF-8");
		resp.setCharacterEncoding("UTF-8");
		String userName = req.getParameter("username");
		String passWord1 = req.getParameter("password1");
		String passWord2 = req.getParameter("password2");

		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSS");
		String remark = formatter.format(Calendar.getInstance().getTime());
		resp.setContentType("application/json;charset=UTF-8");
		PrintWriter pw = resp.getWriter();
		if (passWord1 != null && !passWord1.equals(passWord2)) {
			pw.write(MysqlUtil.listToFreedomJson("-3", "两次密码输入不一致", null, null));
			return;
		}
		String insertSql = "insert into t_entity_user(user_name, password, remark) value(\"" + userName + "\",\""
				+ passWord1 + "\",\"" + remark + "\")";

		System.out.println(insertSql);
		try {
			int result = MysqlUtil.add(insertSql);
			System.out.println("注册用户插入的行数" + result);
		} catch (Exception e) {
			pw.write(MysqlUtil.listToFreedomJson("-4", e.getMessage(), null, null));
			return;
		}
		pw.write(MysqlUtil.listToFreedomJson("0", "注册成功", null, null));
	}
}

注册要点
  1. 前端已经校验了两个密码是否相等了,后端为什么还要再校验一次?这是因为用户有可能是用postman或者swagger等接口测试工具发的请求,所以需要重新校验一次

至于为什么非空没校验,是因为懒,所以没写

但是真实企业场景下,除非做一些请求来源的验证,否则前端有的校验,后端有;前端没有的校验,后端一样有!后端负责整个项目的兜底

  1. sql的字符串一定要注意转移引号,否则sql会执行出错
  2. 这里在数据库的user表中,给user_name字段加了一个唯一索引(UNIQUE),防止重复。所以后端的注册没有判断用户名重复

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/632109.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用API有效率地管理Dynadot域名,默认将域名隐形转发至其他界面

关于Dynadot Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 Dynadot平台操作教程索引&#xff08;包括域名邮…

webpack优化构建速度示例-resolve.extensions:

当项目不仅仅包含.js或.json文件&#xff0c;还包含其他类型文件(如.ts、.vue、.css)作为模块时&#xff0c;配置resolve.extensions可以不必要的文件搜索提高性能。 src/index.ts import { someFuction } from ./modulesomeFuction()src/module.tsimport {otherSomeFuction} f…

三分钟快速上手SpringSecurity框架

导入依赖框架 web 框架(spring-boot-starter-web) <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency> springSecurity 框架(spring-boot-starter-security) <de…

【算法】二分查找——在排序数组中查找元素的第一个和最后一个位置

本节博客主要是通过“在排序数组中查找元素的第一个和最后一个位置”总结关于二分算法的左右界代码模板&#xff0c;有需要借鉴即可。 目录 1.题目2.二分边界算法2.1查找区间左端点2.1.1循环条件2.1.2求中点的操作2.1.3总结 2.2查找区间右端点2.1.1循环条件2.1.2求中点的操作2.…

vue框架学习--表单校验

在使用 Element UI&#xff08;一个常见的 Vue UI 组件库&#xff09;&#xff0c;要给 添加表单验证&#xff0c;Element UI 的表单验证通常通过 Form 和 FormItem 组件以及它们的 rules 属性来实现。下面是一个例子&#xff0c;展示如何给联系人字段添加表单验证&#xff1a;…

网页打开:为什么国内用新标签页,国外用当前页?

想写这个话题很久了&#xff0c;因为用百度和Google搜索时&#xff0c;打开搜索结果链接时的交互差异&#xff0c;几乎每天都要提醍我一下。 网页打开——这个交互&#xff0c;在设计里&#xff0c;算是极微小&#xff0c;但影响极广泛的操作设计。甚至&#xff0c;因此形成了…

使用Python处理Excel数据:去除列中的双引号

目录 引言 技术背景 步骤概述 代码示例 案例分析 扩展内容 1. 处理多个列中的双引号 2. 处理大型Excel文件 3. 自定义函数处理数据 4. 错误处理和日志记录 结论 引言 在当今信息爆炸的时代&#xff0c;数据已经成为了各个行业最宝贵的资源之一。而Excel&#xff0c…

转载 | 大佬3万字深度分析:2024全球游戏业正在遭遇什么困境?

2022年&#xff0c;游戏业当时的裁员人数达到了破纪录的8500人&#xff0c;2023年这个数字几乎增长了20%&#xff0c;然后在2024开年的两个月&#xff0c;就已经有7800人丢掉了工作。伴随着这些裁员的&#xff0c;是大量表现不及预期的或者完全失败的游戏&#xff0c;还有更多处…

人工智能(一)架构

一、引言 人工智能这个词不是很新鲜&#xff0c;早就有开始研究的&#xff0c;各种推荐系统、智能客服都是有一定的智能服务的&#xff0c;但是一直都没有体现出多高的智能性&#xff0c;很多时候更像是‘人工智障’。 但是自从chatGpt3被大范围的营销和使用之后&#xff0c;人…

Hbuild-X运行ios基座app

一、说明 ios真机第一次运行的时候需要下载插件&#xff0c;这个都是自动监测&#xff0c;自动下载的&#xff0c;不用多说。ios真机运行是需要签名的&#xff0c;不然就会报以下错误。如何制作免费的签名证书呢&#xff0c;需要借助爱思助手来完成。 二、安装爱思助手 &…

吴恩达机器学习笔记:第 10 周-17大规模机器学习(Large Scale Machine Learning)17.3-17.4

目录 第 10 周 17、 大规模机器学习(Large Scale Machine Learning)17.3 小批量梯度下降17.4 随机梯度下降收敛 第 10 周 17、 大规模机器学习(Large Scale Machine Learning) 17.3 小批量梯度下降 小批量梯度下降算法是介于批量梯度下降算法和随机梯度下降算法之间的算法&am…

一行代码实现vip标志的显示

需求说明 在项目中&#xff0c;后期添加了一种用户类型。需要再用户头像右下角显示一个vip的标志。问题是只要有头像的地方都要显示。而有头像的地方很多&#xff0c;设置到的接口也很多。后面考虑通过一个工具类&#xff0c;将这个功能外挂到原来的业务需要的地方。 实现效果…

Java—如何判断两个浮点数相等

结论 一旦有浮点型数据参与运算的结果&#xff0c;一定不要使用 “ ” 与其比较。 提出问题 我们知道在Java中浮点数float 和 double 的值不能很精准的表示一个小数&#xff0c;因为会有精度损失。 下面来看一个例子&#xff1a; public class FloatTest {public static …

教程:在 Apifox 中将消息通知集成到钉钉、飞书等应用

Apifox 支持将「消息通知」集成到第三方应用平台&#xff0c;包括企业微信、钉钉、飞书、Webhook 和 Jenkins。具体可在项目的【项目设置 -> 通知设置 -> 外部通知】里新建一个通知事件&#xff0c;然后在弹出的界面中配置即可。 在配置界面可以选择需要的触发事件&#…

如何在WordPress中启用两因素身份验证?

在WordPress中启用两因素身份验证方法&#xff1a;安装和激活WordFence安全性、启用两因素验证。 使用您可以从任何位置登录的任何门户&#xff0c;建议启用两个因素身份验证以增加帐户的安全性。 这样&#xff0c;即使有人可以正确猜测你的密码&#xff0c;它们仍然需要获得2…

诸葛智能携手五大银行,以数据驱动的营销中台带来可预见增长

对于银行来说&#xff0c;客户是赖以生存的基础&#xff0c;也是保持活力的关键。尤其是大数据、人工智能等新兴技术的推动下&#xff0c;通过数据赋能产品升级和服务创新&#xff0c;深挖客户潜能&#xff0c;更是助推银行快步迈入高质量发展的新阶段。 在银行加速拥抱新质生…

32位处理的寻址方式

32位处理器兼容16位处理器的寻址方式&#xff0c;可以运行传统的16位代码。但是由于32位的处理器都拥有32位的寄存器和算数逻辑部件&#xff0c;而且同内存芯片之间的数据通路至少是32位的&#xff0c;因此&#xff0c;所有需要从寄存器或者内存地址处取得操作数的指令都被扩充…

Python专题:八、为整数增加小数点

1、题目 虽说很多人讨厌小数点&#xff0c;但是有时候小数点是必不可少的一项&#xff0c;请你使用强制类型转换为输入的整数增加小数点&#xff0c;并输出改变类型后的变量类型。 2、代码 import sysa float(int(input())) print(f"(a:.lf)",type(a),sep"\…

RTMP低延迟推流

人总是需要压力才能进步, 最近有个项目, 需要我在RK3568上, 推流到公网, 最大程度的降低延迟. 废话不多说, 先直接看效果: 数据经过WiFi发送到Inenter的SRS服务器, 再通过网页拉流的. 因为是打金任务, 所以逼了自己一把, 把RTMP推流好好捋一遍. 先说说任务目标, 首先是MPP编码…

什么是检索增强生成(Retrieval Augmented Generation)?RAG 架构如何实现?

检索增强生成&#xff08;Retrieval Augmented Generation&#xff09;时代 在不断发展的生成人工智能世界中&#xff0c;检索增强生成 (RAG) 标志着一项重大进步&#xff0c;它将检索模型的准确性与生成模型的创造性相结合&#xff0c;达到了准确&创新的更高层级。 这种…