天天看點

任務卡_03-Java核心類庫_第6節 網絡程式設計

目錄

​​一,快遞管理訓練任務​​

​​1,題目描述​​

​​2,源代碼​​

​​2.1 bean.Express​​

​​2.2 dao.ExpressDao​​

​​2.3 main​​

​​2.4 view.View​​

​​3,總結​​

​​3.1 核心資料結構改動​​

​​3.2 ExpressDao​​

​​3.3 Main與ServerMain、ClientMain​​

​​3.4 說明​​

​​3.5 遇到的問題​​

​​3.6 思考​​

​​二,圖書管理訓練任務(選做)​​

​​1,題目描述​​

一,快遞管理訓練任務

1,題目描述

還記得之前的快遞管理嗎?

我們将資料存儲在檔案中,其實資料存儲在客 戶端中是很不安全的,今天我們來學習網絡程式設計,用戶端後續隻用來收集使用者 的操作,需要存儲的資料都存儲在伺服器中。 

為了保證伺服器能同時連接配接多個用戶端,記得在伺服器引入多線程技術。 接下來加油學習吧!

任務卡_03-Java核心類庫_第6節 網絡程式設計

2,源代碼

代碼結構

任務卡_03-Java核心類庫_第6節 網絡程式設計

2.1 bean.Express

package bean;

import java.io.Serializable;
import java.util.Objects;

/**
 *
 */
public class Express implements Serializable {
    private String number;  // 快遞單号
    private String company; // 公司
    private int code;       // 取件碼
    public int posX, posY;  // 快遞所在快遞櫃中的位置

    // 構造方法
    public Express(String number, String company, int code) {
        this.number = number;
        this.company = company;
        this.code = code;
    }

    public Express() {
    }

    // getter/setter

    public String getNumber() {
        return number;
    }

    public String getCompany() {
        return company;
    }

    public int getCode() {
        return code;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    public void setCompany(String company) {
        this.company = company;
    }

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

    // 重寫toString 方法

    @Override
    public String toString() {
        return "Express{" +
                "number='" + number + '\'' +
                ", company='" + company + '\'' +
                ", code=" + code +
                '}';
    }

    // 重寫equals方法

    /**
     * 隻要快遞單号相同就認為快遞相同
     * @param o
     * @return
     */
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Express express = (Express) o;
        return Objects.equals(number, express.number);
    }

    @Override
    public int hashCode() {
        return Objects.hash(code);
    }
}      

2.2 dao.ExpressDao

package dao;

import bean.Express;

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

// 實作可序列化标記接口 使得dao對象支援序列化與反序列化
public class ExpressDao {
    private File file = new File("SerializedData.txt");
    private boolean[][] cabinet = new boolean[10][];            // 二維數組表示快遞櫃位置是否被占用 true已占用 false未占用
    private ArrayList<Express> expresses = new ArrayList<>();   // 存放所有的Express對象 便于周遊
    private Random random = new Random();                       // 用于生成随機數

    /**
     * 反序列化獲得快遞櫃中存放的對象HashMap<Integer, Express> data
     */
    public void readFromFile() {
        try (FileInputStream fis = new FileInputStream(file)) {
            ObjectInputStream ois = new ObjectInputStream(fis);
            expresses = (ArrayList<Express>) ois.readObject();  // 反序列化讀取對象
            ois.close();                                        // 關閉輸入流
        } catch (IOException | ClassNotFoundException e) {
            expresses = new ArrayList<Express>();               // 打開檔案異常時 将expresses初始為空
        }
    }

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

    /**
     * 初始化資料結構:cabinet(表示快遞櫃是否被占用),expresses(存儲)
     */
    public void init() {
        for(int i = 0; i < 10; i++){
            cabinet[i] = new boolean[10];
        }
        for(Express e : expresses) {
            cabinet[e.posX][e.posY] = true;         // 表示此位置已被占用
        }
    }

    /**
     *
     * @param e 新加入的快遞對象
     * @return
     */
    public synchronized boolean add(Express e){
        int size = expresses.size();
        if(size >= 100){
            return false;
        }
        // 1,随機生成兩個0-9的下标
        int x = -1, y = -1;
        while (true){
            x = random.nextInt(10);
            y = random.nextInt(10);
            if(cabinet[x][y] == false){
                break;                                  // 此位置未被占用
            }
        }
        // 2,判斷取件碼是否重複(最簡單的 一個個對比)
        int code = randomCode();           // 獲得沒有重複的取件碼
        e.setCode(code);
        e.posX = x;                                     // 快遞櫃存放快遞的位置
        e.posY = y;
        size++;                                         // 快遞數目加一
        cabinet[x][y] = true;                           // 此位置已被占用
        expresses.add(e);                              //
        return true;
    }

    /**
     * 周遊所有對象 生成獨一無二的取件碼
     * @return
     */
    private int randomCode(){
        while (true) {
            int code = random.nextInt(900000) + 100000; // 範圍(000000-899999)+1000000
            Express e = findByCode(code);
            if(e == null) { // 說明取件碼未重複
                return code;
            }
        }
    }

    /**
     * 快遞員根據快遞單号查詢HashMap中存放的快遞
     * @param number
     * @return
     */
    public Express findByNumber(String number){
        for(Express e : expresses) {
            if(e.getNumber().equals(number)) {
                return e;
            }
        }
        return null;
    }

    /**
     * 根據取件碼查詢快遞
     * @param code 取件碼
     * @return 查詢到結果 查詢失敗傳回null
     */
    public Express findByCode(int code){
        for(Express e : expresses) {
            if(e.getCode() == code) {
                return e;
            }
        }
        return null;
    }

    /**
     * 多餘的操作 為了MVC更圓潤
     * @param oldExpress
     * @param newExpress
     */
    public synchronized Boolean update(Express oldExpress, Express newExpress){
        delete(oldExpress);
        return add(newExpress);
    }

    /**
     * 删除特定的快遞對象
     * @param e
     */
    public synchronized boolean delete(Express e){
        cabinet[e.posX][e.posY] = false;
        return expresses.remove(e);// 删除指定對象
    }

    /**
     * 擷取所有的快遞對象
     * @return
     */
    public synchronized ArrayList<Express> getAll() {
        return expresses;
    }
}      

2.3 main

1)main.ClientMain

package main;

import bean.Express;
import view.View;

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

public class ClientMain {
    private Socket socket;
    private View v = new View();

    public static void main(String[] args) throws IOException {
        ClientMain client = new ClientMain();
        client.link();
    }

    /**
     * 建立套接字,與服務端進行連接配接;
     * 建立對象輸入/輸出流,與服務端進行資料互動;
     * @throws IOException
     */
    public void link() throws IOException {
        OutputStream os = null;
        InputStream is = null;
        ObjectOutputStream oos = null;
        ObjectInputStream ois = null;
        try {
            socket = new Socket("127.0.0.1", 8888);
            v.connectSuccess();
            is = socket.getInputStream();
            os = socket.getOutputStream();
            oos = new ObjectOutputStream(os);// 由于伺服器是先ois後oos 為了保證配對 這裡需要順序調換
            ois = new ObjectInputStream(is);
            o:while (true) {
                int num = v.menu();// 獲得角色選擇碼
                oos.writeInt(num);
                oos.flush();
                switch (num) {
                    case 0:
                        break o;
                    case 1:
                        gClient(oos, ois);
                        break;
                    case 2:
                        uClient(oos, ois);
                        break;
                    default:
                        v.choiceError();
                        break;
                }
            }
        } 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
     * @throws ClassNotFoundException
     */
    public void gClient(ObjectOutputStream oos, ObjectInputStream ois) throws IOException, ClassNotFoundException {
        while (true) {
            int num = v.gMenu();// 獲得使用者輸入的功能碼
            oos.writeInt(num);// 向伺服器傳送功能碼 保證進入同樣的功能子產品
            oos.flush();
            switch (num) {
                case 0:// 退出
                    return;
                case 1:// 插入
                    insert(oos, ois);
                    break;
                case 2:// 修改
                    update(oos, ois);
                    break;
                case 3:// 删除
                    delete(oos, ois);
                    break;
                case 4:// 顯示所有
                    printAll(oos, ois);
                    break;
                default:
                    v.choiceError();
                    break;
            }
        }
    }

    /**
     * 用戶端使用者子產品
     * @param oos
     * @param ois
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public void uClient(ObjectOutputStream oos, ObjectInputStream ois) throws IOException, ClassNotFoundException {
        while (true) {
            int num = v.uMenu();
            oos.writeInt(num);
            oos.flush();
            switch (num) {
                case 0:
                    return;
                case 1:
                    int code = v.getExpress();
                    oos.writeInt(code);
                    oos.flush();
                    Express e = (Express) ois.readObject();
                    if(e != null) {// 查詢到有快遞存在
                        v.printExpress(e);
                        if(ois.readBoolean()) v.success();
                        else v.fail();
                    } else {
                        v.printNull();// 取件碼對應快遞不存在
                    }
                    break;
                default:
                    v.choiceError();
                    break;
            }
        }
    }

    /**
     * 插入快遞對象;
     * 利用view對象擷取将要插入快遞對象,并将其傳送給服務端
     * @param oos
     * @param ois
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public void insert(ObjectOutputStream oos, ObjectInputStream ois) throws IOException, ClassNotFoundException {
        Express e = v.insert();
        oos.writeObject(e);
        oos.flush();
        Express e1 = (Express) ois.readObject();// 傳回對象為空 表示目前快遞單号尚未被使用
        if(e1 == null) {
            if(ois.readBoolean()) {// 插入成功
                v.success();
            } else {
                v.fail();
            }
        } else {
            v.expressExist();
        }
    }

    /**
     * 删除快遞對象
     * @param oos
     * @param ois
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public void delete(ObjectOutputStream oos, ObjectInputStream ois) throws IOException, ClassNotFoundException {
        String id = v.findByNumber();
        oos.writeObject(id);
        oos.flush();
        Express e = (Express) ois.readObject();
        if(e != null) {
            int num = v.delete();// 再次向使用者确認是否删除
            oos.writeInt(num);
            oos.flush();
            switch (num) {
                case 1:// 确認删除
                    if(ois.readBoolean()) v.success();
                    else v.fail();
                    break;
                default:// 取消删除或退出
                    break;
            }
        } else {
            v.printNull();
        }
    }

    /**
     * 更新快遞對象
     * @param oos
     * @param ois
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public void update(ObjectOutputStream oos, ObjectInputStream ois) throws IOException, ClassNotFoundException {
        String id = v.findByNumber();
        oos.writeObject(id);
        oos.flush();
        Express e = (Express) ois.readObject();
        if(e != null) {// 被更新的快遞對象存在
            Express e1 = v.update();
            oos.writeObject(e1);

            oos.flush();
            if(ois.readBoolean()) v.success();
            else v.fail();
        } else {
            v.printNull();
        }
    }

    /**
     * 列印快遞對象
     * @param oos
     * @param ois
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public void printAll(ObjectOutputStream oos, ObjectInputStream ois) throws IOException, ClassNotFoundException {
//        ArrayList<Express> expresses = (ArrayList<Express>) ois.readObject();
//        v.printAll(expresses);
        Express[] es = (Express[]) ois.readObject();
        List<Express> expresses =  Arrays.asList(es);
        v.printAll(expresses);
    }
}      

2)main.ServerMain

package main;

import bean.Express;
import dao.ExpressDao;

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

public class ServerMain {
    private ServerSocket serverSocket;
    private ExpressDao dao = new ExpressDao();
    private int numOfClient = 0;
    // 伺服器
    public static void main(String[] args) throws IOException {
        ServerMain server = new ServerMain();
        server.start();
    }

    /**
     * 啟動伺服器,并與用戶端進行連接配接
     */
    public void start() {
        try {
            serverSocket = new ServerSocket(8888);
            System.out.println("伺服器已啟動");
            dao.readFromFile();// 從檔案中讀取資料
            dao.init();// 初始化資料結構
            System.out.println("資料初始化成功");
            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();
            }
        }
    }

    /**
     * 建立對象輸入/輸出流,與用戶端進行資料互動;
     * 進入主子產品,選擇角色;
     * @param socket
     * @throws IOException
     */
    public void receive(Socket socket) throws IOException {
        InputStream is = socket.getInputStream();
        OutputStream os = socket.getOutputStream();
        ObjectInputStream ois = new ObjectInputStream(is);
        ObjectOutputStream oos = new ObjectOutputStream(os);
        try(is; os; ois; oos) {// 這種方式可以在try/catch執行結束後 自動關閉資源
            o: while (true) {
                switch (ois.readInt()) {
                    case 0:// 退出
                        dao.writeToFile();// 退出伺服器端 将資料對象寫回檔案
                        break o;
                    case 1:
                        gClient(ois, oos);// 進入管理者操作功能子產品
                        break ;
                    case 2:
                        uClient(ois, oos);// 進入使用者操作功能子產品
                        break ;
                    default: break ;
                }
            }
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 服務端——管理者子產品,負責與用戶端——管理者子產品進行資料互動
     * @param ois
     * @param oos
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public void gClient(ObjectInputStream ois, ObjectOutputStream oos) throws IOException, ClassNotFoundException {
        while (true) {
            switch (ois.readInt()) {
                case 0:// 退出
                    return;
                case 1:// 插入
                    insert(ois, oos);
                    break;
                case 2:// 修改
                    update(ois, oos);
                    break;
                case 3:// 删除
                    delete(ois, oos);
                    break;
                case 4:// 顯示所有
                    printAll(ois, oos);
                    break;
            }
        }
    }

    /**
     * 服務端——使用者子產品,負責與用戶端——使用者子產品進行資料互動
     * @param ois
     * @param oos
     * @throws IOException
     */
    public void uClient(ObjectInputStream ois, ObjectOutputStream oos) throws IOException {
        while (true) {
            switch (ois.readInt()) {
                case 0:
                    return;
                case 1:// 取件
                    Express e = dao.findByCode(ois.readInt());// 根據用戶端傳過來的取件碼 查找快遞對象
                    oos.writeObject(e);// 向用戶端傳送查找的對象
                    oos.flush();
                    if(e != null) {
                        oos.writeBoolean(dao.delete(e));
                        oos.flush();
                    }
                    break;
                default: break;
            }
        }
    }

    /**
     * 插入快遞對象;
     * 接受用戶端發來的新快遞對象,用dao對象對資料進行操作,并将操作結果返還給用戶端
     * @param ois
     * @param oos
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public void insert(ObjectInputStream ois, ObjectOutputStream oos) throws IOException, ClassNotFoundException {
        Express e = (Express) ois.readObject();
        Express e1 = dao.findByNumber(e.getNumber());// 根據快遞單号判斷對應快遞是否已存在
        oos.writeObject(e1);
        oos.flush();
        if(e1 == null) {
            oos.writeBoolean(dao.add(e));
            oos.flush();
        }
    }

    /**
     * 删除快遞對象
     * @param ois
     * @param oos
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public void delete(ObjectInputStream ois, ObjectOutputStream oos) throws IOException, ClassNotFoundException {
        String id = (String) ois.readObject();
        Express e = dao.findByNumber(id);
        oos.writeObject(e);
        oos.flush();
        if(e != null) {// 快遞對象存在
            switch (ois.readInt()) {// 再次向使用者确認是否删除
                case 1:
                    oos.writeBoolean(dao.delete(e));
                    oos.flush();
                    break;
                default:
                    break;
            }
        }
    }

    /**
     * 更新快遞對象
     * @param ois
     * @param oos
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public void update(ObjectInputStream ois, ObjectOutputStream oos) throws IOException, ClassNotFoundException {
        String id = (String) ois.readObject();
        Express e = dao.findByNumber(id);
        oos.writeObject(e);
        oos.flush();
        if(e != null) {
            Express e1 = (Express) ois.readObject();
            oos.writeBoolean(dao.update(e, e1));
            oos.flush();
        }
    }

    /**
     * 向用戶端傳送所有快遞對象
     * @param ois
     * @param oos
     * @throws IOException
     */
    public void printAll(ObjectInputStream ois, ObjectOutputStream oos) throws IOException {
//        oos.writeObject(dao.getAll());
//        oos.flush();
        ArrayList<Express> list = dao.getAll();
        Express[] expresses = new Express[list.size()];
        list.toArray(expresses);
        oos.writeObject(expresses);
        oos.flush();
    }
}      

2.4 view.View

package view;

import bean.Express;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Scanner;

/**
 * 視圖層
 * 隻負責展示視圖 不包含其他任何邏輯
 */
public class View {
    public Scanner input = new Scanner(System.in);

    /**
     * 獲得使用者的角色選擇輸入,并進入相應的功能
     * @return 傳回功能碼 1:管理者 2:普通使用者 0:退出
     */
    public int menu(){
        System.out.println("根據提示輸入功能序号:");
        System.out.println("1,管理者");
        System.out.println("2,普通使用者");
        System.out.println("0,退出");
        String s = input.nextLine();
        int funcNum = -1;
        try{
            funcNum = Integer.parseInt(s);
        }catch (NumberFormatException e){   // 格式異常 遞歸繼續擷取功能碼
            return menu();
        }
        if(funcNum < 0 || funcNum > 2){     // 功能碼不合法
            return menu();
        }
        return funcNum;
    }

    /*
    -----------------------------------------------------------------
     */

    /**
     * 獲得管理者輸入的功能碼
     * @return 管理者輸入的合法功能碼 1:錄入 2:修改 3:删除 4:檢視所有 0:退出
     */
    public int gMenu(){
        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();
        int funcNum = -1;
        try{
            funcNum = Integer.parseInt(s);
        }catch (NumberFormatException e){   // 格式異常 遞歸繼續擷取功能碼
            return gMenu();
        }
        if(funcNum < 0 || funcNum > 4){     // 功能碼不合法
            return gMenu();
        }
        return funcNum;
    }

    /**
     * 1快遞員錄入資訊
     * @return 傳回包含了快遞單号和快遞公司的快遞對象
     */
    public Express insert(){
        System.out.println("請根據提示輸入快遞資訊:");
        System.out.print("請輸入快遞單号:");
        String number = input.nextLine();
        System.out.print("請輸入快遞公司:");
        String company = input.nextLine();
        Express e = new Express();
        e.setNumber(number);
        e.setCompany(company);
        return e;
    }

    /**
     * 2修改快遞資訊
     */
    public Express update(){
        System.out.print("請輸入新的快遞單号:");
        String number = input.nextLine();
        System.out.print("請輸入新的快遞公司");
        String company = input.nextLine();
        Express e = new Express();
        e.setNumber(number);
        e.setCompany(company);
        return e;
    }

    /**
     * 3詢問是否删除
     * @return 給出快遞管理者的選擇 1:删除 2:取消
     */
    public int delete(){
        System.out.println("确認是否删除:");
        System.out.println("1,确認删除");
        System.out.println("2,取消删除");
        System.out.println("0,退出");
        String s = input.nextLine();
        int num = -1;
        try {
            num = Integer.parseInt(s);
        }catch (NumberFormatException e){
            return delete();
        }
        if(num < 0 || num > 2){
            return delete();
        }
        return num;
    }

    /**
     * 4周遊顯示所有快遞資訊
     * @param es
     */
    public void printAll(List<Express> es){
        int count = 0;
        for(Express e : es) {
            count++;
            printExpress(e);
        }
        if(count == 0){
            System.out.println("暫無快遞資訊");
        }
    }

    /**
     * 提示使用者輸入快遞單号
     * @return
     */
    public String findByNumber(){
        System.out.println("請根據提示輸入快遞資訊:");
        System.out.print("請輸入需要操作的快遞單号:");
        String number = input.nextLine();
        return number;
    }

    /**
     * 顯示快遞資訊
     * @param e
     */
    public void printExpress(Express e){
        if(e == null){
            System.out.println("快遞資訊不存在");
            return;
        }
        System.out.println("快遞資訊如下:");
        System.out.println("位置:第" + (e.posX + 1) + "排," + (e.posY + 1) + "列; " +
                "快遞公司:" + e.getCompany() + "; " + "快遞單号:" + e.getNumber() + ";" +
                "取件碼:" + e.getCode() + ";");
    }


    /*
    -----------------------------------------------------------------
     */

    /**
     * 獲得使用者輸入的取件碼(這裡簡化,隻要取件碼相同,就算取件成功)
     * @return 使用者輸入的合法功能碼(6位)
     */
    public int uMenu(){
        System.out.println("根據提示輸入功能序号:");
        System.out.println("0,退出");
        System.out.println("1,取出快遞");
        String s = input.nextLine();
        int funcNum = -1;
        try{
            funcNum = Integer.parseInt(s);
        }catch (NumberFormatException e){   // 格式異常 遞歸繼續擷取功能碼
            System.out.println("格式異常");
            return uMenu();
        }
        if(funcNum < 0 || funcNum > 1){     // 功能碼不合法
            System.out.println("功能碼不合法");
            return uMenu();
        }
        return funcNum;
    }

    /**
     * 使用者取件
     * @return
     */
    public int getExpress() {
        System.out.println("根據提示進行取件:");
        System.out.print("請輸入取件碼:");
        String s = input.nextLine();
        int code = -1;
        try{
            code = Integer.parseInt(s);
        }catch (NumberFormatException e){   // 格式異常 遞歸繼續擷取功能碼
            System.out.println("格式異常");
            return getExpress();
        }
        if(code < 100000 || code > 999999){     // 功能碼不合法
            System.out.println("輸入有誤,請重試!");
            return getExpress();
        }
        return code;
    }

    public void expressExist(){
        System.out.println("此快遞單号已存在,請勿重複存儲");
    }
    public void printCode(Express e) {
        System.out.println("新快遞的取件碼為:" + e.getCode());
    }
    public void success(){
        System.out.println("操作成功!");
    }
    public void fail(){
        System.out.println("操作失敗!");
    }
    public void choiceError() {
        System.out.println("輸入選項有誤,請重新輸入!");
    }
    public void printNull(){
        System.out.println("快遞不存在,請檢查輸入");
    }
    public void connectSuccess() {
        System.out.println("伺服器連接配接成功");
    }
}      

3,總結

與上一次的任務卡​​@&再見螢火蟲&【任務卡_03-Java核心類庫_第4節 IO】​​相比,有着較大的改動。

3.1 核心資料結構改動

将HashMap<Integer, Express> data删除,隻保留Collection<Express> expresses;
  • 雖然可以根據HashMap快速的查找相應的Express對象,但是會導緻快遞對象的重複存儲,也就是說在data中和expresses中存儲了許多重複的快遞對象,是以此次修改,隻保留了expresses資料結構;
資料存儲由main函數轉移至dao對象中;
  • 将資料存儲在main中,利用dao對象對資料進行操作需要傳送大量的參數,使得函數看起來較為冗雜;
  • main函數中聲明大量資料結構,使得主函數看起來較為複雜,破壞了整體的結構清晰感;

3.2 ExpressDao

1)将所有快遞對象資料存放在dao的一個屬性中(上一次IO任務卡,把他們放在了main方法中了);

2)取消根據取件碼查找快遞對象的HashMap資料結構,改成用ArrayList存儲。避免對象重複存儲占用大量空間;

3)插入、删除、更新、查詢所有等方法使用synchronized進行修飾,保證線程安全;

3.3 Main與ServerMain、ClientMain

1)将Main拆解成ServerMain和ClientMain兩個方法,一個負責服務端,一個負責用戶端;

2)用戶端和服務端需要保證大緻相同的邏輯結構,即當用戶端由狀态1轉變為狀态2(方法功能,接受資料對象及類型等發生改變),服務端需要偵聽這種狀态轉變,并進行同樣的狀态轉移操作。反之同理;

任務卡_03-Java核心類庫_第6節 網絡程式設計
3)用戶端與服務端的資料交換是一去一回,嚴格配對!即便是在new輸入輸出流時也要保持一緻!
任務卡_03-Java核心類庫_第6節 網絡程式設計

4)伺服器啟動專門聲明一個start方法完成,主要作用是:建立ServerSocket、反序列化讀取對象資訊、初始化資料結構、通過while循環實作多線程、線程run方法隻用來調用receive方法(進入角色選擇子產品);

5)服務端的receive和用戶端的link 是互相配對的。在這兩個方法中建立ois(ObjectInoutStream)、oos(ObjectOutputStream),并将它們作為參數,進行資料互動;

3.4 說明

實作了多線程、集合、IO等技術;

較好的進行方法設計,使得項目整體結構清晰,備援度較低;

基本完成題目要求功能:序列化反序列化、多線程、集合等;

3.5 遇到的問題

1)用戶端執行到擷取ObjectInputStream時卡住了,不再向下執行

任務卡_03-Java核心類庫_第6節 網絡程式設計
咨詢老師之後,發現問題。伺服器與用戶端在資料傳輸時,不但需要在互動階段需要配對,聲明指派時也要配對,即輸出對應輸入、輸入對應輸出!
任務卡_03-Java核心類庫_第6節 網絡程式設計
任務卡_03-Java核心類庫_第6節 網絡程式設計

2)在dao中對資料進行操作後,快遞對象集合确實發生變化了(在服務端列印出來看過)。但是在用戶端進行printAll時,第一次是對的,後面不管怎麼修改,再次printAll結果都不會改變

任務卡_03-Java核心類庫_第6節 網絡程式設計
注釋掉的,是原先有問題的代碼。請教老師給出的解答是,流用完之後沒有關閉,而且是作為參數進行傳遞,是以借助于流在用戶端和伺服器之間傳遞的集合對象expresses沒有發生改變,依舊是第一次傳輸的資料,因而結果不發生改變。
任務卡_03-Java核心類庫_第6節 網絡程式設計
但是有兩點疑問:(以後再回頭看看吧)
  1. flush的作用不就是清楚緩沖嗎?為什麼不起作用?
  2. 為什麼把ArrayList對象轉換為對象數組進行傳輸,就可以解決問題?是因為每次傳輸時,伺服器都重新new了數組嗎?

3.6 思考

1)try/catch與直接抛出異常相比有什麼優缺點?

2)将流作為參數進行傳遞,不管對原資料進行什麼操作,多次調用方法,擷取流中傳輸的資料依舊是最開始傳輸的那一次?那flush的意以何在?

3)服務端、用戶端進行資料互動時,不僅在傳輸資料需要一去一回,建立ois(ObjectInoutStream)、oos(ObjectOutputStream)時也要遵循這樣的規則

二,圖書管理訓練任務(選做)

時間原因,有空再補o( ̄┰ ̄*)ゞ

1,題目描述

還記得之前的圖書管理嗎?我們将資料存儲在檔案中,其實資料存儲在客 戶端中是很不安全的,今天我們來學習網絡程式設計,用戶端後續隻用來收集使用者 的操作,需要存儲的資料都存儲在伺服器中。 

為了保證伺服器能同時連接配接多個用戶端,記得在伺服器引入多線程技術。 接下來加油學習吧! 

1. 管理者登陸 

2. 圖書管理 

2.1 圖書新增 

2.2 圖書修改 

2.3 圖書删除 

2.4 根據圖書名稱模糊查找圖書 

2.5 檢視所有圖書 (三種排序) 

——價格從高到低排序 

——價格從低到高排序 

——新舊排序(出版日期排序)

繼續閱讀