

❀❀❀ 大佬求个关注吧~祝您开心每一天 ❀❀❀

目录
[3.1 系统菜单打印](#3.1 系统菜单打印)
[3.2 系统注册](#3.2 系统注册)
[3.2.1 检测账号是否存在](#3.2.1 检测账号是否存在)
[3.2.2 检测密码是否满足要求](#3.2.2 检测密码是否满足要求)
[3.2.3 检测身份证号是否满足要求](#3.2.3 检测身份证号是否满足要求)
[3.3 系统登陆](#3.3 系统登陆)
[3.3.1 限制登录次数](#3.3.1 限制登录次数)
[3.4 忘记密码](#3.4 忘记密码)
[3.4.1 重置密码](#3.4.1 重置密码)
上一篇文章当中,写了一个简单的学生管理系统,今天在这个系统的基础上,实现一个基于用户登录注册的学生管理系统。
一、系统设计图

系统流程图大致如上,图中有有一些部分在这里省略掉了,用简单的方式展示一下系统的功能。
主要包含三个模块,登录、注册和忘记密码。
登录功能包含验证码校验(只是模拟简单的验证码校验,不涉及短信等服务),还有密码重试次数,当密码重试达到一定次数后,就会禁止登陆。
注册功能在使用的时候还会填写姓名和身份证号码,用于忘记密码时候的密保信息,注册功能确保注册的用户的账号不重复。
忘记密码功能,会校验用户输入的密保信息,信息正确则提示用户修改密码,然后重新跳转登录(图中未体现)。
二、添加用户类
对于用户类的设计,除了基本的账号、密码、姓名和身份证号外,应该还有一些其他的信息,比如我们提到了会记录用户登录时输入密码的次数,我们可以考虑在用户类中添加一个属性,来记录用户输入密码错误的次数。引入错误次数后,还要考虑,将错误次数清除,我们可以设计在第二天的时候,清空错误次数,不然用户就无法登陆了。所以还要有一个字段记录第一次错误时候的时间。只要用户可以在规定次数内输入正确,就把这个错误次数清空。
java
public class User {
private String username;
private String password;
private String nickname;
private String idNumber;
private String errorDate;
private Integer errorCount;
}
代码中的get和set方法我去掉了在这里,因为太长了,大家可以自己补全一下,使用Alt+Insert键,选择getter和setter就可以自动生成。
三、系统功能设计
3.1 系统菜单打印
和上次的文章一样,系统菜单的打印差不多,主要就是登录、注册和忘记密码功能。
java
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(true){
printMenu();
System.out.print("请输入要进入的功能:");
int option = sc.nextInt();
switch (option){
case 1:
System.out.println("登录");
break;
case 2:
System.out.println("注册");
break;
case 3:
System.out.println("忘记密码");
break;
case 0:
System.out.println("退出系统");
break;
default:
System.out.println("输入的选项有误");
break;
}
}
}
public static void printMenu() {
// 打印菜单界面
System.out.println("┌──────────────────────────┐");
System.out.println("│ 学生信息管理系统登录 │");
System.out.println("├──────────────────────────┤");
System.out.println("│ 1. 登录 │");
System.out.println("│ 2. 注册 │");
System.out.println("│ 3. 忘记密码 │");
System.out.println("│ 0. 退出系统 │");
System.out.println("└──────────────────────────┘");
}
3.2 系统注册
系统的注册功能在这里我做了两个校验:
- 密码安全性校验:要求密码是6-10位且包含字母和数字的组合
- 身份证号校验:身份证号必须满足真实身份证号的规则(可以用自己的,本地程序不会有信息泄露)
注册功能代码如下,详细内容可以看代码中的注释。有些逻辑还是可以补充的,比如密码输入错误可以使用循环重试,这里我直接返回了。
java
public static void registerUser(List<User> users){
// 注册用户首先保证用户名不能重复
// 模拟信息的填写过程
Scanner sc = new Scanner(System.in);
System.out.print("请输入用户名:");
String username = sc.next();
// 检查用户是否存在了
boolean checkUserExist = checkUserExist(users, username);
if(checkUserExist){
// 用户存在了
System.out.println("该用户已被注册!");
// 跳出到系统页面
return;
}
System.out.print("请输入密码(6-10位,且包含数字和字母):");
String password = sc.next();
// 进行密码强度的检测 我们要求密码是6-10位的数字和字母组成
boolean safe = checkPassword(password);
if(!safe){ // 相当于 if(safe == false)
System.out.println("您的密码输入格式有误!");
// 这里直接返回了,其实这里可以用循环去操作
// 但是这里设定,输入密码有误直接跳出到登录页面重新尝试
return;
}
System.out.print("确认密码:");
String ensurePassword = sc.next();
if(!password.equals(ensurePassword)){
// 如果两次密码不一致,直接返回
System.out.println("您输入的两次密码不一致!");
return;
}
System.out.print("请输入您的姓名(用作密保信息):");
String nickname = sc.next();
System.out.print("请输入您的身份证号码(仅用作密码信息):");
String idNumber = sc.next();
// 校验输入的身份证号码
boolean checkNumber = checkIDNumber(idNumber);
if(!checkNumber){ // 相当于 checkNumber == false
// 身份证号不符合规则
// 这里不跳出去了,毕竟都输入了那么多信息了,这里给两次重试机会
for (int i = 0; i < 2 && !checkNumber; i++) {
System.out.println("您输入的身份证号码有误,请重新尝试!");
System.out.print("请输入您的身份证号码(仅用作密码信息):");
idNumber = sc.next();
checkNumber = checkIDNumber(idNumber);
}
//这里在判断一下身份证对不对
if(!checkNumber){
// 输入了两次还是不对
System.out.println("您输入的身份证有误,失败次数过多,退出系统");
return;
}
}
// 走到这里就说明有一次是输入正确的
User user = new User();
user.setUsername(username);
user.setPassword(password);
user.setNickname(nickname);
user.setIdNumber(idNumber);
user.setErrorCount(0);
user.setErrorDate(SimpleDateFormat.getDateInstance().format(new Date()));
users.add(user);
System.out.println("注册成功!");
return;
}
在上方的代码中,用到了三个方法,分别用户检测账号是否被注册、检测输入的密码是否正确以及检测输入的身份证号是否满足真实身份证号的信息。
3.2.1 检测账号是否存在
java
private static boolean checkUserExist(List<User> users, String username) {
for (User user : users) {
if(user.getUsername().equals(username)){
return true;
}
}
return false;
}
3.2.2 检测密码是否满足要求
这个正则表达式不用太在意,我也是在网上搜索的,大家有时间可以自己学习一下。
java
private static boolean checkPassword(String password) {
Pattern pattern = Pattern.compile("^(?!^\\d+$)(?!^[a-zA-Z]+$)[a-zA-Z0-9]{6,10}$");
Matcher matcher = pattern.matcher(password);
/*if(matcher.matches()){
// 证明符合规则
return true
}else{
return false;
}*/
return matcher.matches();
}
3.2.3 检测身份证号是否满足要求
java
private static boolean checkIDNumber(String idNumber) {
// 身份证号码正则表达式,我们直接上网搜索,这里不在讲解正则表达式了
Pattern pattern = Pattern.compile("^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$");
Matcher matcher = pattern.matcher(idNumber);
/*if(matcher.matches()){
// 证明符合规则
return true
}else{
return false;
}*/
return matcher.matches();
}
3.3 系统登陆
java
public static boolean loginUser(List<User> users){
Scanner sc = new Scanner(System.in);
// 模拟一个验证码
Random random = new Random();
String sendCode = String.valueOf(1000 + random.nextInt(9000));
System.out.println("系统向您的手机发送了验证码,请查收");
System.out.println("您的验证码是:" + sendCode);
System.out.print("请输入账号:");
String username = sc.next();
// 判断用户是否存在
boolean checkUserExist = checkUserExist(users, username);
if(!checkUserExist){
// 如果不存在
System.out.println("该账号未注册!");
return false;
}
// 添加验证码校验
System.out.print("请输入验证码:");
String code = sc.next();
if(!code.equals(sendCode)){
// 验证码不正确
return false;
}
System.out.print("请输入密码");
String password = sc.next();
boolean checkLogin = false;
// 判断密码是否正确
// 这里我没有写新的方法,其实是可以单独写一个方法的
for (User user : users) {
if(user.getUsername().equals(username) && user.getPassword().equals(password)){
// 密码验证正确
checkLogin = true;
}
}
if(!checkLogin){
// 如果密码不正确
System.out.println("您的密码有误!");
return false;
}
// 登录成功
return true;
}
登录的代码的逻辑都写到了注释当中了,当我们登录成功后,是要登录到学生管理系统的,对比之前写过的管理系统的代码,应该调整一下之前的代码,不能在main方法中启动程序了。调整到普通的方法当中,其中的静态方法也要 改为静态,且私有,只有展示菜单的方法,我们设置为公有。
java
public static void -》 private void
然后把main方法的内容写到startApp方法中,删掉main方法。
java
public void startApp(){
List<Student> students = new ArrayList<>();
printMenu();
while (true) {
int option;
Scanner sc = new Scanner(System.in);
System.out.print("请选择要进行的操作:");
option = sc.nextInt();
switch (option) {
case 1:
getStudentInfo(students);
break;
case 2:
addStudent(students);
break;
case 3:
updateStudentInfo(students);
break;
case 4:
deleteStudentInfo(students);
break;
case 0:
System.out.println("退出系统");
System.exit(0);
break;
default:
System.out.println("请输入正确的选项");
break;
}
}
}
调整我们写的登录的代码,switch中的。
java
switch (option){
case 1:
if(loginUser(users)){
Runtime.getRuntime().exec("cls");
// 把我们展示系统功能的页面打印出来
new StudentManagement().startApp();
}
break;
case 2:
registerUser(users);
break;
case 3:
System.out.println("忘记密码");
break;
case 0:
System.out.println("退出系统");
System.exit(0);
break;
default:
System.out.println("输入的选项有误");
break;
}
我在测试的时候发现,在学生管理页面输入0的时候,直接退出系统了,并没有跳转到这个登录页面,检查管理系统的页面发现,使用了这行命令。这行代码直接让我们的程序退出了,会影响到我们的登录功能,所以要调整一下。

调整后的代码如下:
在这里如果是0的话直接return。
3.3.1 限制登录次数
当我们密码输入错误的时候,就会记录到errorCount属性中。
具体的逻辑都在注释当中了。
java
public static boolean loginUser(List<User> users){
Scanner sc = new Scanner(System.in);
// 模拟一个验证码
Random random = new Random();
String sendCode = String.valueOf(1000 + random.nextInt(9000));
System.out.println("系统向您的手机发送了验证码,请查收");
System.out.println("您的验证码是:" + sendCode);
System.out.print("请输入账号:");
String username = sc.next();
// 判断用户是否存在
boolean checkUserExist = checkUserExist(users, username);
if(!checkUserExist){
// 如果不存在
System.out.println("该账号未注册!");
return false;
}
// 判断账号今日是否封禁了 密码重试次数达到上线
for (User user : users) {
if(user.getUsername().equals(username)){
String errorDate = user.getErrorDate();
String currentDate = SimpleDateFormat.getDateInstance().format(new Date());
if(user.getErrorCount() >= 3 && errorDate!= null && errorDate.equals(currentDate)){
System.out.println("您的密码重试次数达到上限,今日无法登录!");
return false;
}
}
}
// 添加验证码校验
System.out.print("请输入验证码:");
String code = sc.next();
if(!code.equals(sendCode)){
// 验证码不正确
return false;
}
System.out.print("请输入密码:");
String password = sc.next();
boolean checkLogin = false;
// 判断密码是否正确
// 这里我没有写新的方法,其实是可以单独写一个方法的
for (User user : users) {
if(user.getUsername().equals(username) && user.getPassword().equals(password)){
// 密码验证正确
checkLogin = true;
}else if(user.getUsername().equals(username) && !user.getPassword().equals(password)){
// 判断是不是当天第一次错误
int errorCount = user.getErrorCount();
String errorDate = user.getErrorDate();
String currentDate = SimpleDateFormat.getDateInstance().format(new Date());
// 如果错误日期为空,说明我们还没有错误过 证明是第一次错误
// 如果错误日期不为空,那么判断错误日期是否是当前日期,如果不是,说明记录的是之前错误的次数 也是当天第一次错误
if(errorDate == null || !errorDate.equals(currentDate)){
// 当天第一次错误
user.setErrorCount(1);
user.setErrorDate(currentDate);
}else{
// 不是当天第一次错误
user.setErrorCount(errorCount + 1);
if(user.getErrorCount() >= 3){
// 如果错误次数大于等于3了,就不让用户登陆了
System.out.println("您的密码重试次数达到上限,今日无法登录!");
return false;
}
}
}
}
if(!checkLogin){
// 如果密码不正确
System.out.println("您的密码有误!");
return false;
}
// 登录成功
return true;
}
3.4 忘记密码
最后就是忘记密码的功能了,在选择忘记密码时,首先输入忘记密码的账号,然后首先要判断一下账号是否存在。当密保信息校验正确后,重置密码。
java
private static void forgetPassword(List<User> users) {
Scanner sc = new Scanner(System.in);
System.out.print("请输入账号:");
String username = sc.next();
// 从users中查出这个用户
// 这里用之前写的checkUserExist那个方法
boolean userExist = checkUserExist(users, username);
if(!userExist){
System.out.println("该账号未注册!");
return;
}
// 但是这样写就会重复循环
// 因为要获取用户的密保信息
User user = new User();
for (User u : users) {
if(user.getUsername().equals(username)){
user = u;
break;
}
}
System.out.print("请输入绑定的姓名:");
String nickname = sc.next();
System.out.println("请输入绑定的身份证号:");
String idNumber = sc.next();
if(nickname.equals(user.getNickname()) && idNumber.equals(user.getIdNumber())){
// 校验成功 重新修改密码
changePassword(user);
return;
}
System.out.println("密保信息校验失败!");
}
3.4.1 重置密码
之前说到过,Java中是值传递的,这样子可以修改到users中对应用户的密码。
java
private static void changePassword(User user) {
Scanner sc = new Scanner(System.in);
System.out.print("请输入新的密码(6-10位,且包含数字和字母):");
String password = sc.next();
boolean checkPassword = checkPassword(password);
if(!checkPassword){
for (int i = 0; i < 2 && !checkPassword; i++) {
System.out.print("您输入的密码格式有误,请重新输入密码:");
password = sc.next();
checkPassword = checkPassword(password);
}
}
if(!checkPassword){
System.out.println("失败次数过多!");
return;
}
user.setPassword(password);
}