快递管理系统
任务描述:
从最初使用二维数组的方法存储快递信息,到使用集合将数据存储,这些存储方式在程序被关闭后,数据也随着丢失。因此,使用刚刚学习的IO技术完善快递管理系统,也可以巩固所学内容。
任务过程:
1、明确需求
2、选择合适的集合存储快递数据
3、将快递数据存储在文件中
4、程序启动时自动加载文件中数据
5、测试功能,保证齐全,无bug出现
任务所涉及知识点:
1、面向对象
2、集合
3、IO(文件输入输出)
4、MVC模型结构
添加链接描述
思考:
Java 平台允许我们在内存中创建可复用的 Java 对象,但一般情况下,只有当 JVM 处于运行时,这些对象才可能存在,即这些对象的生命周期不会比JVM的生命周期更长。但在现实应用中,就可能要求在 JVM 停止运行之后能够保存(持久化)指定的对象,并在将来重新读取被保存的对象。那么Java对象序列化就能够帮助我们实现该功能。
序列化:将数据结构或对象转换成二进制串的过程,是一种对象服务,把内存中的对象序列化成流,方便持久化到磁盘或者网络传输。
反序列化:将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程。
在序列化和反序列化中主要使用到1)ObjectOutputStream(对象输出流) , 可以通过writeObject(Object obj)方法对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。 2)ObjectInputStream(对象输入流) ,可通过readObject()方法从输入流中读取字节序 列,再把它们反序列化成为一个对象,并将其返回。
注:被序列化的对象需要实现Serializable接口。
完成过程:
第一步:
根据快递管理系统的任务描述可得,关于快递信息有如下:快递单号、快递公司、取件码、存储位置。根据这些信息,可以创建一个Model类,用来封装这些信息含有的属性。并对各属性设置get和set方法,以及构造方法,为后续使用。Model层主要是数据的存储,因此需要对Model进行序列化标记Serializable。
Model类(完整):
public class Model implements Serializable {
//快递信息
private String number;
private String company;
private int code;
//存储位置相关
public int posX,posY;
//get和set方法
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
//构造方法
public Model(String number, String company, int code) {
this.number = number;
this.company = company;
this.code = code;
}
public Model() {
}
@Override
public String toString() {
return "Model{" +
"number='" + number + '\'' +
", company='" + company + '\'' +
", code=" + code +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Model model = (Model) o;
return code == model.code &&
Objects.equals(number, model.number) &&
Objects.equals(company, model.company);
}
@Override
public int hashCode() {
return Objects.hash(number, company, code);
}
}
第二步:
对快递信息进行了封装,当要完成添加、删除、修改等操作时,每次都使用Model创建对象很不方便,因此出现了MVC模式中的View视图,给用户展示这些操作。
View类(完整)
public class View {
Scanner input = new Scanner(System.in);
public void welcome(){
System.out.println("欢迎使用快递柜~");
}
public void bye(){
System.out.println("再见,欢迎下次使用!");
}
/**
* 身份选择菜单
* @return
*/
public int menu(){
System.out.println("请根据相应提示,输入功能序号:");
System.out.println("1.管理员");
System.out.println("2.普通用户");
System.out.println("0.退出");
String text = input.nextLine();
int num = -1;
try{
num = Integer.parseInt(text);
}catch(NumberFormatException e){
}
if(num<0||num>2){
System.out.println("输入有误,请重新输入");
return menu();
}
return num;
}
/**
* 快递员的操作
* @return
*/
public int cMenu(){
System.out.println("请根据相应提示,输入功能序号:");
System.out.println("1.快递录入");
System.out.println("2.修改快递");
System.out.println("3.删除快递");
System.out.println("4.查看所有快递");
System.out.println("0.返回上一级");
String text = input.nextLine();
int num = -1;
try{
num = Integer.parseInt(text);
}catch(NumberFormatException e){
}
if(num<0||num>4){
System.out.println("输入有误,请重新输入");
return cMenu();
}
return num;
}
/**
* 录入快递
*/
public Model insert(){
System.out.println("请根据提示,输入快递信息:");
System.out.println("请输入快递单号:");
String number = input.nextLine();
System.out.println("请输入快递公司:");
String company = input.nextLine();
Model m = new Model();
m.setNumber(number);
m.setCompany(company);
return m;
}
/**
* 提示输入快递单号,根据单号来查找快递
* @return
*/
public String findByNumber(){
System.out.println("请根据提示,输入快递信息:");
System.out.println("请输入要操作的快递单号:");
String number = input.nextLine();
return number;
}
public void print(Model m){
System.out.println("快递信息如下:");
System.out.println("快递公司:"+m.getCompany()+",快递单号:"+m.getNumber()+",取件码:"+m.getCode());
}
public void update(Model m){
System.out.println("请输入新的快递单号:");
String number = input.nextLine();
System.out.println("请输入新的快递公司:");
String company = input.nextLine();
m.setCompany(company);
m.setNumber(number);
}
public int delete(){
System.out.println("是否确认删除?\n 1.确认删除\n 2.取消操作");
String number = input.nextLine();
int num = -1;
try{
num = Integer.parseInt(number);
}catch (NumberFormatException e){
}
if(num<1||num>2){
System.out.println("输入有误,请重新输入");
return delete();
}
return num;
}
public void printAll(Collection<Model>ms){
int count = 0;
for (Model m:ms) {
count++;
System.out.println("第"+(m.posX+1)+"排"+(m.posY+1)+"列");
print(m);
}
if(count==0){
System.out.println("暂无快递信息!");
}
}
public int userMenu(){
System.out.println("请根据提示,进行取件");
System.out.println("请输入您的取件码:");
String code = input.nextLine();
int num = -1;
try{
num = Integer.parseInt(code);
}catch (NumberFormatException e){
}
if(num<100000||num>999999){
System.out.println("输入有误,请重新输入");
return userMenu();
}
return num;
}
public void success(){
System.out.println("操作成功!");
}
public void exist(){
System.out.println("此快递单号已存在!");
}
public void printNull(){
System.out.println("暂无快递!");
}
}
第三步:
数据处理层Controller
public class Controller {
boolean[][] cabinet = new boolean[10][10];
HashMap<Integer,Model> data = new HashMap<>();
Collection<Model> models = data.values();
private int size;
private Random r = new Random();
public boolean add(Model m,boolean[][] cabinet,HashMap<Integer,Model>data){
int size = data.size();
if(size>=100){
System.out.println("快递柜已满,不能存储快递!");
return false;
}
int x = -1;
int y = -1;
while(true){
x = r.nextInt(10);
y = r.nextInt(10);
if(cabinet[x][y]==false){
break;
}
}
int code = randomCode(data.values());
m.setCode(code);
m.posX = x;
m.posY = y;
cabinet[x][y] = true;
data.put(code,m);
return true;
}
public int randomCode(Collection<Model> models){
while(true){
int code = r.nextInt(900000)+100000;
Model m = findByCode(code,models);
if(m==null){
return code;
}
}
}
public Model findByCode(int code,Collection<Model>models){
for (Model m:models) {
if(m.getCode()==code){
return m;
}
}
return null;
}
public Model findByNumber(String number,Collection<Model>models){
for (Model m:models) {
if(m.getNumber().equals(number)){
return m;
}
}
return null;
}
public void update(Model oldModel,Model newModel,boolean[][] cabinet,HashMap<Integer,Model>data){
delete(oldModel,cabinet,data);
add(newModel,cabinet,data);
}
public void delete(Model m,boolean[][] cabinet,HashMap<Integer,Model>data) {
data.remove(m.getCode());
cabinet[m.posX][m.posY] = false;
size--;
}
public Collection<Model> findAll(){
return models;
}
}
第四步:
main函数:
public class Main {
private static View view = new View();
private static Controller controller = new Controller();
private int size;//当前存储的快递数目(后边用于判断是否有空位置)
public static void main(String[] args) throws IOException {
view.welcome();
/**
* 初始化数据结构
* 将需要用到的数据对象,作为main方法中的变量
*/
boolean[][] cabinet = new boolean[10][10];//二维数组表示快递柜位置
HashMap<Integer,Model> data;//HashMap存放取件码(Integer)和快递对象
Collection<Model> models;//存放所有的快递对象,为后边遍历
/**
* 向文件里传入对象 ObjectInputStream
* read.Object()
*/
//反序列化获得快递柜中存储的对象HashMap<Integer,Model>data
try(FileInputStream fis = new FileInputStream("TEXT.txt")){
ObjectInputStream ois = new ObjectInputStream(fis);
data = (HashMap<Integer,Model>) ois.readObject();
ois.close();//关闭输入流
} catch (IOException | ClassNotFoundException e) {
data = new HashMap<>();//打开文件异常时,将data初始化为空,在main函数结束时进行序列化
}
//初始化数据结构 所有快递对象
models = data.values();
for (Model m:models) {
cabinet[m.posX][m.posY] = true;
}
m:while(true){
int menu = view.menu();
switch(menu){
case 0:
break m;
/**
* 展示功能,将数据结构作为参数传进去,便于对数据进行处理
*/
case 1:
cClient(data.size(),cabinet,data);
break ;
case 2:
uClient(data.size(),cabinet,data);
break ;
}
}
/**
* 序列化存储对象HashMap<Integer,Model>data
* 将对象写入到文件中
*/
FileOutputStream fos = new FileOutputStream("TEXT.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(data);
oos.close();
view.bye();
}
private static void cClient(int size,boolean[][] cabinet,HashMap<Integer,Model> data) {
while(true){
int menu = view.cMenu();
switch(menu){
case 0:
return;
case 1:{
Model m = view.insert();
Model m2 = controller.findByNumber(m.getNumber(),data.values());
if(m2==null){
controller.add(m,cabinet,data);
view.print(m);
}
else{
view.exist();
}
}
break;
case 2:{
String number = view.findByNumber();
Model m = controller.findByNumber(number,data.values());
Model m2 = m;
if(m==null){
view.printNull();
}else{
view.print(m);
view.update(m2);
controller.update(m,m2,cabinet,data);
view.print(m2);
}
}
break;
case 3:{
String number = view.findByNumber();
Model m = controller.findByNumber(number,data.values());
if(m==null){
view.printNull();
}else{
view.print(m);
int type = view.delete();
if(type==1){
controller.delete(m,cabinet,data);
view.success();
}
}
}
break;
case 4:{
view.printAll(data.values());
}
break;
}
}
}
public static void uClient(int size,boolean[][] cabinet,HashMap<Integer,Model>data){
Collection<Model> models = data.values();
int code = view.userMenu();
Model m = controller.findByCode(code,models);
if(m==null){
view.printNull();
}else{
view.success();
view.print(m);
controller.delete(m,cabinet,data);
}
}
}
结论:
生成了TEXT.txt文件