JAVA 技术方向支线任务-快递管理训练任务(多线程、网络)

JAVA 技术方向支线任务-快递管理训练任务

1. 任务概述: 还记得之前的快递管理吗?我们将数据存储在文件中,其实数据存储在客 户端中是很不安全的,今天我们来学习网络编程,客户端后续只用来收集用户 的操作,需要存储的数据都存储在服务器中。 为了保证服务器能同时连接多个客户端,记得在服务器引入多线程技术。
在这里插入图片描述

2.代码结构
在这里插入图片描述

3.源代码
3.1. bean.Express

package bean;
import java.io.Serializable;
/**
 快递类
 */
public class Express implements Serializable {
    //快递单号
    private String order;
    //公司名称
    private String compony;
    //取件码、快递位置
    private int code,target;

    public Express(String order, String compony) {
        this.order = order;
        this.compony = compony;
    }

    public Express() {

    }

    private String showTarget() {
        return target/10+"排"+target%10+"列";
    }

    @Override
    public String toString() {
        return "快递单号:"+order+"\t快递公司:"+compony+"\t取件码:"+code+"\t"+showTarget();
    }


    public String getOrder() {
        return order;
    }

    public void setOrder(String order) {
        this.order = order;
    }

    public String getCompony() {
        return compony;
    }

    public void setCompony(String compony) {
        this.compony = compony;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public int getTarget() {
        return target;
    }

    public void setTarget(int target) {
        this.target = target;
    }
}

3.2. dao.ExpressDao接口与ExpressDaoImpl实现类

package dao;

import bean.Express;

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

public interface ExpressDao {
    /**
     * 添加方法
     * @param express
     * @return
     */
    Express add(Express express);

    /**
     * 删除快递
     * @param order
     * @return
     */
    boolean delete(String order);

    /**
     * 修改快递
     * @param oldExp
     * @param newExp
     * @return
     */
    Express update(Express oldExp, Express newExp);

    /**
     * 查询所有快递信息
     * @return
     */
    ArrayList<Express> getAll();

    /**
     * 取快递
     * @param code
     * @return
     */
    boolean getExpress(int code);

    /**
     * 数组大小
     * @return
     */
    int size();

    /**
     *根据快递号查询快递信息
     * @param order
     * @return
     */
    Express findByOrder(String order);

    /**
     * 根据取件查询快递信息
     * @param order
     * @return
     */
    Express findByCode(int order);

    /**
     * 从文件中读取快递信息(反序列化)
     */
    void readFromFile();

    /**
     * 将信息写入文件中(序列化)
     * @throws IOException
     */
    void writeToFile() throws IOException;
}

package dao.impl;

import bean.Express;
import dao.ExpressDao;

import java.io.*;
import java.util.ArrayList;
import java.util.Random;

public class ExpressDaoImpl implements ExpressDao {
    private File file = new File("Express.txt");
    private ArrayList<Express> list;
    private Random random = new Random();
 
    //快递柜
    private int max = 100;

    /**
     * 反序列化获得快递柜中存放的对象HashMap<Integer, Express> data
     */
    public void readFromFile() {
        try (FileInputStream fis = new FileInputStream(file)) {
            ObjectInputStream ois = new ObjectInputStream(fis);
            list = (ArrayList<Express>) ois.readObject();  // 反序列化读取对象
            ois.close();                                        // 关闭输入流
        } catch (IOException | ClassNotFoundException e) {
            list = new ArrayList<Express>();               // 打开文件异常时 将expresses初始为空
        }
    }

    /**
     * 序列化存储对象HashMap<Integer, Express> data
     *
     * @throws IOException
     */
    public void writeToFile() throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
        oos.writeObject(list);                             // 序列化对象
        oos.close();
    }

    /**
     * 随机生成6位数取件码
     *
     * @return 6位数取件码
     */
    public int randomCode() {
        while (true) {
            int code = random.nextInt(900000) + 100000;
            Express e = findByCode(code);
            if (e == null) {
                return code;
            }
        }

    }

    /**
     * 初始化快递柜位置
     *
     * @return
     */
    public int randomTarget() {
        int target;
        do {
            target = random.nextInt(max) + 1;
        } while (findByTarger(target) != null);
        return target;
    }

    /**
     * 判断快递柜是否占用
     *
     * @param target
     * @return
     */
    private Express findByTarger(int target) {
        for (Express express : list) {
            if (express.getTarget() == target) {
                return express;
            }
        }
        return null;
    }

    /**
     * 根据取件码查询快递
     *
     * @param code 取件码
     * @return 查询的结果,没有则返回null
     */
    public Express findByCode(int code) {
        for (Express express : list) {
            if (express.getCode() == code) {
                return express;
            }
        }
        return null;
    }

    /**
     * 根据单号查询
     *
     * @param order
     * @return
     */
    public Express findByOrder(String order) {
        for (Express e : list) {
            if (e.getOrder().equals(order)) {
                return e;
            }
        }
        return null;
    }

    @Override
    public synchronized Express add(Express express) {
        if (size() >= max) {
            return null;
        } else {
            express.setCode(randomCode());
            express.setTarget(randomTarget());
            list.add(express);
            return express;
        }
    }

    @Override
    public synchronized boolean delete(String order) {
        Express byOrder = findByOrder(order);
        if (byOrder == null) {
            return false;
        }
        list.remove(byOrder);
        return true;
    }

    @Override
    public synchronized Express update(Express oldExp, Express newExp) {
        Express byOrder = findByOrder(oldExp.getOrder());
        if (byOrder != null) {
            list.remove(oldExp);
            newExp.setCode(randomCode());
            newExp.setTarget(randomTarget());
            list.add(newExp);
            return newExp;
        }
        return oldExp;
    }

    @Override
    public synchronized ArrayList<Express> getAll() {
        return list;
    }

    @Override
    public synchronized boolean getExpress(int code) {
        Express express = findByCode(code);
        if (express != null) {
            list.remove(express);
            return true;
        }
        return false;
    }

    @Override
    public int size() {
        return list.size();
    }
}

3.3 ExpressService服务器

package service;

import bean.Express;
import dao.ExpressDao;
import dao.impl.ExpressDaoImpl;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

public class ExpressService {
    private ServerSocket serverSocket;
    private static ExpressDao expressDao = new ExpressDaoImpl();
    private int numOfClient = 0;

    public static void main(String[] args) throws IOException {
        ExpressService service = new ExpressService();
        service.start();
    }

    public void start() {
        try {
            serverSocket = new ServerSocket(7063);
            System.out.println("服务器已启动");
            expressDao.readFromFile();
            while (true) {
                Socket socket = serverSocket.accept();
                System.out.println("第" + (++numOfClient) + "个客户端连接了");
                new Thread() {
                    @Override
                    public void run() {
                        try {
                            receive(socket);// 准备连接 进入主功能模块
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (serverSocket != null) {
                    serverSocket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void receive(Socket socket) throws IOException {
        InputStream is = null;
        OutputStream os = null;
        ObjectInputStream ois = null;
        ObjectOutputStream oos = null;
        try {
            is = socket.getInputStream();
            os = socket.getOutputStream();
            ois = new ObjectInputStream(is);
            oos = new ObjectOutputStream(os);
            o:
            while (true) {
                System.out.println("进入主菜单");
                switch (ois.readInt()) {
                    case 0:
                        System.out.println("客户端退出");
                        expressDao.writeToFile();
                        break o;
                    case 1:
                        deliveryManClient(ois, oos);
                        break;
                    case 2:
                        userClient(ois, oos);
                        break;
                    default:
                        break;
                }
            }

        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 管理员客户端
     *
     * @param oos 发送数据给服务区
     * @param ois 从服务器接收数据
     * @throws IOException
     */
    private void deliveryManClient(ObjectInputStream ois, ObjectOutputStream oos) throws IOException, ClassNotFoundException {
        System.out.println("进入快递员界面");
        switch (ois.readInt()) {
            case 0:
                expressDao.writeToFile();
                break;
            case 1:
                System.out.println("添加快递");
                addExpress(ois, oos);
                break;
            case 2:
                System.out.println("删除快递");
                deleteExpress(ois, oos);
                break;
            case 3:
                System.out.println("修改快递");
                updateExpress(ois, oos);
                break;
            case 4:
                System.out.println("查看快递");
                seleteAllExpress(ois, oos);
                break;
            default:
                return;
        }
    }

    /**
     * 用户
     *
     * @param oos 发送数据给服务器
     * @param ois 从服务器接收数据
     * @throws IOException
     * @throws ClassNotFoundException
     */
    private void userClient(ObjectInputStream ois, ObjectOutputStream oos) throws IOException, ClassNotFoundException {
        System.out.println("用户取快递界面");
        // 根据客户端传过来的取件码 查找快递对象
        Express e = expressDao.findByCode(ois.readInt());
        oos.writeObject(e);// 向客户端传送查找的对象
        oos.flush();
        if (e != null) {
            //取出快递
            expressDao.writeToFile();
            oos.writeBoolean(expressDao.getExpress(e.getCode()));
            oos.flush();
        }
    }

    /**
     * 存储快递
     *
     * @param oos
     * @param ois
     */
    private void addExpress(ObjectInputStream ois, ObjectOutputStream oos) throws IOException, ClassNotFoundException {
        //1.从客户端接收快递数据
        Express addExpress = (Express) ois.readObject();
        System.out.println(addExpress.toString());
        //2.根据快递单号判断对应快递是否已存在
        Express byOrder = expressDao.findByOrder(addExpress.getOrder());
        //判断快递是否存在,不存在则添加快递,为空则代表不存在,添加快递。
        if (byOrder == null) {
            byOrder = expressDao.add(addExpress);
            oos.writeObject(byOrder);
            oos.flush();
        } else {
            oos.writeObject(null);
            oos.flush();
        }
    }

    /**
     * 删除快递
     *
     * @param oos
     * @param ois
     */
    private void deleteExpress(ObjectInputStream ois, ObjectOutputStream oos) throws IOException, ClassNotFoundException {
        //获取到客户端输入的单号
        String deleteOrder = (String) ois.readObject();
        //判断是否存在
        Express byOrder = expressDao.findByOrder(deleteOrder);
        //发送快递信息至客户端
        oos.writeObject(byOrder);
        oos.flush();
        //如果快递存在
        if (byOrder != null) {
            //接收用户确认是否删除
            switch (ois.readInt()) {
                case 1:
                    oos.writeBoolean(expressDao.delete(deleteOrder));
                    oos.flush();
                    break;
                default:
                    break;
            }
        }

    }

    /**
     * 修改快递
     *
     * @param oos
     * @param ois
     */
    private void updateExpress(ObjectInputStream ois, ObjectOutputStream oos) throws IOException, ClassNotFoundException {
        //得到需要修改的单号
        String updateOrber = (String) ois.readObject();
        //根据单号查找内容,将查找到的数据发送客户端
        Express oldExpress = expressDao.findByOrder(updateOrber);
        oos.writeObject(oldExpress);
        oos.flush();
        if (oldExpress != null) {
            //接收客户端回传的更改内容
            Express newExpress = (Express) ois.readObject();
            //根据新快递内容去库中查找是否存在,存在就代表库中有相同的数据
            Express isExit = expressDao.findByOrder(newExpress.getOrder());
            if (isExit != null) {
                oos.writeBoolean(false);
                oos.flush();
            } else {
                Express update = expressDao.update(oldExpress, newExpress);
                //修改成功
                oos.writeBoolean(true);
                //将修改的值返回客户端
                oos.writeObject(update);
                oos.flush();
            }
        }
    }


    /**
     * 查看所有快递
     *
     * @param oos
     * @param ois
     */
    private void seleteAllExpress(ObjectInputStream ois, ObjectOutputStream oos) throws IOException, ClassNotFoundException {
        // ArrayList<Express> all = expressDao.getAll();
        //views.printExpressAll(all);
        ArrayList<Express> list = expressDao.getAll();
        Express[] expresses = new Express[list.size()];
        list.toArray(expresses);
        oos.writeObject(expresses);
        oos.flush();
    }
}

3.4ExpressClient客户端


import bean.Express;
import dao.ExpressDao;
import dao.impl.ExpressDaoImpl;
import views.Views;

import java.io.*;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ExpressClient {
    //初始化视图
    private static Views views = new Views();
    //初始化Dao对象
    private static ExpressDao expressDao = new ExpressDaoImpl();
    private static Socket socket;
    //状态码
    private boolean status = true;

    public static void main(String[] args) throws IOException {
        ExpressClient ec = new ExpressClient();
        ec.init();
    }


    private void init() throws IOException {
        OutputStream os = null;
        InputStream is = null;
        ObjectOutputStream oos = null;
        ObjectInputStream ois = null;
        //1.欢迎
        views.welcome();
        try {
            socket = new Socket("127.0.0.1", 7063);
            os = socket.getOutputStream();
            is = socket.getInputStream();
            // 由于服务器是先ois后oos 为了保证配对 这里需要顺序调换
            oos = new ObjectOutputStream(os);
            ois = new ObjectInputStream(is);
            m:
            while (status) {
                int menu = views.menuMain();
                oos.writeInt(menu);
                oos.flush();
                switch (menu) {
                    case 0:
                        break m;
                    case 1:
                        deliveryManClient(oos, ois);
                        break;
                    case 2:
                        userClient(oos, ois);
                        break;
                    default:
                        break;
                }
            }
            oos.writeInt(0);
            oos.flush();
            views.exit();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (ois != null) ois.close();
            if (oos != null) oos.close();
            if (socket != null) socket.close();
        }


    }

    /**
     * 管理员客户端
     *
     * @param oos 发送数据给服务区
     * @param ois 从服务器接收数据
     * @throws IOException
     */
    private void deliveryManClient(ObjectOutputStream oos, ObjectInputStream ois) throws IOException, ClassNotFoundException {
        int menu = views.menuDeliveryMan();
        oos.writeInt(menu);
        oos.flush();
        switch (menu) {
            case 0:
                status = false;
                break;
            case 1:
                addExpress(oos, ois);
                break;
            case 2:
                deleteExpress(oos, ois);
                break;
            case 3:
                updateExpress(oos, ois);
                break;
            case 4:
                seleteAllExpress(oos, ois);
                break;
            default:
                break;
        }
    }

    /**
     * 用户
     *
     * @param oos 发送数据给服务器
     * @param ois 从服务器接收数据
     * @throws IOException
     * @throws ClassNotFoundException
     */
    private void userClient(ObjectOutputStream oos, ObjectInputStream ois) throws IOException, ClassNotFoundException {
        //获取用户输入的取件码
        int code = views.menuUser();
        oos.writeInt(code);
        oos.flush();
        //根据取件码查询快递
        Express byCode = (Express) ois.readObject();
        if (byCode == null) {
            //不存在,提示用户取件码错误或快递不存在
            views.printCodeNull();
        } else {
            //提示用户操作成功,打印快递信息
            views.printSuccess();
            views.printExpress(byCode);
            //从快递柜删除该快递
            if (!ois.readBoolean()) views.printFail();
        }
    }

    /**
     * 存储快递
     *
     * @param oos
     * @param ois
     */
    private void addExpress(ObjectOutputStream oos, ObjectInputStream ois) throws IOException, ClassNotFoundException {
        //1.提示输入快递信息
        Express addExpress = views.insert();
        oos.writeObject(addExpress);
        oos.flush();
        //2.判断快递是否已存储
        Express add = (Express) ois.readObject();
        if (add != null) {
            views.printExpress(add);
        } else {
            //提示快递已存在
            views.expressExist();
        }
    }

    /**
     * 删除快递
     *
     * @param oos
     * @param ois
     */
    private void deleteExpress(ObjectOutputStream oos, ObjectInputStream ois) throws IOException, ClassNotFoundException {
        //获取到用户输入的单号
        String deleteOrder = views.findByOrder();
        //传给服务器
        oos.writeObject(deleteOrder);
        //刷新
        oos.flush();
        //查询单号是否存在
        Express i = (Express) ois.readObject();
        if (i == null) {
            views.printNull();
        } else {
            //向用户确认是否删除
            int menu = views.deleteExpress();
            //传给服务器
            oos.writeInt(menu);
            oos.flush();
            switch (menu) {
                case 1:
                    if (ois.readBoolean()) {
                        views.printSuccess();
                    } else {
                        views.printFail();
                    }
                    break;
                default:
                    break;
            }
        }

    }

    /**
     * 修改快递
     *
     * @param oos
     * @param ois
     */
    private void updateExpress(ObjectOutputStream oos, ObjectInputStream ois) throws IOException, ClassNotFoundException {
        //得到需要修改的单号
        String updateOrber = views.findByOrder();
        oos.writeObject(updateOrber);
        oos.flush();
        //得到服务端回传的数据
        Express oldExpress = (Express) ois.readObject();
        //判断是否存在
        if (oldExpress != null) {
            Express newExpress = views.updateExpress();
            //将修改的内容发送至服务器
            oos.writeObject(newExpress);
            oos.flush();
            if (!ois.readBoolean()) {
                views.expressExist();
                views.printExpress(oldExpress);
            }else{
                //得到修改后的值,打印输出
                Express update=(Express) ois.readObject();
                views.printSuccess();
                views.printExpress(update);
            }
        } else {
            views.printNull();
        }
    }


    /**
     * 查看所有快递
     *
     * @param oos
     * @param ois
     */
    private void seleteAllExpress(ObjectOutputStream oos, ObjectInputStream ois) throws IOException, ClassNotFoundException {
        // ArrayList<Express> all = expressDao.getAll();
        //views.printExpressAll(all);
        Express[] es = (Express[]) ois.readObject();
        List<Express> expresses = Arrays.asList(es);
        if (expresses.size() != 0) {
            for (Express ex : expresses) {
                views.printExpress(ex);

            }
        } else {
            views.isNull();
        }

    }
}

3.5 Views视图

package views;

import bean.Express;

import java.util.ArrayList;
import java.util.Scanner;

public class Views {
    private Scanner scanner = new Scanner(System.in);

    public void welcome() {
        System.out.println("=====欢迎使用新职课快递柜=====");
    }

    public void exit() {
        System.out.println("=====欢迎下次使用=====");
    }

    /**
     * 选择身份界面
     *
     * @return
     */
    public int menuMain() {
        System.out.println("请输入您的身份:1-快递员,2-用户,0-退出程序");
        //全局使用nextLine(),不会因为输入产生冲突,且可以更好的接收各种类型的数据
        String input = scanner.nextLine();
        int num = -1;
        // 判断用户输入是否正确
        try {
            num = Integer.parseInt(input);
        } catch (NumberFormatException e) {
        }
        if (num < 0 || num > 2) {
            System.out.println("输入有误,请重新输入");
            return menuMain();
        }
        return num;
    }

    /**
     * 快递员功能界面
     *
     * @return
     */
    public int menuDeliveryMan() {
        System.out.println("请选择操作:1-快递录入,2-快递删除,3-快递修改,4-查看所有快递,5-返回上级目录,0-退出");
        String input = scanner.nextLine();
        int num = -1;
        // 判断用户输入是否正确
        try {
            num = Integer.parseInt(input);
        } catch (NumberFormatException e) {
        }
        if (num < 0 || num > 5) {
            System.out.println("输入有误,请重新输入");
            return menuDeliveryMan();
        }
        return num;
    }

    /**
     * 快递员录入快递
     *
     * @return 快递单号及快递公司
     */
    public Express insert() {
        System.out.println("请输入快递单号:");
        String order = scanner.nextLine();
        System.out.println("请输入快递公司:");
        String compony = scanner.nextLine();
        Express express = new Express();
        express.setOrder(order);
        express.setCompony(compony);
        return express;
    }

    /**
     * 用于查找快递单号
     *
     * @return 快递单号
     */
    public String findByOrder() {
        System.out.println("请输入要操作的快递单号:");
        String order = scanner.nextLine();
        return order;
    }

    /**
     * 打印快递信息
     *
     * @param express
     */
    public void printExpress(Express express) {
        System.out.println(express.toString());
    }

    /**
     * 修改快递信息
     *
     * @param
     */
    public Express updateExpress() {
        System.out.println("请输入新的快递单号:");
        String order = scanner.nextLine();
        System.out.println("请输入新的快递公司:");
        String compony = scanner.nextLine();
        Express express =new Express();
        express.setOrder(order);
        express.setCompony(compony);
        return express;
    }

    /**
     * 询问是否删除
     *
     * @return 1确认删除,2取消并退出
     */
    public int deleteExpress() {
        System.out.println("是否确认删除:1-确认删除,其他-取消操作");
        String input = scanner.nextLine();
        int num = -1;
        // 判断用户输入是否正确
        try {
            num = Integer.parseInt(input);
        } catch (NumberFormatException e) {
        }
       /* if (num < 1) {
            System.out.println("输入有误,请重新输入");
            return deleteExpress();
        }*/
        return num;
    }

    /**
     * 将给定数组的快递信息,遍历显示
     *
     * @param expresses
     */
    public void printExpressAll(ArrayList<Express> expresses) {
        int count = 0;
        for (int i = 0; i < expresses.size(); i++) {
            count++;
            System.out.println(expresses.get(i));
        }
        if (count == 0) {
            System.out.println("暂无快递信息");
        }
    }

    /**
     * 用户菜单界面
     *
     * @return
     */
    public int menuUser() {
        System.out.println("请输入取件码:");
        String code = scanner.nextLine();
        int num = -1;
        // 判断用户输入是否正确
        try {
            num = Integer.parseInt(code);
        } catch (NumberFormatException e) {
        }
        if (num < 100000 || num > 999999) {
            System.out.println("输入有误,请重新输入");
            return menuUser();
        }
        return num;
    }

    /**
     * 提示快递已存在
     */
    public void expressExist() {
        System.out.println("此单号在快递柜中已存在,请检查是否正确");
    }

    /**
     * 打印空信息,提示快递不存在
     */
    public void printNull() {
        System.out.println("该快递不存在,请检查输入是否正确!");
    }

    /**
     * 打印操作成功信息
     */
    public void printSuccess() {
        System.out.println("操作成功!");
    }

    /**
     * 打印空取件码,提示取件码错误
     */
    public void printCodeNull() {
        System.out.println("取件码错误或快递已取出,请检查!");
    }

    public void printFail() {
        System.out.println("操作失败!");
    }

    public void isNull(){
        System.out.println("无快递信息");
    }
}

4.注意事项
1.客户端与服务器收发必须对应,客户端发送,服务器接收。服务器发送,客户端接收。即ObjectInputStream与ObjectOutputStream一一对应!!
2.在使用修改方法时,如果使用list.remove(oldExp);return add(newExp),方法会导致update方法调用add线程方法,卡住程序。(不敢确定,没有深入分析)。
5.疑问
在客户端发送菜单指令后,服务器应该是一一对应的,但服务器的中break语句正常结束后,ois.readInt()方法不会返回,而是一直往下执行。必须使用return才能返回上级。----已解决
6.解决问题
1.在服务器中仅监听客户端连接及主菜单选择处需要使用while(true)循环,无需与客户端一致。
2.在修改快递时,需要判断修改后的快递是否存在,如果已存在则需提醒客户修改失败。

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值