快递管理控制台简易版——加入多线程与网络编程(完整版,附完整源码)(Java)

文章目录


数组存储版可参考文章:快递管理控制台简易版——数组存储版(Java)

List集合存储版可参考文章:快递管理控制台简易版——List集合存储版(Java)

Map集合存储版可参考文章:快递管理控制台简易版——Map集合存储版(Java)

基于Map集合存储版使用IO技术实现数据存储可参考文章:快递管理控制台简易版——IO流的使用(Java)

  • 数组存储版采用二维数组对快递进行存储,快递位置对应二维数组的两个下标

  • List集合存储版采用List集合对快递进行存储

  • Map集合存储版采用Map集合对快递进行存储,用Map集合进行存储的优势在于,Map是键-值(key-value)对,key为快递单号,value 为快递对象,保证快递单号唯一

  • IO流的使用 以Map集合存储版为基础进行优化,使用IO技术将快递数据存储到文件中,并从文件中读取数据,文件存储快递信息后,可以在每次启动应用时读取文件中的内容,从而实现程序数据的一直存在

  • 关于多线程和网络编程加入了多线程和网络编程技术,实现客户端和服务器的数据交互,并且使用多线程,使得每一个用户发送登录请求到服务器后,服务器端就分配一个线程去处理这个请求
    tips:本文仅仅涉及到如何加入多线程和运用网络编程技术,不涉及完整的控制台操作


具体需求

  1. 实现基于网络编程模式下的用户登录功能,要求:
    (1)用户包含管理员和普通用户两个角色进行测试
    管理员用户名:admin,密码:abc 普通用户名:user 密码:123
    (2)用户从客户端发起登录请求,客户端将数据传递到服务器端,
    由服务器做验证。服务器端保存用户数据,用户登录成功提示登录成功
    并显示功能模块,登录失败提示:用户名或密码不正确
  2. 基于上一个练习,了解客户端和服务器端的概念,客户端用来获取用户信息,服务器端用于进行数据存储和逻辑判断
    在网络编程的基础上,在服务器端启用多线程模式,要求每一个用户发送登录请求到服务器后,服务器端就分配一个线程去处理这个请求,以实现服务器端多线程模式下的用户登录

涉及知识点

  1. 面向对象
  2. 集合
  3. IO
  4. 多线程
  5. 网络编程

思路及代码实现

一、 自定义异常

创建一个exception包,新建类OutNumberBoundException

OutNumberBoundException

public class OutNumberBoundException extends Throwable {
    public OutNumberBoundException(String s) {
        super(s);
    }
}

二、 工具包

创建一个util包,新建类IOUtil

IOUtil

文件读写工具类,因此方法都推荐静态static

  • 从指定文件中读数据
public static Object readFile(String fileName) throws IOException, ClassNotFoundException {
        FileInputStream fis = new FileInputStream(fileName);//指定文件
        ObjectInputStream ois = new ObjectInputStream(fis);
        return ois.readObject();//读出数据
    }
  • 写入数据到指定文件
 public static void writeFile(Object obj,String fileName) throws IOException {
        FileOutputStream fos = new FileOutputStream(fileName);//指定文件
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(obj);//写入数据obj
    }

三、 对象

创建一个pojo包,新建类Express

Express

  • 定义属性并用setter和getter设置和获取值
	private String number;//快递单号
    private String company;//公司
    private int code;//取件码
    private int x;
    private int y;
    
	 /**
     * 使用setter和getter设置和获取值
     */
    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 int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }
  • 定义无参和全参构造方法
/**
     * 定义无参构造方法
     */
    public Express() {
    }

    /**
     * 定义全参构造方法
     */
    public Express(String number, String company, int code, int x, int y) {
        this.number = number;
        this.company = company;
        this.code = code;
        this.x = x;
        this.y = y;
    }
  • 重写toString将信息转换为字符串
    /**
     * toString将信息转化为字符串形式
     */
    @Override
    public String toString() {
        return "快递信息[" +
                "快递单号:" + getNumber() + ' ' +
                ", 快递公司:" + getCompany() + ' ' +
                ", 取件码:" + getCode() + " , 在第" + (getX() + 1) + "行 第" + (getY() + 1) + "列柜子" +
                ']';
    }

四、数据处理

创建一个dao包,新建类Dao

Dao

  • 创建文件并初始化数据
    public static final String FILE_NAME = "快递信息.txt";
    
    //静态 代码块
    static {
        File file = new File(FILE_NAME);
        if (!file.exists()){//如果文件不存在,创建文件
            try {
                if (file.createNewFile()){//创建文件名为FILE_NAME的文件
                    System.out.println("第一次启动项目,创建储存文件成功!");
                }
            } catch (IOException e) {
                System.out.println(e.getMessage());
            }
        }
    }
    
    //初始化数据
    public Dao() {
        //从文件中读取数据
        try {
            Object obj = IOUtil.readFile(FILE_NAME);
            if (obj!=null && obj instanceof List){
                expressList = (List<Express>) obj;
            }
        }catch (IOException | ClassNotFoundException e) {
            System.out.println(e.getMessage());
        }
    }
  • 添加快递
    public static Express add(Express express) throws Exception {
        Random random = new Random();
        if (expressList.size() == 100) {
            System.out.println("快递柜已存满!");
            return null;
        }
        int x, y;
        do {
            x = random.nextInt(10);
            y = random.nextInt(10);
        } while (isExist(x, y));

        int code;
        do {
            code = random.nextInt(900000) + 100000;
        } while (isExistCode(code));
        express.setCode(code);
        express.setX(x);
        express.setY(y);
        expressList.add(express);
        IOUtil.writeFile(expressList,FILE_NAME);//更新文档中的数据
        return express;
    }

  • 判断当前位置是否已存在快递
    public static boolean isExist(int x, int y) {
        for (Express express : expressList) {
            if (express.getX() == x && express.getY() == y) {
                return true;
            }
        }
        return false;
    }
  • 判断随机产生的取件码是否存在
    public static boolean isExistCode(int code) {
        for (Express express : expressList) {
            if (express.getCode() == code) {
                return true;
            }
        }
        return false;
    }
  • 删除快递
    public static boolean delete(String number) throws Exception {
        int index = findByNumber(number);
        if (index == -1) {
            return false;
        }
        expressList.remove(index);//删除快递的操作
        IOUtil.writeFile(expressList,FILE_NAME);
        return true;
    }
  • 根据快递单号查询快递
    public static int findByNumber(String number) {
        int i = 0;
        for (Express express : expressList) {
            if (number.equals(express.getNumber())) {
                return i;
            }
            i++;
        }
        return -1;
    }
  • 更新快递
    public static boolean update(String number, Express newExpress) throws Exception {
        int index = findByNumber(number);
        if (index == -1) {
            System.out.println("快递不存在!");
            return false;
        }
        Express express1 = expressList.get(index);
        express1.setNumber(newExpress.getNumber());
        express1.setCompany(newExpress.getCompany());
        IOUtil.writeFile(expressList,FILE_NAME);//数据加入
        return true;
    }
  • 获得所有快递信息
    public static List<Express> getExpressList() {
        return expressList;
    }
  • 取快递
    public Express findByCodeAndDelete(int code) throws Exception {
        Express express = findExpressByCode(code);
        if (express!=null){
            if (delete(express.getNumber())){
                return express;
            }
        }
        return null;
    }
  • 通过取件码查找快递
    public static Express findExpressByCode(int code){
        for (int i = 0;i<expressList.size();i++) {
            if (expressList.get(i).getCode() == code){
                return expressList.get(i);
            }
        }
        return null;
    }

五 、 C/S网络编程

  • 主要负责服务器与客户端之间的交互

创建一个socket包,新建类Server和Client

Server服务器

在main中创建Server对象,并且调用start方法

    public static void main(String[] args) {
        Server server = new Server();
        server.start();
    }

接下来编写start方法启动服务器:


首先创建服务器

	//端口号
    private final int PORT = 10086; 
    
    //创建一个服务器
    private ServerSocket server; 

1、 创建start方法,进行服务器的搭建运行以及客户端的连接

  • 进入服务器后等待客户端连接
    使用while循环,实现用户的多次连接
	server = new ServerSocket(PORT);//端口号传入到服务器
	System.out.println("服务器已经准备好!服务端口:" + PORT);
	//等待客户端得连接
	while (true) {//实现多用户连接,使用用while循环
		Socket client = server.accept();//连接服务器得客户端
        System.out.println("客户端" + client.hashCode() + "连接成功");//不同的hashcode表示不同的对象
    }
  • 加入多线程,使用匿名内部类
	//为每个客户单独开一个线程处理请求
	new Thread(new Runnable() {
		@Override
		public void run() {
        //客户端得请求   接受客户端得请求  读数据 -- 处理完毕之后将结果相应给客户端 ---写数据到客户端
        	try {
            	init(client);//用户的方法  方法里包括了序列化和反序列化
            } catch (IOException|Exception e) {
            	e.printStackTrace();
            } 
        }
     }).start();

start()方法完整代码如下:

    //开启一个线程 服务端开启的方法
    public void start() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    server = new ServerSocket(PORT);//端口号传入到服务器
                    System.out.println("服务器已经准备好!服务端口:" + PORT);
                    //等待客户端得连接
                    while (true) {//实现多用户连接,使用用while循环
                        Socket client = server.accept();//连接服务器得客户端
                        System.out.println("客户端" + client.hashCode() + "连接成功");//不同的hashcode表示不同的对象
                        //为每个客户单独开一个线程处理请求
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                //客户端得请求   接受客户端得请求  读数据 -- 处理完毕之后将结果相应给客户端 ---写数据到客户端
                                try {
                                    init(client);//用户的方法  方法里包括了序列化和反序列化
                                } catch (IOException|Exception  e) {
                                    e.printStackTrace();
                                }
                            }
                        }).start();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

2、 编写任务run中的init方法实现与客户端数据的交互

  • 收消息
        InputStream is = null;
        ObjectInputStream in = null;
  • 发消息
        OutputStream os = null;
        ObjectOutputStream out = null;
  • 获取流对象
		is = client.getInputStream();
    	os = client.getOutputStream();
   		out = new ObjectOutputStream(os);
    	in = new ObjectInputStream(is);
  • 进入系统
       System.out.println("用户得请求类型" + flag + "线程" + Thread.currentThread().getName() + "为你服务!");
  • 获取用户的具体操作
		String flag = in.readUTF();
		System.out.println(flag);
    • 添加快递
                    //获取客户端发布的参数
                    Express express = (Express) in.readObject();
                    express = dao.add(express);
                    out.writeObject(express);
    • 删除快递
                    String number = in.readUTF();
                    boolean res = dao.delete(number);
                    out.writeObject(res);
    • 修改快递
                    String number =in.readUTF();//旧数据
                    Express newExpress = (Express) in.readObject();
                    boolean res = dao.update(number, newExpress);
    • 打印所有快递
                	//在服务器端打印当前快递存储信息
                    System.out.println("-----------------------------------执行findadll");
                    List<Express> expressList = dao.getExpressList();
                    //获取处理结果 返回给客户端写数据
                    if (expressList != null && expressList.size() != 0) {
                        System.out.println("----------------当前快递信息如下,准备发给客户端---------------------------");
                        for (Express express : expressList) {//遍历
                            System.out.println("--" + express);
                        }
                        out.reset();
                        out.writeObject(expressList);
                        System.out.println("发送成功!");
                    } else
                        out.writeObject("快递柜中暂时没有任何快递");
                        out.flush();
    • 取件
                    Integer code = in.readInt();
                    Express res = dao.findByCodeAndDelete(code);
                    System.out.println("res:"+res);
                    out.writeObject(res);
  • 关闭流
		if (in != null) {
			in.close();
			}
        if (out != null) {
            out.close();
        }

init方法的完整代码如下:

	//接受客户端得请求  读数据 -- 处理完毕之后将结果相应给客户端 ---写数据到客户端
    public void init(Socket client) throws Exception {
        OutputStream os = null;
        ObjectOutputStream out = null;
        InputStream is = null;
        ObjectInputStream in = null;

        //获取流对象
        try {
            is = client.getInputStream();
            os = client.getOutputStream();
            out = new ObjectOutputStream(os);
            in = new ObjectInputStream(is);
            //获取客户端得发送得请求类型
            while (true) {
                System.out.println("用户得请求类型" + flag + "线程" + Thread.currentThread().getName() + "为你服务!");
                
                String flag = in.readUTF();
                System.out.println(flag);
                if ("printAll".equals(flag)) {
                	//在服务器端打印当前快递存储信息
                    System.out.println("-----------------------------------执行findadll");
                    List<Express> expressList = dao.getExpressList();
                    //获取处理结果 返回给客户端写数据
                    if (expressList != null && expressList.size() != 0) {
                        System.out.println("----------------当前快递信息如下,准备发给客户端---------------------------");
                        for (Express express : expressList) {//遍历
                            System.out.println("--" + express);
                        }
                        out.reset();
                        out.writeObject(expressList);
                        System.out.println("发送成功!");
                    } else
                        out.writeObject("快递柜中暂时没有任何快递");
                        out.flush();
                    continue;
                } else if ("insert".equals(flag)) {
                    //获取客户端发布的参数
                    Express express = (Express) in.readObject();
                    express = dao.add(express);
                    out.writeObject(express);
                    continue;
                } else if ("update".equals(flag)) {
                    String number =in.readUTF();//旧数据
                    Express newExpress = (Express) in.readObject();
                    boolean res = dao.update(number, newExpress);
                    out.writeObject(res);
                    continue;
                } else if ("delete".equals(flag)) {
                    String number = in.readUTF();
                    boolean res = dao.delete(number);
                    out.writeObject(res);
                    continue;
                } else if ("findByCode".equals(flag)) {//取件 先查询后删除
                    Integer code = in.readInt();
                    Express res = dao.findByCodeAndDelete(code);
                    System.out.println("res:"+res);
                    out.writeObject(res);
                    continue;
                } else {
                    out.writeObject("你的请求服务器暂时处理不了");
                    continue;
                }
            }//end while
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }//end void

Client客户端

在main中创建Client对象,并且调用start方法实现用户连接服务器

    public static void main(String[] args) {
        Client c = new Client();
        c.start();
    }

首先创建客户端

    private final int PORT = 10086;//客户端要链接的端口号
    
    private Socket client;//客户端

1、创建start方法,运行客户端,连接服务器

  • 收消息
        InputStream is = null;
        ObjectInputStream in = null;
  • 发消息
        OutputStream os = null;
        ObjectOutputStream out = null;
  • 连接服务器
            do {
                if (client == null || client.isClosed()) {
                    client = new Socket("127.8.0.1", PORT);
                    in = client.getInputStream();
                    out = client.getOutputStream();
                    objectOutputStream = new ObjectOutputStream(out);
                    objectInputStream = new ObjectInputStream(in);
                    System.out.println("客户端连接服务器成功!");
                }
            } while (mainMenu(objectInputStream, objectOutputStream) != 0);
  • 退出系统,关闭流
		if (objectInputStream != null) {
			objectInputStream.close();
		}
	    if (objectOutputStream != null) {
			objectOutputStream.close();
	    }
		if (client != null) {
			client.close();
		}

start完整方法如下:

    //客户端启动的方法
    public void start() {
        OutputStream out = null;
        ObjectOutputStream objectOutputStream = null;
        InputStream in = null;
        ObjectInputStream objectInputStream = null;
        //获取流对象
        try {
            do {
                if (client == null || client.isClosed()) {
                    client = new Socket("127.8.0.1", PORT);
                    in = client.getInputStream();
                    out = client.getOutputStream();
                    objectOutputStream = new ObjectOutputStream(out);
                    objectInputStream = new ObjectInputStream(in);
                    System.out.println("客户端连接服务器成功!");
                }
            } while (mainMenu(objectInputStream, objectOutputStream) != 0);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } catch (OutNumberBoundException e) {
            e.printStackTrace();
        } finally {//关闭流
            try {
                if (objectInputStream != null) {
                    objectInputStream.close();
                }
                if (objectOutputStream != null) {
                    objectOutputStream.close();
                }
                if (client != null) {
                    client.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }//end finally
    }//end void start

2、 主菜单

    public static int mainMenu(ObjectInputStream in, ObjectOutputStream out) throws OutNumberBoundException, Exception {
        int mainNum = 0;
        do{
            System.out.println("----------欢迎使用快递管理系统----------");
            System.out.println("请选择您的身份:");
            System.out.println("1.管理员");
            System.out.println("2.普通用户");
            System.out.println("0.退出");
            String s = input.nextLine();
            try{
                mainNum = validNum(s,0,2);
                break;
            }catch(NumberFormatException | OutNumberBoundException e){
                System.out.println(e.getMessage());
            }
        }while(true);
        switch(mainNum){
            case 0://结束使用
                System.out.println("感谢使用快递管理系统!");
                break ;
            case 1://进入管理员平台
                managerPlatform(in,out);
                break ;
            case 2://进入用户平台
                userPlatform(in,out);
                break ;
        }
        return mainNum;
    }//end mainMenu()
  • 判断输入是否为有效数字
    private static int validNum(String s,int begin,int end) throws NumberFormatException, OutNumberBoundException {
        try{
            int num = Integer.parseInt(s);
            if (num < begin || num > end){
                throw new OutNumberBoundException("数字的范围必须在" + begin + "和" + end +"之间");
            }
            return num;
        }catch(NumberFormatException | OutNumberBoundException e){
            throw new NumberFormatException("输入的必须是数字!");
        }
    }

2.1 管理员界面

    public static void managerPlatform(ObjectInputStream in, ObjectOutputStream out) throws OutNumberBoundException, Exception{
        w:while(true){
            int managerNum = 0;
            do{
                System.out.println("尊敬的管理员,您好!");
                System.out.println("请选择您要进行的操作:");
                System.out.println("1.录入快递");
                System.out.println("2.删除快递");
                System.out.println("3.修改快递");
                System.out.println("4.查看所有快递");
                System.out.println("0.返回上一级界面");
                String s = input.nextLine();
                try{
                    managerNum = validNum(s,0,4);
                    break;
                }catch(NumberFormatException | OutNumberBoundException e){
                    System.out.println(e.getMessage());
                }
            }while(true);
            switch(managerNum){
                case 0:{//返回上一级页面
                    return;
                }
                case 1:{//1.录入快递
                    insert(in,out);
                }
                break w;
                case 2:{//2.删除快递
                    delete(in,out);
                }
                break w;
                case 3:{//3.修改快递
                    update(in,out);
                }
                break w;
                case 4:{//4.查看所有快递
                    printAll(in,out);
                }
                break w;
            }// end switch
        }//end while
    }//end managerPlatform

  • 添加快递
    private static void insert(ObjectInputStream in, ObjectOutputStream out) {
        System.out.println("---------存快递----------");
        Express express = new Express();
        System.out.print("请输入快递单号:");
        express.setNumber(input.nextLine());
        System.out.print("请输入快递公司:");
        express.setCompany(input.nextLine());
        //当前快递单号不存在,存快递
        if(Server.dao.findByNumber(express.getNumber()) == -1){
            try {
                out.writeUTF("insert");
                out.writeObject(express);
                out.flush();
                //接受服务器端的响应---读数据
                Object object = in.readObject();
                if (object instanceof Express) {
                    express = (Express) object;
                    System.out.println("添加成功!快递在第" + (express.getX() + 1) + "排,第" + (express.getY() + 1) + "列");
                } else {
                    System.out.println("添加失败" + object);
                }
            } catch (Exception exception) {
                System.out.println("系统异常,添加失败!");
                System.out.println(exception.getMessage());
            }
        }else{
            System.out.println("该快递单号已存在!快递添加失败!");
        }
    }
  • 删除快递
    private static void delete(ObjectInputStream in, ObjectOutputStream out) {
        System.out.println("删除快递");
        System.out.print("请输入要删除的快递单号:");
        String number = input.nextLine();
        int exist = Server.dao.findByNumber(number);
        if (exist == -1) {
            System.out.println("快递不存在!");
        } else {
            int deleteNum;
            do {
                System.out.println("是否进行删除操作?");
                System.out.println("1.确认删除");
                System.out.println("0.取消操作");
                String s = input.nextLine();
                deleteNum = -1;
                try {
                    deleteNum = validNum(s, 0, 1);
                    break;
                } catch (NumberFormatException | OutNumberBoundException e) {
                    System.out.println(e.getMessage());
                }
            } while (true);
            if (deleteNum == 0) {
                System.out.println("取消删除成功!");
            } else {
                try {
                    out.writeUTF("delete");
                    out.writeUTF(number);
                    out.flush();
                    Object obj = in.readObject();
                    if (obj instanceof Boolean) {
                        boolean res = (boolean) obj;
                        if (res == true) {
                            System.out.println("删除成功");
                        } else {
                            System.out.println("删除失败");
                        }
                    } else {
                        System.out.println("删除失败!!!!!!");
                    }
                } catch (Exception e) {
                    System.out.println("系统异常,删除失败!");
                    System.out.println(e.getMessage());
                }
            }// end else  option of delete
        }//end else express exist
    }//end method
  • 修改快递
    private static void update(ObjectInputStream in, ObjectOutputStream out) {
        System.out.println("---------修改快递-----------");
        System.out.print("请输入要修改的快递单号:");
        String number = input.nextLine();
        int exist = Server.dao.findByNumber(number);
        if(exist == -1){
            System.out.println("快递不存在!");
        }else{
            Express newExpress = new Express();
            System.out.print("请输入新的快递单号:");
            newExpress.setNumber(input.nextLine());
            System.out.print("请输入新的公司名称:");
            newExpress.setCompany(input.nextLine());
            try {
                out.writeUTF("update");
                out.flush();
                out.writeUTF(number);
                out.flush();
                out.writeObject(newExpress);
                out.flush();
                Object obj = in.readObject();
                if (obj instanceof Boolean) {
                    boolean res = (boolean) obj;
                    if (res == true) {
                        System.out.println("更新成功!");
                    } else {
                        System.out.println("更新失败!");
                    }
                } else{
                    System.out.println("更新失败!!!!!!");
                }
            } catch (Exception e) {
                System.out.println("系统异常,更新失败!");
                System.out.println(e.getMessage());
            }
        }// end else(option of exist then update)
    }//end update method
  • 打印所有快递
    public static void printAll(ObjectInputStream in, ObjectOutputStream out) throws IOException, ClassNotFoundException {
        System.out.println("--------当前快递存储情况---------");
        out.writeUTF("printAll");//与Server相对应,发送给服务器请求类型
        out.flush();
        Object obj = in.readObject();
        if (obj instanceof List) {
            List<Express> expressList = (List<Express>) obj;//强转
            for (Express express : expressList) {//遍历输出
                System.out.println(express);
            }
        }else {
            System.out.println(obj);
        }
    }

2.2 用户界面

  • 取件
    public static void userPlatform(ObjectInputStream in, ObjectOutputStream out) throws OutNumberBoundException, Exception {
        int code = -1;
        do {
            System.out.print("请输入取件码:");
            String s = input.nextLine();
            try {
                code = validNum(s, 100000, 999999);
                break;
            } catch (NumberFormatException | OutNumberBoundException e) {
                System.out.println(e.getMessage());
            }
        } while (true);
        out.writeUTF("findByCode");
        out.writeInt(code);
        out.flush();
        Object obj = in.readObject();
        if (obj instanceof Express) {
            Express e = (Express) obj;
            System.out.println("快递信息:" + e);
            System.out.println("您的快递存储在快递柜的第" + (e.getX() + 1) + "排,第" + (e.getY() + 1) + "列,取件愉快~");

        } else {
            System.out.println("快递不存在,取件失败!");
        }
    }

完整代码

一、自定义异常

OutNumberBoundException

public class OutNumberBoundException extends Throwable {
    public OutNumberBoundException(String s) {
        super(s);
    }
}

二、 工具包

IOUtil

/**
 * 文件读写技术
 *
 */
public class IOUtil {
    /**
     * 从指定的文件中读取数据
     * Reader
     * InputStream
     */
    public static Object readFile(String fileName) throws IOException, ClassNotFoundException {
        FileInputStream fis = new FileInputStream(fileName);//指定文件
        ObjectInputStream ois = new ObjectInputStream(fis);
        return ois.readObject();//读出数据
    }

    /**
     * 写入数据到指定文件
     * Writer
     * OutputStream
     */
    public static void writeFile(Object obj,String fileName) throws IOException {
        FileOutputStream fos = new FileOutputStream(fileName);//指定文件
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(obj);//写入数据obj
    }

}

三、 对象

Express

public class Express implements Serializable {
    private String number;//快递单号
    private String company;//公司
    private int code;//取件码
    private int x;
    private int y;

    /**
     * 定义无参构造方法
     */
    public Express() {
    }

    /**
     * 定义全参构造方法
     */
    public Express(String number, String company, int code, int x, int y) {
        this.number = number;
        this.company = company;
        this.code = code;
        this.x = x;
        this.y = y;
    }

    /**
     * 使用setter和getter设置和获取值
     */
    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 int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    /**
     * toString将信息转化为字符串形式
     */
    @Override
    public String toString() {
        return "快递信息[" +
                "快递单号:" + getNumber() + ' ' +
                ", 快递公司:" + getCompany() + ' ' +
                ", 取件码:" + getCode() + " , 在第" + (getX() + 1) + "行 第" + (getY() + 1) + "列柜子" +
                ']';
    }
}

四、 数据处理

Dao

public class Dao {
    //链表的初始设置
    private static List<Express> expressList = new ArrayList<>(100);
    //存储快递的文件名
    public static final String FILE_NAME = "快递信息.txt";

    //静态 代码块
    static {
        File file = new File(FILE_NAME);
        if (!file.exists()){//如果文件不存在,创建文件
            try {
                if (file.createNewFile()){//创建文件名为FILE_NAME的文件
                    System.out.println("第一次启动项目,创建储存文件成功!");
                }
            } catch (IOException e) {
                System.out.println(e.getMessage());
            }
        }
    }
    
    //初始化数据
    public Dao() {
        //从文件中读取数据
        try {
            Object obj = IOUtil.readFile(FILE_NAME);
            if (obj!=null && obj instanceof List){
                expressList = (List<Express>) obj;
            }
        }catch (IOException | ClassNotFoundException e) {
            System.out.println(e.getMessage());
        }
    }


    /**
     * 获得快递的所有信息
     * @return
     */
    public static List<Express> getExpressList() {
        return expressList;
    }


    /**
     * 添加快递
     * @param express
     * @return
     * @throws Exception
     */
    public static Express add(Express express) throws Exception {
        Random random = new Random();
        if (expressList.size() == 100) {
            System.out.println("快递柜已存满!");
            return null;
        }
        int x, y;
        do {
            x = random.nextInt(10);
            y = random.nextInt(10);
        } while (isExist(x, y));

        int code;
        do {
            code = random.nextInt(900000) + 100000;
        } while (isExistCode(code));
        express.setCode(code);
        express.setX(x);
        express.setY(y);
        expressList.add(express);
        IOUtil.writeFile(expressList,FILE_NAME);//更新文档中的数据
        return express;
    }


    /**
     * 添加快递中,判断当前位置是否已经存在快递
     * @param x
     * @param y
     * @return
     */
    public static boolean isExist(int x, int y) {
        for (Express express : expressList) {
            if (express.getX() == x && express.getY() == y) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断取件码是否已经存在
     * @param code
     * @return
     */
    public static boolean isExistCode(int code) {
        for (Express express : expressList) {
            if (express.getCode() == code) {
                return true;
            }
        }
        return false;
    }

    /**
     * 根据快递单号查找快递,如果不存在返回-1
     * @param number
     * @return
     */
    public static int findByNumber(String number) {
        int i = 0;
        for (Express express : expressList) {
            if (number.equals(express.getNumber())) {
                return i;
            }
            i++;
        }
        return -1;
    }


    /**
     * 删除快递
     * @param number
     * @return
     * @throws Exception
     */
    public static boolean delete(String number) throws Exception {
        int index = findByNumber(number);
        if (index == -1) {
            return false;
        }
        expressList.remove(index);//删除快递的操作
        IOUtil.writeFile(expressList,FILE_NAME);
        return true;
    }


    /**
     * 更新快递
     * @param number
     * @param newExpress
     * @return
     * @throws Exception
     */
    public static boolean update(String number, Express newExpress) throws Exception {
        int index = findByNumber(number);
        if (index == -1) {
            System.out.println("快递不存在!");
            return false;
        }
        Express express1 = expressList.get(index);
        express1.setNumber(newExpress.getNumber());
        express1.setCompany(newExpress.getCompany());
        IOUtil.writeFile(expressList,FILE_NAME);//数据加入
        return true;
    }

    /**
     * 通过取件码查找快递
     * @param code
     * @return
     */
    public static Express findExpressByCode(int code){
        for (int i = 0;i<expressList.size();i++) {
            if (expressList.get(i).getCode() == code){
                return expressList.get(i);
            }
        }
        return null;
    }

    /**
     * 取件,删除快递
     * @param code
     * @return
     * @throws IOException
     */
    public Express findByCodeAndDelete(int code) throws Exception {
        Express express = findExpressByCode(code);
        if (express!=null){
            if (delete(express.getNumber())){
                return express;
            }
        }
        return null;
    }
}

五、 C/S网络编程

Server

public class Server {
    public static Dao dao = new Dao();
    public static void main(String[] args) {
        Server server = new Server();
        server.start();
    }

    private final int PORT = 10086; //端口号

    private ServerSocket server; //建立一个服务器

    //开启一个线程 服务端开启的方法
    public void start() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    server = new ServerSocket(PORT);//端口号传入到服务器
                    System.out.println("服务器已经准备好!服务端口:" + PORT);
                    //等待客户端得连接
                    while (true) {//实现多用户连接,使用用while循环
                        Socket client = server.accept();//连接服务器得客户端
                        System.out.println("客户端" + client.hashCode() + "连接成功");//不同的hashcode表示不同的对象
                        //为每个客户单独开一个线程处理请求
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                //客户端得请求   接受客户端得请求  读数据 -- 处理完毕之后将结果相应给客户端 ---写数据到客户端
                                try {
                                    init(client);//用户的方法  方法里包括了序列化和反序列化
                                } catch (IOException|Exception  e) {
                                    e.printStackTrace();
                                }
                            }
                        }).start();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

	//接受客户端得请求  读数据 -- 处理完毕之后将结果相应给客户端 ---写数据到客户端
    public void init(Socket client) throws Exception {
        OutputStream os = null;
        ObjectOutputStream out = null;
        InputStream is = null;
        ObjectInputStream in = null;

        //获取流对象
        try {
            is = client.getInputStream();
            os = client.getOutputStream();
            out = new ObjectOutputStream(os);
            in = new ObjectInputStream(is);
            //获取客户端得发送得请求类型
            while (true) {
                System.out.println("用户得请求类型" + flag + "线程" + Thread.currentThread().getName() + "为你服务!");
                
                String flag = in.readUTF();
                System.out.println(flag);
                if ("printAll".equals(flag)) {
                	//在服务器端打印当前快递存储信息
                    System.out.println("-----------------------------------执行findadll");
                    List<Express> expressList = dao.getExpressList();
                    //获取处理结果 返回给客户端写数据
                    if (expressList != null && expressList.size() != 0) {
                        System.out.println("----------------当前快递信息如下,准备发给客户端---------------------------");
                        for (Express express : expressList) {//遍历
                            System.out.println("--" + express);
                        }
                        out.reset();
                        out.writeObject(expressList);
                        System.out.println("发送成功!");
                    } else
                        out.writeObject("快递柜中暂时没有任何快递");
                        out.flush();
                    continue;
                } else if ("insert".equals(flag)) {
                    //获取客户端发布的参数
                    Express express = (Express) in.readObject();
                    express = dao.add(express);
                    out.writeObject(express);
                    continue;
                } else if ("update".equals(flag)) {
                    String number =in.readUTF();//旧数据
                    Express newExpress = (Express) in.readObject();
                    boolean res = dao.update(number, newExpress);
                    out.writeObject(res);
                    continue;
                } else if ("delete".equals(flag)) {
                    String number = in.readUTF();
                    boolean res = dao.delete(number);
                    out.writeObject(res);
                    continue;
                } else if ("findByCode".equals(flag)) {//取件 先查询后删除
                    Integer code = in.readInt();
                    Express res = dao.findByCodeAndDelete(code);
                    System.out.println("res:"+res);
                    out.writeObject(res);
                    continue;
                } else {
                    out.writeObject("你的请求服务器暂时处理不了");
                    continue;
                }
            }//end while
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }//end void

}

Client

public class Client {
    private static Scanner input = new Scanner(System.in);
    private Express express = new Express();
    private final int PORT = 10086;//客户端要链接的端口号
    private Socket client;//客户端

    public static void main(String[] args) {
        Client c = new Client();
        c.start();
    }
  
    //客户端启动的方法
    public void start() {
        OutputStream out = null;
        ObjectOutputStream objectOutputStream = null;
        InputStream in = null;
        ObjectInputStream objectInputStream = null;
        //获取流对象
        try {
            do {
                if (client == null || client.isClosed()) {
                    client = new Socket("127.8.0.1", PORT);
                    in = client.getInputStream();
                    out = client.getOutputStream();
                    objectOutputStream = new ObjectOutputStream(out);
                    objectInputStream = new ObjectInputStream(in);
                    System.out.println("客户端连接服务器成功!");
                }
            } while (mainMenu(objectInputStream, objectOutputStream) != 0);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } catch (OutNumberBoundException e) {
            e.printStackTrace();
        } finally {//关闭流
            try {
                if (objectInputStream != null) {
                    objectInputStream.close();
                }
                if (objectOutputStream != null) {
                    objectOutputStream.close();
                }
                if (client != null) {
                    client.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }//end finally
    }//end void start
    
    /**
     * 主菜单,系统界面
     * @return
     */
    public static int mainMenu(ObjectInputStream in, ObjectOutputStream out) throws OutNumberBoundException, Exception {
        int mainNum = 0;
        do{
            System.out.println("----------欢迎使用快递管理系统----------");
            System.out.println("请选择您的身份:");
            System.out.println("1.管理员");
            System.out.println("2.普通用户");
            System.out.println("0.退出");
            String s = input.nextLine();
            try{
                mainNum = validNum(s,0,2);
                break;
            }catch(NumberFormatException | OutNumberBoundException e){
                System.out.println(e.getMessage());
            }
        }while(true);
        switch(mainNum){
            case 0://结束使用
                System.out.println("感谢使用快递管理系统!");
                break ;
            case 1://进入管理员平台
                managerPlatform(in,out);
                break ;
            case 2://进入用户平台
                userPlatform(in,out);
                break ;
        }
        return mainNum;
    }//end mainMenu()

    /**
     * 判断输入是否为数字、是否在有效范围内
     * @param s
     * @param begin
     * @param end
     * @return
     * @throws NumberFormatException
     */
    private static int validNum(String s,int begin,int end) throws NumberFormatException, OutNumberBoundException {
        try{
            int num = Integer.parseInt(s);
            if (num < begin || num > end){
                throw new OutNumberBoundException("数字的范围必须在" + begin + "和" + end +"之间");
            }
            return num;
        }catch(NumberFormatException | OutNumberBoundException e){
            throw new NumberFormatException("输入的必须是数字!");
        }
    }


    /**
     * 管理员操作界面
     * @param in
     * @param out
     * @throws OutNumberBoundException
     * @throws Exception
     */
    public static void managerPlatform(ObjectInputStream in, ObjectOutputStream out) throws OutNumberBoundException, Exception{
        w:while(true){
            int managerNum = 0;
            do{
                System.out.println("尊敬的管理员,您好!");
                System.out.println("请选择您要进行的操作:");
                System.out.println("1.录入快递");
                System.out.println("2.删除快递");
                System.out.println("3.修改快递");
                System.out.println("4.查看所有快递");
                System.out.println("0.返回上一级界面");
                String s = input.nextLine();
                try{
                    managerNum = validNum(s,0,4);
                    break;
                }catch(NumberFormatException | OutNumberBoundException e){
                    System.out.println(e.getMessage());
                }
            }while(true);
            switch(managerNum){
                case 0:{//返回上一级页面
                    return;
                }
                case 1:{//1.录入快递
                    insert(in,out);
                }
                break w;
                case 2:{//2.删除快递
                    delete(in,out);
                }
                break w;
                case 3:{//3.修改快递
                    update(in,out);
                }
                break w;
                case 4:{//4.查看所有快递
                    printAll(in,out);
                }
                break w;
            }// end switch
        }//end while
    }//end managerPlatform


    /**
     * 打印所有快递
     * @param in
     * @param out
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public static void printAll(ObjectInputStream in, ObjectOutputStream out) throws IOException, ClassNotFoundException {
        System.out.println("--------当前快递存储情况---------");
        out.writeUTF("printAll");//与Server相对应,发送给服务器请求类型
        out.flush();
        Object obj = in.readObject();
        if (obj instanceof List) {
            List<Express> expressList = (List<Express>) obj;//强转
            for (Express express : expressList) {//遍历输出
                System.out.println(express);
            }
        }else {
            System.out.println(obj);
        }
    }


    /**
     * 添加快递
     * @param in
     * @param out
     */
    private static void insert(ObjectInputStream in, ObjectOutputStream out) {
        System.out.println("---------存快递----------");
        Express express = new Express();
        System.out.print("请输入快递单号:");
        express.setNumber(input.nextLine());
        System.out.print("请输入快递公司:");
        express.setCompany(input.nextLine());
        //当前快递单号不存在,存快递
        if(Server.dao.findByNumber(express.getNumber()) == -1){
            try {
                out.writeUTF("insert");
                out.writeObject(express);
                out.flush();
                //接受服务器端的响应---读数据
                Object object = in.readObject();
                if (object instanceof Express) {
                    express = (Express) object;
                    System.out.println("添加成功!快递在第" + (express.getX() + 1) + "排,第" + (express.getY() + 1) + "列");
                } else {
                    System.out.println("添加失败" + object);
                }
            } catch (Exception exception) {
                System.out.println("系统异常,添加失败!");
                System.out.println(exception.getMessage());
            }
        }else{
            System.out.println("该快递单号已存在!快递添加失败!");
        }
    }


    /**
     * 删除快递
     * @param in
     * @param out
     */
    private static void delete(ObjectInputStream in, ObjectOutputStream out) {
        System.out.println("删除快递");
        System.out.print("请输入要删除的快递单号:");
        String number = input.nextLine();
        int exist = Server.dao.findByNumber(number);
        if (exist == -1) {
            System.out.println("快递不存在!");
        } else {
            int deleteNum;
            do {
                System.out.println("是否进行删除操作?");
                System.out.println("1.确认删除");
                System.out.println("0.取消操作");
                String s = input.nextLine();
                deleteNum = -1;
                try {
                    deleteNum = validNum(s, 0, 1);
                    break;
                } catch (NumberFormatException | OutNumberBoundException e) {
                    System.out.println(e.getMessage());
                }
            } while (true);
            if (deleteNum == 0) {
                System.out.println("取消删除成功!");
            } else {
                try {
                    out.writeUTF("delete");
                    out.writeUTF(number);
                    out.flush();
                    Object obj = in.readObject();
                    if (obj instanceof Boolean) {
                        boolean res = (boolean) obj;
                        if (res == true) {
                            System.out.println("删除成功");
                        } else {
                            System.out.println("删除失败");
                        }
                    } else {
                        System.out.println("删除失败!!!!!!");
                    }
                } catch (Exception e) {
                    System.out.println("系统异常,删除失败!");
                    System.out.println(e.getMessage());
                }
            }// end else  option of delete
        }//end else express exist
    }//end method


    /**
     * 更新快递
     * @param in
     * @param out
     */
    private static void update(ObjectInputStream in, ObjectOutputStream out) {
        System.out.println("---------修改快递-----------");
        System.out.print("请输入要修改的快递单号:");
        String number = input.nextLine();
        int exist = Server.dao.findByNumber(number);
        if(exist == -1){
            System.out.println("快递不存在!");
        }else{
            Express newExpress = new Express();
            System.out.print("请输入新的快递单号:");
            newExpress.setNumber(input.nextLine());
            System.out.print("请输入新的公司名称:");
            newExpress.setCompany(input.nextLine());
            try {
                out.writeUTF("update");
                out.flush();
                out.writeUTF(number);
                out.flush();
                out.writeObject(newExpress);
                out.flush();
                Object obj = in.readObject();
                if (obj instanceof Boolean) {
                    boolean res = (boolean) obj;
                    if (res == true) {
                        System.out.println("更新成功!");
                    } else {
                        System.out.println("更新失败!");
                    }
                } else{
                    System.out.println("更新失败!!!!!!");
                }
            } catch (Exception e) {
                System.out.println("系统异常,更新失败!");
                System.out.println(e.getMessage());
            }
        }// end else(option of exist then update)
    }//end update method


    /**
     * 用户操作界面
     * @throws OutNumberBoundException
     * @throws Exception
     */
    public static void userPlatform(ObjectInputStream in, ObjectOutputStream out) throws OutNumberBoundException, Exception {
        int code = -1;
        do {
            System.out.print("请输入取件码:");
            String s = input.nextLine();
            try {
                code = validNum(s, 100000, 999999);
                break;
            } catch (NumberFormatException | OutNumberBoundException e) {
                System.out.println(e.getMessage());
            }
        } while (true);
        out.writeUTF("findByCode");
        out.writeInt(code);
        out.flush();
        Object obj = in.readObject();
        if (obj instanceof Express) {
            Express e = (Express) obj;
            System.out.println("快递信息:" + e);
            System.out.println("您的快递存储在快递柜的第" + (e.getX() + 1) + "排,第" + (e.getY() + 1) + "列,取件愉快~");

        } else {
            System.out.println("快递不存在,取件失败!");
        }
    }
    
}

上一篇:express中间件原理


下一篇:解决Centos7下安装express之后创建文件失败的问题