前言
学习了那么久的Java语法,总体感觉就是Java的语法知识更抽象,知识点也更琐碎。所以是时候来使用学过的知识做一个Java小项目了,一方面是对学过知识的总结,另一方面也可以通过项目来提示自己的编程能力。疫情发展到今天正在逐渐成为过去式,为纪念当年与疫情作斗争的日子,那么下面就以《核酸检测信息管理系统》为这次项目的主题。
一、功能与需求分析
核酸检测信息管理系统顾名思义就是对核酸检测中产生的各种信息进行管理,其中可能包括一些用户的个人信息,账户信息等,同时还应具有将数据进行分类管理能力,给使用者提供一些便捷的管理接口等,具体需求大致分为如下三个部分:
1、系统设计的初衷: 该系统的目的是为了更好地管理核酸检测信息,使得居民、采样人员和检测人员能够高效地使用系统。
2、系统的用户: 居民、采样人员和检测人员是该系统的三类用户,每类用户都有一些特定的功能。
(1)居民用户的功能:居民用户可以使用系统进行核酸预约登记、查询预约信息、修改预约信息、删除预约信息以及检测报告查询。
(2)采样人员用户功能: 采样人员用户可以使用系统查询已预约人员名单、采样信息录入和查询采样记录。
(3)检测人员用户功能: 检测人员在这个系统中可以查询已采样人员名单、检测结果录入和查询检测记录。
3、其他基本功能:
(1)该系统应分类管理不同用户的访问权限,以免发生访问冲突。
(2)该系统应具有数据存储的能力。需要支持用户数据的存储,以便对数据信息进行有效的检索和操作。
(3)该系统应具有最基本的登录验证功能,保护系统和用户信息的安全。
基于面向对象的设计思想,结合以上需求,我们可以画出如下具体业务流程图:
二、详细设计与实现
为了能够对系统内各部分信息,以及系统的各部分功能进行更好的分类管理,这里建了3个包和一个主函数:
1、data包
data包是系统的信息区,主要包含了用户核酸检测的个人信息、用户的账号和密码信息。这里面的信息也是之后operation包中各个功能类操作的信息来源,可以说是整个系统的基础核心。
(1)Data+DataBase
Data类中是系统中核酸检测所需的各种信息,这里对这些信息采用了private封装,仅提供对外的set和get方法便于之后对这些信息的处理。同时增加了一些基本信息的构造方法,方便对用户基本信息的初始化。最后便于信息的显示,重写了Data类下的toString方法。
package data; public class Data { private String name;//姓名 private String id;//身份证号 private String phone;//手机号 private String type;//预约类型 private boolean isOrdered;//是否已预约 private boolean isSampled;//是否已采样 private boolean isChecked;//是否已检测 private boolean isNegative;//是否阴性 public Data(String name, String id, String phone, String type) { this.name = name; this.id = id; this.phone = phone; this.type = type; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getType() { return type; } public void setType(String type) { this.type = type; } public boolean isOrdered() { return isOrdered; } public void setOrdered(boolean ordered) { isOrdered = ordered; } public boolean isSampled() { return isSampled; } public void setSampled(boolean sampled) { isSampled = sampled; } public boolean isChecked() { return isChecked; } public void setChecked(boolean checked) { isChecked = checked; } public boolean isNegative() { return isNegative; } public void setNegative(boolean negative) { isNegative = negative; } @Override public String toString() { return "Resident{" + "name='" + name + '\'' + ", id='" + id + '\'' + ", phone='" + phone + '\'' + ", type='" + type + '\'' + ", isOrdered=" + (isOrdered==false?"未预约":"已预约") + ", isSampled=" + (isSampled==false?"未采样":"已采样") + ", isChecked=" + (isChecked==false?"未检测":"已检测") + '}'; } }
DataBase类是一个基于Data类的信息库,可以将Data类理解为一本书、那么DataBase就是相当于书架的存在。DataBase提供了一个容纳信息的容器Data[] datas = new Data[100],之后系统中的用户信息统一交给DataBase储存管理,之后对信息的各种操作也要通过DataBase进行。
package data; public class DataBase { Data[] datas = new Data[100]; private String checkInstation;// private int containSize=0;//当前信息容量 public DataBase() { datas[0]=new Data("张三","111111111111111111","11111119876","单采"); datas[1]=new Data("李四","222222222222222222","11111118765","单采"); datas[2]=new Data("王五","333333333333333333","11111117654","单采"); datas[3]=new Data("赵六","444444444444444444","11111116543","混采"); datas[4]=new Data("路人甲","555555555555555555","11111115432","混采"); datas[5]=new Data("路人乙","666666666666666666","11111114321","混采"); datas[0].setOrdered(true); datas[1].setOrdered(true); datas[2].setOrdered(true); datas[3].setOrdered(true); datas[4].setOrdered(true); datas[5].setOrdered(true); containSize=6; } public int getContainSize() { return containSize; } public void setContainSize(int containSize) { this.containSize = containSize; } public Data getData(int pos) { return datas[pos]; } public void setData(Data data) { this.datas[containSize]=data; } public void setData(int pos,Data data) { this.datas[pos]=data; } public String getCheckInstation() { return checkInstation; } public void setCheckInstation(String checkInstation) { this.checkInstation = checkInstation; } }
(2)NaPa+NamePassword
NaPa类定义了用户账号密码的基本信息,使用private修饰账户信息,并对外提供了一些get和set方法方便对账户信息进行必要更改。同时提供构造方法,方便信息初始化。
package data; public class NaPa { String name; String password; public NaPa(String name, String password) { this.name = name; this.password = password; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
NamePassword类是专门用来存储用户账号密码的信息库,其作用相当于上面的DataBase类。之后用户的登录/注册以及身份验证都需要通过访问NamePassword类进行。
package data; public class NamePassword { private NaPa[] naPas = new NaPa[100]; private int NPnubmer; public NamePassword() { naPas[0]=new NaPa("张三","123456"); naPas[1]=new NaPa("李四","666666"); naPas[2]=new NaPa("王五","7777777"); NPnubmer=3; } public int getNPnubmer() { return NPnubmer; } public void setNPnubmer(int NPnubmer) { this.NPnubmer = NPnubmer; } public void setNaPas(String name,String password) { NaPa naPa = new NaPa(name,password); naPas[NPnubmer]=naPa; } public NaPa getNapas(int pos) { return naPas[pos]; } }
2、operation包
operation包中的类是操作类,是对用户的在系统的的功能权限进行了具体的实现。为方便管理,这些类统一实现了IOperation接口,之后通过IOperation接口统一调用,这里也是使用到了多态的设计思想。这里的每个类都对应这系统流程中的一个功能,这些功能可以根据具体的业务需求进行实现,这里博主只是根据自己的理解进行实现,所以下面就给出各个类的代码,不再详细介绍每种实现方式,大家可以以此作为参考:
(1)操作接口
package operation; import data.DataBase; import java.util.Scanner; public interface IOperation { Scanner scanner = new Scanner(System.in); void work(DataBase dataBase); }
(2)Resident用户功能
0.退出当前系统
package operation; import data.DataBase; public class ExitChild implements IOperation{ @Override public void work(DataBase dataBase) { System.out.println("已退出当前系统!"); } }
1.核酸预约登记
import data.Data; import data.DataBase; public class Register implements IOperation { @Override public void work(DataBase dataBase) { System.out.println("核酸预约登记!"); System.out.print("请输入你的姓名:"); String name = scanner.nextLine(); System.out.print("请输入你的身份证号:"); String id = scanner.nextLine(); System.out.print("请输入你的手机号:"); String phone = scanner.nextLine(); System.out.print("请输入预约类型:(单采/混采):"); String type = scanner.nextLine(); //判断是否预约过-按id在DataBase查找 int currentSize=dataBase.getContainSize(); for (int i = 0; i < currentSize; i++) { if (dataBase.getData(i).getId().equals(id)) { System.out.println("已存在身份证号为:"+id+"的预约信息!"); return; } } Data data = new Data(name,id,phone,type); dataBase.setData(data); data.setOrdered(true); dataBase.setContainSize(currentSize+1);//踩坑了 System.out.println("预约成功!"); } }
2.预约信息查询
package operation; import data.DataBase; public class SearchRegister implements IOperation { @Override public void work(DataBase dataBase) { System.out.println("预约信息查询!"); System.out.print("请输入您的身份证号:"); String id = scanner.nextLine(); int currentSize=dataBase.getContainSize(); for (int i = 0; i < currentSize; i++) { if (dataBase.getData(i).getId().equals(id)) { System.out.println("预约人:"+dataBase.getData(i).getName()); System.out.println("身份证号:"+dataBase.getData(i).getId()); System.out.println("手机号:"+dataBase.getData(i).getPhone()); System.out.println("预约状态:已预约"); return; } } System.out.println("不存在预约信息,请先预约!"); } }
3.预约信息修改
package operation; import data.DataBase; public class ModifyRegister implements IOperation { @Override public void work(DataBase dataBase) { System.out.println("预约信息修改!"); System.out.print("请输入您的身份证号:"); String id = scanner.nextLine(); int currentSize=dataBase.getContainSize(); for (int i = 0; i < currentSize; i++) { if (dataBase.getData(i).getId().equals(id)) { System.out.println("找到预约信息,请修改:"); System.out.print("请输入修改姓名:"); String name = scanner.nextLine(); System.out.print("请输入修改身份证号:"); id = scanner.nextLine(); System.out.print("请输入修改电话:"); String phone = scanner.nextLine(); System.out.print("请输入修改采样类型:(单采/混采):"); String type = scanner.nextLine(); dataBase.getData(i).setName(name); dataBase.getData(i).setId(id); dataBase.getData(i).setPhone(phone); dataBase.getData(i).setType(type); System.out.println("修改信息成功!"); return; } } System.out.println("不存在预约信息,请先预约!"); } }
4.预约信息删除
package operation; import data.Data; import data.DataBase; public class DelRegister implements IOperation { @Override public void work(DataBase dataBase) { System.out.println("预约信息删除!"); System.out.print("请输入需要删除人员的身份证号:"); String id = scanner.nextLine(); int currentSize=dataBase.getContainSize(); for (int i = 0; i < currentSize; i++) { if (dataBase.getData(i).getId().equals(id)) { for (int j = i; j < currentSize-1; j++) { Data data = dataBase.getData(j+1); dataBase.setData(j,data); } dataBase.setData(currentSize-1,null); dataBase.setContainSize(currentSize-1); System.out.println("已删除id="+id+"的预约信息!"); return; } } System.out.println("未找到预约信息,请先预约!"); } }
5.核酸报告查询
package operation; import data.Data; import data.DataBase; public class SearchResult implements IOperation { @Override public void work(DataBase dataBase) { System.out.println("检测报告查询!"); System.out.print("请输入你的姓名:"); String name = scanner.nextLine(); System.out.print("请输入你的身份证号:"); String id = scanner.nextLine(); int currentSize=dataBase.getContainSize(); for (int i = 0; i < currentSize; i++) { Data data = dataBase.getData(i); if (data.getId().equals(id)) { if (!data.isSampled()) { System.out.println("当前状态:未采样"); return; } if (!data.isChecked()) { System.out.println("当前状态:未检测"); return; } System.out.println("┌-----------------------------┐"); System.out.println("你好 "+name+" 您的核酸检测信息如下:"); System.out.println("身份证号:"+id); System.out.println("检测机构:"+dataBase.getCheckInstation()); System.out.println("检测结果:"+(!data.isNegative()?"阴性":"阳性")); System.out.println("└-----------------------------┘"); } } } }
(3)Simper用户功能
1.查询已预约人员名单
package operation; import data.DataBase; public class Registerlist implements IOperation { @Override public void work(DataBase dataBase) { System.out.println("已预约人员名单!"); int currentSize=dataBase.getContainSize(); for (int i = 0; i < currentSize; i++) { System.out.println(dataBase.getData(i)); } } }
2.采样信息录入
package operation; import data.DataBase; public class SampleEnter implements IOperation { @Override public void work(DataBase dataBase) { System.out.println("采样信息录入!"); System.out.print("请输入手机尾号后四位:"); String temPhone = scanner.nextLine(); int currentSize=dataBase.getContainSize(); for (int i = 0; i < currentSize; i++) { String splitPhone = dataBase.getData(i).getPhone().substring(dataBase.getData(i).getPhone().length()-4); if (temPhone.equals(splitPhone)) { dataBase.getData(i).setSampled(true); System.out.println("手机尾号为"+splitPhone+" 已采样完毕!"); return; } } System.out.println("未找到尾号为"+temPhone+"的预约信息,采样失败!"); } }
3.查询采样记录
package operation; import data.Data; import data.DataBase; public class SearchSampled implements IOperation{ @Override public void work(DataBase dataBase) { System.out.println("查询采样记录!"); System.out.println("已采样人员:"); int currentSize=dataBase.getContainSize(); for (int i = 0; i < currentSize; i++) { Data data = dataBase.getData(i); if (data.isSampled()) { System.out.println(data.getName() + data.getPhone() + "已采样"); } } System.out.println("未采样人员:"); for (int i = 0; i < currentSize; i++) { Data data = dataBase.getData(i); if (!data.isSampled()) { System.out.println(data.getName() + data.getPhone() + "未采样"); } } } }
(4)Checker用户功能
1.查询已采样人员名单
package operation; import data.Data; import data.DataBase; public class SampleList implements IOperation { @Override public void work(DataBase dataBase) { System.out.println("已采样人员名单!"); int currentSize=dataBase.getContainSize(); for (int i = 0; i < currentSize; i++) { Data data = dataBase.getData(i); if (data.isSampled()) { System.out.println(data); } } } }
2.样本检测结果输入
package operation; import data.DataBase; public class CheckEnter implements IOperation { @Override public void work(DataBase dataBase) { System.out.println("样本检测结果录入!"); System.out.print("请输入手机尾号后四位:"); String temPhone = scanner.nextLine(); int currentSize=dataBase.getContainSize(); for (int i = 0; i < currentSize; i++) { String splitPhone = dataBase.getData(i).getPhone().substring(dataBase.getData(i).getPhone().length()-4); if (temPhone.equals(splitPhone)) { dataBase.getData(i).setChecked(true); System.out.println("请输入检测结果:(1.阴性 2.阳性)"); int choice = scanner.nextInt(); scanner.nextLine();//读取回车符号 if(choice==2) { dataBase.getData(i).setNegative(true); } System.out.println("手机尾号为"+splitPhone+" 的居民检测结果录入完毕!"); return; } } System.out.println("未找到尾号为"+temPhone+"的采样信息,检测失败!"); } }
3.查询检测记录
package operation; import data.Data; import data.DataBase; public class SearchChecked implements IOperation { @Override public void work(DataBase dataBase) { System.out.println("查询检测记录!"); System.out.println("已检测人员:"); int currentSize=dataBase.getContainSize(); for (int i = 0; i < currentSize; i++) { Data data = dataBase.getData(i); if (data.isChecked()) { System.out.println(data.getName() + data.getPhone() + "已检测"); } } System.out.println("未检测人员:"); for (int i = 0; i < currentSize; i++) { Data data = dataBase.getData(i); if (!data.isChecked()) { System.out.println(data.getName() + data.getPhone() + "未检测"); } } } }
3、user包
user包下是本系统的三类用户Resident-居民、Samper-采样人员、Checker-检测人员。经分析,无论是居民、采样人员还是检测人员,在系统中它们都属于用户,所以在user包下可以将用户抽象成一个类User,将Resident、Samper、Checker看成User的子类,并且这样处理也是方便了对用户的统一管理,之后可以在Main中直接通过操控父类User,利用多态的思想就能实现对各用户的分类管理。
(1)User类
为了在使用User类时实现对三类不同用户的管理即多态,首先这里声明了一个抽象方法menu,在后续Resident、Samper、Checker中可以分别按需实现不同的菜单menu,另外在User中提供了IOperation接口数组、doWork方法,通过统一调用doWork方法再根据用户选择后菜单中的返回值choice,可以在接口数组中根据下标找到相应的功能,最后通过IOperation接口实现对业务的统一调用。当然至于IOperation数组的实现可以放到后续的Resident、Samper、Checker中分别进行具体的实现。用IOperation接口数组实现各个菜单下的多态,对于没有相关设计经验的小白来说,这也是本系统的难点,希望可以对这点多加体会。
package user; import data.DataBase; import operation.IOperation; public abstract class User { public abstract int menu(); IOperation[] iOperation; public void doWork(int choice, DataBase dataBase) { iOperation[choice].work(dataBase); } }
(2)Resident类
package user; import operation.*; import java.util.Scanner; public class Resident extends User{ public Resident() { super.iOperation=new IOperation[] { new ExitChild(), new Register(), new SearchRegister(), new ModifyRegister(), new DelRegister(), new SearchResult() }; } @Override public int menu() { Scanner scanner = new Scanner(System.in); System.out.println("************* 欢迎来到核酸信息管理系统! **************"); System.out.println("1.核酸预约登记"); System.out.println("2.预约信息查询"); System.out.println("3.预约信息修改"); System.out.println("4.预约信息删除"); System.out.println("5.检测报告查询"); System.out.println("0.退出当前系统"); System.out.print("请选择你的操作:"); int choice = scanner.nextInt(); return choice; } }
(3)Samper类
package user; import operation.*; import java.util.Scanner; public class Samper extends User { public Samper() { super.iOperation=new IOperation[] { new ExitChild(), new Registerlist(), new SampleEnter(), new SearchSampled() }; } @Override public int menu() { Scanner scanner = new Scanner(System.in); System.out.println("************* 欢迎来到核酸信息管理系统! **************"); System.out.println("1.查询已预约人员名单"); System.out.println("2.采样信息录入"); System.out.println("3.查询采样记录"); System.out.println("0.退出当前系统"); System.out.print("请选择你的操作:"); int choice = scanner.nextInt(); return choice; } }
(4)Checker类
package user; import operation.*; import java.util.Scanner; public class Checker extends User{ public Checker() { super.iOperation=new IOperation[] { new ExitChild(), new SampleList(), new CheckEnter(), new SearchChecked() }; } @Override public int menu() { Scanner scanner = new Scanner(System.in); System.out.println("************* 欢迎来到核酸信息管理系统! **************"); System.out.println("1.查询已采样人员名单"); System.out.println("2.样本检测结果录入"); System.out.println("3.查询检测记录"); System.out.println("0.退出当前系统"); System.out.print("请选择你的操作:"); int choice = scanner.nextInt(); return choice; } }
4、Main-系统逻辑主体
Main类是整个系统的入口,同时起到了将上述内容合理串联起来的作用。其中包含了登录/注册、身份选择、异常处理。
import data.DataBase; import data.NamePassword; import user.*; import java.util.ArrayList; import java.util.Scanner; class InvalidUsernameException extends RuntimeException { //帮助父类构造 public InvalidUsernameException(String message) { super(message); } } class InvalidPasswordException extends RuntimeException { //帮助父类构造 public InvalidPasswordException(String message) { super(message); } } public class Main { //登录注册函数: public static void sign(NamePassword namePassword) { Scanner scanner = new Scanner(System.in); while (true) { System.out.println("1.登录 2.注册"); System.out.print("请输入你的选择:"); int choice = scanner.nextInt(); scanner.nextLine();//读取/n if (choice==1) { System.out.print("请输入你的用户名:"); String name = scanner.nextLine(); System.out.print("请输入你的密码:"); String password = scanner.nextLine(); int i=0; for (i = 0; i < namePassword.getNPnubmer(); i++) { if (name.equals(namePassword.getNapas(i).getName())) { break; } } if (i==namePassword.getNPnubmer()) { throw new InvalidUsernameException("用户名错误!"); } int j=0; for (j = 0; j < namePassword.getNPnubmer(); j++) { if (password.equals(namePassword.getNapas(i).getPassword())) { return; } } if (j==namePassword.getNPnubmer()) { throw new InvalidPasswordException("密码错误!"); } } else if (choice==2) { int currentNumber = namePassword.getNPnubmer(); System.out.print("请输入你的用户名:"); String name = scanner.nextLine(); System.out.print("请输入你的密码:"); String password = scanner.nextLine(); namePassword.setNaPas(name,password); namePassword.setNPnubmer(currentNumber+1); System.out.println("注册成功!"); } else { System.out.println("输入错误,请重新输入!"); } } } //登录验证和身份选择 public static User login(DataBase dataBase,NamePassword namePassword) { Scanner scanner = new Scanner(System.in); System.out.println("1.居民 2.采样人员 3.检测人员 0.退出系统"); System.out.print("请输入你的身份:"); int id=scanner.nextInt(); scanner.nextLine(); // 处理无效选择: if(id==0) { System.out.println("已退出核酸检测信息管理系统!"); System.exit(0); return null; } if (id!=1 && id!=2 && id!=3) { System.out.println("无效选择,退出系统!"); System.exit(1); } //处理登录异常异常 try{ sign(namePassword); System.out.println("登录成功!"); } catch (InvalidUsernameException e) { System.out.println(e); System.out.println("登录异常,退出系统!"); System.exit(1); } catch (InvalidPasswordException e) { System.out.println(e); System.out.println("登录异常,退出系统!"); System.exit(1); } // 处理有效选择: if(id==1) { return new Resident(); } if(id==2) { return new Samper(); } if (id==3){ System.out.print("请输入检测机构:"); String station=scanner.nextLine(); dataBase.setCheckInstation(station); return new Checker(); } return null; } //系统的入口,对整体逻辑进行组织 public static void main(String[] args) { NamePassword namePassword = new NamePassword(); DataBase dataBase=new DataBase(); while (true) { int choice=1; User user = login(dataBase,namePassword); while (choice!=0) { choice=user.menu(); user.doWork(choice,dataBase); } } } }
三、系统测试
1、系统注册/登录测试
2、Resident-居民功能测试
3、Samper-采样人员功能测试
4、Checker-检测人员功能测试
总结
以上就是《核酸检测信息管理系统》的全部设计与实现了,其实如果你仔细观察Main类的话,可以发现整个系统也就是通过User类和IOperation接口实现统领全局的,通过User类可以实现对三种用户的跳转,通过IOperation接口又可以实现各用户下的不同功能。可以说多态的思想在User类和IOperation接口中体现的淋漓尽致!
同时本系统设计的一个难点在于通过IOperation接口数组的下标,实现对不同用户菜单下的多态控制,这里希望大家能够多多体会,在实践中加深理解。最后希望通过对系统设计的阐述能够给你带来一些启发,如果想参考本章节系统的完整源码,大家可以在我的Gitee仓库获取:《核酸检测信息管理系统》