快递管理控制台简易版——加入多线程与网络编程(仅含方法)(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 的基础上,在服务器端启用多线程模式,要求:每一个用户发送登录请求到服务器后,服务器端就分配一个线程去处理这个请求,以实现服务器端多线程模式下的用户登录

管理员

  • 快递录入
    …柜子位置(系统产生,不能重复)
    …快递单号(输入)
    …快递公司(输入)
    …6位取件码(系统产生,不能重复)
  • 删除快递(根据单号)
  • 修改快递(根据单号)
  • 查看所有快递(遍历)

普通用户

  • 快递取出
    …输入取件码:显示快递信息和柜子位置,从柜子中移除快递

任务过程

  1. 明确需求:练习 1、2 主要是实现用户登录,练习 1 为单用户的网络编程登录,练习 2 为多用户
  2. 先创建客户端和服务器端的编码,编码过程中,双方数据传递建议使用类对象
  3. 服务器端的多线程,本质就是让服务器一直处于运行状态,并且accept()请求后,分配新线程去处理请求

涉及知识点

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

思路及代码实现

下面的代码只涉及到多线程和网络编程的加入,实现用户登录和界面显示,因此代码不完整

一、 自定义异常

创建一个exception包,新建类OutNumberBoundException

OutNumberBoundException

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

二、视图分析

仅列出本文中涉及到的方法

创建一个view包,新建类ExpressView

  • 进入系统
    public  static String welcome(){
        return "欢迎进入快递管理系统!";
    }
  • 退出系统
    public static String bye(){
        return "感谢使用快递管理系统!";
    }
  • 身份选择
    public static String mainMenu(){
        return "请选择您的身份:  1.管理员  2.普通用户  0.退出";
    }
  • 输入账号和密码
/**
     * 登录界面,输入账号
     */
    public static String loginName(){
        String s = "请输入登录用户名:";
        return s;
    }

    /**
     * 登录界面,输入密码
     */
    public static String loginPassword(){
        String s = "请输入登录密码:";
        return s;
    }

三、数据处理

仅列出本文中涉及到的方法

创建一个dao包,新建类ExpressDao

  • 判断输入数字是否在有效范围内
 public 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("输入的必须是数字!");
        }
    }
  • 判断账号密码是否对应
public static boolean judgeLoginID(int n,String s1,String s2){//s1为用户名,s2为密码
        if(n == 1){//管理员,用户名为admin,密码为abc
            if("admin".equals(s1) && "abc".equals(s2)){//账号密码完全相同,即登陆成功
                return true;
            }
        }else if(n == 2){//用户,用户名为user,密码为123
            if("user".equals(s1) && "123".equals(s2)){//账号密码完全相同,即登陆成功
                return true;
            }
        }
        return false;
    }

四、 C/S网络编程

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

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

Server服务器

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

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

接下来编写start方法


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

  • 搭建服务器
		ServerSocket server = new ServerSocket(55555);
  • 进入服务器后等待客户端连接
    使用while循环,实现用户的多次连接
		System.out.println("服务器启动完毕,等待客户连接中...");
        while(true){
            //等待客户端连接
            Socket socket = server.accept();
            System.out.println("一个客户端连接了!");
        }
  • 加入多线程,使用匿名内部类
            new Thread(new Runnable() {
                @Override
                public void run() {
                    init(server,socket);//init方法来实现数据的交互
                }
            }).start();

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

public static void start() throws IOException {
        //搭建服务器
        ServerSocket server = new ServerSocket(55555);

        //进入服务器
        System.out.println("服务器启动完毕,等待客户连接中...");

        while(true){
            //等待客户端连接
            Socket socket = server.accept();
            System.out.println("一个客户端连接了!");
            new Thread(new Runnable() {
                @Override
                public void run() {
                    init(server,socket);//init方法来实现数据的交互
                }
            }).start();
        }
    }

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

  • 收消息
            InputStream is = socket.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
  • 发消息
            OutputStream os = socket.getOutputStream();
            PrintStream ps = new PrintStream(os);
  • 进入系统
            send = v.welcome();
            ps.println(send);//发消息,提示用户进入系统
            ps.flush();//刷新流
  • 发消息给用户需要输入的信息
            //发消息,提示用户输入,1管理员,2普通用户,0退出
            send = v.mainMenu();
            ps.println(send);//发消息,提示用户输入菜单信息
  • 接收用户的输入(管理员or用户)
			 do{
                 //收消息,1表示管理员,2表示普通用户,0表示退出
                 receive = br.readLine();
                 try{
                     mainNumber = dao.validNum(receive,0,2);
                     break;
                 }catch(NumberFormatException | OutNumberBoundException e){
                     ps.println("请输入0~2之间的有效数字: 1.管理员  2.普通用户  0.退出");
                 }
             }while(true);

通过客户端输入的数字进入相应界面

  • 0.退出
    在服务器界面打印断开连接
			System.out.println("客户端已断开与服务器的连接!");
  • 1.管理员 或者 2.用户
    (由于都是输入用户名和密码,因此输入部分一起处理)
    • 输入用户名和密码
			//输入用户名
			send= v.loginName();
			ps.println(send);//请求客户端输入用户名,发送给客户端
			name = br.readLine();//接收客户端输入的用户名
			//输入密码
			send = v.loginPassword();
			ps.println(send);
			password = br.readLine();
    • 对用户名和密码进行判断是否正确
 			if (dao.judgeLoginID(1, name, password) || dao.judgeLoginID(2, name, password)) {
				ps.println("登陆成功!");
				ps.println(mainNumber);
			}else{
				ps.println("用户名或密码错误!登录失败!");
				break m;
			}
    • 管理员
 			ps.println("尊敬的管理员,您好!");
 			ps.println("请选择您要进行的操作:");
 			ps.println("1.录入快递");
 			ps.println("2.删除快递");
 			ps.println("3.修改快递");
 			ps.println("4.查看所有快递");
 			ps.println("5.返回上一级界面");
    • 用户
 			ps.println("尊敬的用户,您好!");
 			ps.println("请输入取件码:");
  • 关闭流
            input.close();
            br.close();
            ps.close();
            socket.close();
            server.close();

init方法的完整代码如下:

private static void init(ServerSocket server, Socket socket) {
        try {
            //接收客户消息,获取输入流
            InputStream is = socket.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(is));

            //发消息给客户,获取输出流
            OutputStream os = socket.getOutputStream();
            PrintStream ps = new PrintStream(os);

            //与客户端交互
            String receive,send;

            //进入系统
            send = v.welcome();
            ps.println(send);
            ps.flush();

            //主菜单
            //发消息,提示用户输入,1管理员,2普通用户,0退出
            send = v.mainMenu();
            ps.println(send);
            m: while (true) {
                int mainNumber;
                String name,password;
                do{
                    //收消息,1表示管理员,2表示普通用户,0表示退出
                    receive = br.readLine();
                    try{
                        mainNumber = dao.validNum(receive,0,2);
                        break;
                    }catch(NumberFormatException | OutNumberBoundException e){
                        ps.println("请输入0~2之间的有效数字: 1.管理员  2.普通用户  0.退出");
                    }
                }while(true);
                switch (mainNumber){
                    case 0://结束使用
                        System.out.println("客户端已断开与服务器的连接!");
                        break m;
                    default:{
                        //输入用户名
                        send= v.loginName();
                        ps.println(send);
                        name = br.readLine();
                        //输入密码
                        send = v.loginPassword();
                        ps.println(send);
                        password = br.readLine();
                        if (dao.judgeLoginID(1, name, password) || dao.judgeLoginID(2, name, password)) {
                            ps.println("登陆成功!");
                            ps.println(mainNumber);
                        }else{
                            ps.println("用户名或密码错误!登录失败!");
                            break m;
                        }
                        if(mainNumber == 1){
                            //managerPlatform();
                            ps.println("尊敬的管理员,您好!");
                            ps.println("请选择您要进行的操作:");
                            ps.println("1.录入快递");
                            ps.println("2.删除快递");
                            ps.println("3.修改快递");
                            ps.println("4.查看所有快递");
                            ps.println("5.返回上一级界面");
                            break m;//考虑到只题目要求用户登录成功提示登录成功并显示功能模块
                            //因此登陆成功并显示具体操作时程序便结束
                        }else if(mainNumber == 2){
                            // userPlatform();
                            ps.println("尊敬的用户,您好!");
                            ps.println("请输入取件码:");
                            break m;//考虑到只题目要求用户登录成功提示登录成功并显示功能模块
                            //因此登陆成功并显示具体操作时程序便结束
                        }
                    }
                }//end switch
            }//end while
            input.close();
            br.close();
            ps.close();
            socket.close();
            server.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Client客户端

  • 连接到服务器
        Socket socket = new Socket("127.0.0.1",55555);
  • 发消息
        OutputStream os = socket.getOutputStream();
        PrintStream ps = new PrintStream(os);
  • 收消息
        InputStream is = socket.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
  • 接收用户输入
        BufferedReader input = new BufferedReader(newInputStreamReader(System.in));
  • 进入系统提示
        receive = br.readLine();
        System.out.println(receive);

进入系统

  • 发消息,选择对象(管理员or用户)以及输入用户名和密码
        send = input.readLine();
        ps.println(send);
  • 如果输入0,则退出
        if("0".equals(send)){
        	System.out.println(v.bye());
			break;
        }
  • 如果登录成功,打印相应界面
        int num = Integer.parseInt(br.readLine());
        if(num == 1){
        	System.out.println(br.readLine());
        	System.out.println(br.readLine());
        	System.out.println(br.readLine());
        	System.out.println(br.readLine());
        	System.out.println(br.readLine());
        	System.out.println(br.readLine());
        	System.out.println(br.readLine());
        	break;//考虑到只题目要求用户登录成功提示登录成功并显示功能模块
                    //因此登陆成功并显示具体操作时程序便结束
        }else if(num == 2){
        	System.out.println(br.readLine());
        	System.out.println(br.readLine());
            break;//考虑到只题目要求用户登录成功提示登录成功并显示功能模块
                  //因此登陆成功并显示具体操作时程序便结束
         }
  • 登录失败,退出系统
		break;
  • 退出系统,关闭流
        input.close();
        ps.close();
        br.close();
        socket.close();

客户端完整代码如下:

    public static ExpressView v = new ExpressView();

    //客户端
    public static void main(String[] args) throws IOException {
        //      连接到服务器
        Socket socket = new Socket("127.0.0.1",55555);

        //给服务器发消息
        OutputStream os = socket.getOutputStream();
        PrintStream ps = new PrintStream(os);
        
        //接收服务器的消息
        InputStream is = socket.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(is));

        //读取键盘输入
        BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
        
        String receive,send;
        
        //进入系统
        receive = br.readLine();
        System.out.println(receive);

        //主菜单与登录界面
        while(true){
            //收消息,服务器发送的提示内容
            receive = br.readLine();
            System.out.println(receive);
            if("登陆成功!".equals(receive) ){
                int num = Integer.parseInt(br.readLine());
                if(num == 1){
                    System.out.println(br.readLine());
                    System.out.println(br.readLine());
                    System.out.println(br.readLine());
                    System.out.println(br.readLine());
                    System.out.println(br.readLine());
                    System.out.println(br.readLine());
                    System.out.println(br.readLine());
                    break;//考虑到只题目要求用户登录成功提示登录成功并显示功能模块
                    //因此登陆成功并显示具体操作时程序便结束
                }else if(num == 2){
                    System.out.println(br.readLine());
                    System.out.println(br.readLine());
                    break;//考虑到只题目要求用户登录成功提示登录成功并显示功能模块
                    //因此登陆成功并显示具体操作时程序便结束
                }
            }else if("用户名或密码错误!登录失败!".equals(receive)){
                break;
            }

            //发消息
            send = input.readLine();
            ps.println(send);

            if("0".equals(send)){
                System.out.println(v.bye());
                break;
            }

        }//end while 聊天结束

        input.close();
        ps.close();
        br.close();
        socket.close();
    }
  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Selcouther

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值