Java基础 项目实例五 简易聊天系统

项目实例五 简易聊天系统

      • 一、前置知识
      • 二、AWT的基础使用
      • 三、实现cardPanel卡片布局----卡片切换
      • 四、聊天界面实现前置知识
      • 五、GuiChat简易聊天系统(一个成熟的聊天代码)
      • 六、WeiChat简易聊天系统(一个不成熟的聊天代码)

一、前置知识

  1. AWT与Swing
    AWT:抽象窗口工具包,重量级控件。
    Swing:AWT基础上,建立的一套图形界面系统,轻量级空间。(较之AWT界面更为美观)
    轻量级组件的缺点则是执行速度较慢,优点就是可以在所有平台上采用统一的行为。
  2. AWT事件监听:
    事件源(组件)、事件(Event)、监听器(Listener)、事件处理(引发事件后处理方式–处理代码)。
  3. public void windowOpened(windowEvent e):方法,窗口启动时自动执行。
    (注:可以实现弹出窗口,若要关闭窗口则关闭程序;可以实现启动时加载文字信息;可以实现弹出提示信息。)
  4. 流程布局将组件布置在定向流中,流向由容器的componentOrientation属性确定,可以是两个值之一:
    1. ComponentOrientation.LEFT_TO_RIGHT
    2. ComponentOrientation.RIGHT_TO_LEFT
  5. 流程布局通常用于布置面板中的按钮。 它可以水平排列按钮,直到不再有按钮在同一行上。 线对齐由align属性确定。 可能的值是:
    LEFT、RIGHT、CENTER、LEADING、TRAILING
  6. 监听器有:窗口监听器、键盘监听器、鼠标监听器、动作监听器。
  7. 五种布局管理器:
    1. FlowLayout、BorderLayout、GridLayout、GridBagLayout、CardLayout
    2. FlowLayout:基本布局,从左到右,从上至下。
    3. BorderLayout:边界布局管理器,东西南北中,五个方位。
    4. GridLayout:网格布局,划分区块大小相同。
    5. GridBagLayout:网格包布局,网格布局升级,划分区块大小可不一致。
    6. CardLayout:卡片布局。切换程序。(常用:卡片布局注册到监听器中,监听器绑定按钮,实现切换程序页面。)

二、AWT的基础使用

  1. package cn.itcast.test4;
    import java.awt.*;
    import java.awt.event.*;
    public class Javatest7 {
    	/**
    	 *@Title Javatest7.java
    	 *@description TODO
    	 *@time 2020-4-20 上午12:14:49
    	 *@author 羽落清泫
    	 *@version 1.0
    	 **/
    	public static void main(String[] args) {
    		//创建窗体对象
    		final Frame f= new Frame("AWT窗口绘制");	//创建一个名为AWT窗口绘制的窗体
    		//设置窗体属性
    		// 设置窗体中的布局管理器为FlowLayout,所有组件左对齐,水平间距为20,垂直间距为30
    		f.setLayout(new FlowLayout(FlowLayout.LEFT, 20, 30));		//LEFT、RIGHT、CENTER、LEADING、TRAILING
    //		f.setTitle("关闭窗口");	//该窗口名设置,比Frame定义名优先级要高
    		f.setSize(800,600);		//f.setSize(600,800);// 设置窗体大小
    		f.setLocation(550,270);		//f.setLocation(550,270);// 设置窗体显示的位置
    //-------------------------------------------------		
    		//适配器类,实现重写方法,点右上×,可关闭窗口
    		//个人理解:一个窗口监听器,点击窗口关闭则关闭
    		f.addWindowListener(new WindowAdapter(){	
    			public void windowClosing(WindowEvent e){
    				System.exit(0);
    			}
    		});
    		TextField tf = new TextField(40);		//单行文本框,长度40
    		f.add(tf);
    		//一个键盘事件监听,
    		tf.addKeyListener(new KeyAdapter() {
    			public void keyPressed(KeyEvent e){	//键盘监听
    				int code = e.getKeyCode();		
    					//getKeyChar():处理的是比较高层的事件,返回的是每欠敲击键盘后得到的字符(中文输入法下就是汉字)。
    					//getKeyCode()键盘上每一个按钮都有对应码(Code),可用来查知用户按了什么键
    					//getKeyModifiersText()方法可返回修饰键的字符串,如返回“Shift”字符串或是“Ctrl+Shift”字符串, 不过你要先传入modifiers参数。
    				if(!(code>=KeyEvent.VK_0 && code<=KeyEvent.VK_9)){	//VK_0 && VK_9:定义数据字符0~9
    				System.out.println("必须是0-9数字");	//经测试有Bug:当中文输入法时,按出一串字符,以回车方式输入文本框中将不会提示[必须是0-9数字].
    				}
    			}
    		});
    //-----------------------------------------------
    		f.setVisible(true);		// 设置窗体可见
    	}
    }
    

三、实现cardPanel卡片布局----卡片切换

  1. package cn.itcast.test4;
    import java.awt.*;
    import java.awt.event.*;
    public class Javatest8 {
    	/**
    	 *@Title Javatest8.java
    	 *@description 简易聊天系统--(swing体系)
    	 *@time 2020-4-20 下午2:53:14
    	 *@author 羽落清泫
    	 *@version 1.0
    	 **/
    	public static void main(String[] args) {
    		new Chat();
    	}
    }
    //定义Chat继承Frame类,实现ActionListener接口
    class Chat extends Frame implements ActionListener {
    	private static final long serialVersionUID = 1L;
    	Button but1,but2;		//定义两个按钮,实现点击按钮,面板切换
    	Panel p1=new Panel();	//p1面板:实现页面内容展示
    	Panel p2=new Panel();	//p2面板,封装按钮,实现展示按钮
    	CardLayout cardLayout = new CardLayout();// 定义卡片布局对象
    	public Chat(){			// 定义构造方法,设置(卡片布局管理器的)属性
    		setTitle("简易聊天系统--(Swing体系)");	//设置窗口名
    		setSize(800, 600);	// 设置窗体大小
    		setLocation(550,270);	//f.setLocation(550,270);// 设置窗体显示的位置
    		setVisible(true);
    		// 为窗口添加关闭事件监听器
    		this.addWindowListener(new WindowAdapter() {
    			public void windowClosing(WindowEvent e) {
    				Chat.this.dispose();
    			}
    		});
    		p1.setLayout(cardLayout);		// 调用定义的布局对象,设置p1面板对象为卡片布局
    //-------------------------------------------------------
    		// 在cardPanel面板对象中添加2个文本标签
    		Label b1=new Label("第一个界面", Label.CENTER);
    		p1.add(b1);
    		// 创建两个按钮对象
    		but1 = new Button("第一张卡片");
    		but2 = new Button("第二张卡片");
    		//按钮对象绑定动作监听器
    		but1.addActionListener(this);
    		but2.addActionListener(this);
    		//按钮绑定面板
    		p2.add(but1);
    		p2.add(but2);
    		// 将p1面板放置在窗口边界布局的中间,窗口默认为边界布局
    		this.add(p1, BorderLayout.CENTER);
    		// 将p2面板放置在窗口边界布局的北区,
    		this.add(p2, BorderLayout.NORTH);	//NORTH、SOUTH、CUNTER、EAST、WEAST
    	}
    //------------------------------------------
    	//实现按钮的监听触发,并对触发事件做出相应的处理(动作监听器)
    	public void actionPerformed(ActionEvent e) {
    //		// 切换p1面板中当前组件后一个面板,若当前面板为最后一个组件,则显示第一个面板。
    //		if(e.getSource()==but1){
    //			cardLayout.next(p1);
    //		}
    //		//// 切换p1面板中当前组件前一个面板
    //		if(e.getSource()==but2){
    //			cardLayout.previous(p1);
    //		}
    		if(e.getSource()==but1){
    			cardLayout.first(p1);
    			this.setTitle("聊天页");
    		}
    		if(e.getSource()==but2){
    			cardLayout.last(p1);
    			this.setTitle("展示信息页");
    		}
    	}
    //------------------------------------------
    }
    

四、聊天界面实现前置知识

  1. . 网络模型:OSI(开放系统互连)
  2. IP地址:网络中设备的地址(数字或主机名)(InetAddress)
  3. 端口号:用于表示进程的逻辑地址,有效端口:0-65535。(0-1024为系统保留端口。)
  4. UDP:不建立连接,不可靠协议,速度快。
    TCP:建立连接,形成传输数据的通道。
  5. UDP方法:
    1. DatagramPacket:UDP发送端方法。
    2. DatagramSocket:UDP接收端方法。

五、GuiChat简易聊天系统(一个成熟的聊天代码)

  1. package cn.test;
    import java.io.*;
    import java.net.*;
    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    public class GuiChat extends JFrame{
    	private static final long serialVersionUID = 1L;	////赋予一个UID,消除GuiChat黄色警告
    	private static final int DEFAULT_PORT = 8899;
    	// 把主窗口分为NORTH、CEMTER和SOUTH三个部分
    	private JLabel stateLB; // 显示监听状态
    	private JTextArea centerTextArea;       // 显示聊天记录
    	private JPanel southPanel;               // 最下面的面板
    	private JTextArea inputTextArea;        // 聊天输入框
    	private JPanel bottomPanel;              // 放置 IP输入框,按钮等
    	private JTextField ipTextField;         // IP输入框
    	private JTextField remotePortTF;        // 端口号输入框
    	private JButton sendBT;                   // 发送按钮
    	private JButton clearBT;                  // 清除聊天记录按钮
    	private DatagramSocket datagramSocket; // 用于后面功能的实现
    	private void setUpUI() {               // 初始化Swing窗口
    		// 初始化窗口
    		setTitle("GUI聊天");
    		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    		setSize(400, 400);             // 设置窗口的大小
    		setResizable(false);           // 窗口大小不可调整
    		setLocationRelativeTo(null); // 窗口居中
    		// 窗口的NORTH部分
    		stateLB = new JLabel("当前还未启动监听");
    		stateLB.setHorizontalAlignment(JLabel.RIGHT);
    		// 窗口的CENTER部分
    		centerTextArea = new JTextArea();     // 聊天记录显示区域
    		centerTextArea.setEditable(false);
    		centerTextArea.setBackground(new Color(211, 211, 211));
    		// 窗口的SOUTH部分
    		
    		
    		
    		southPanel = new JPanel(new BorderLayout());
    		
    		inputTextArea = new JTextArea(5, 20);// 内容输入区域
    		bottomPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 5));
    		ipTextField = new JTextField("127.0.0.1", 8);
    		remotePortTF = new JTextField(String.valueOf(DEFAULT_PORT), 3);
    		sendBT = new JButton("发送");
    		clearBT = new JButton("清屏");
    		bottomPanel.add(ipTextField);
    		bottomPanel.add(remotePortTF);
    		bottomPanel.add(sendBT);
    		bottomPanel.add(clearBT);
    		southPanel.add(new JScrollPane(inputTextArea), BorderLayout.CENTER);
    		southPanel.add(bottomPanel, BorderLayout.SOUTH);
    		// 添加窗口NORTH、CENTER、SOUTH部分的组件
    		add(stateLB, BorderLayout.NORTH);
    		add(new JScrollPane(centerTextArea), BorderLayout.CENTER);
    		add(southPanel, BorderLayout.SOUTH);
    		
    		setVisible(true);
    	}
    	private void setListener() {
            // 为sendBT按钮添加事件监听器
    		sendBT.addActionListener(new ActionListener() {
    			public void actionPerformed(ActionEvent e) {
    				// 获取发送的目标ip地址和端口号
    				final String ipAddress = ipTextField.getText();
    				final String remotePort = remotePortTF.getText();
    				// 判断ip地址和端口号是否为空
    				if (ipAddress == null || ipAddress.trim().equals("")
    						|| remotePort == null || remotePort.trim().equals("")) {
    					JOptionPane.showMessageDialog(GuiChat.this, "请输入IP地址和端口号");
    					return;
    				}
    				if (datagramSocket == null || datagramSocket.isClosed()) {
    					JOptionPane.showMessageDialog(GuiChat.this, "监听不成功");
    					return;
    				}
    				// 获得需要发送的内容
    				String sendContent = inputTextArea.getText();
    				byte[] buf = sendContent.getBytes();
    				try {
    					// 将发送的内容显示在自己的聊天记录中
    					centerTextArea.append("我对 " + ipAddress + ":" + remotePort + " 说:\n" + inputTextArea.getText() + "\n\n");
    					// 添加内容后,使滚动条自动滚动到最底端
    					centerTextArea.setCaretPosition(centerTextArea.getText().length());
    					// 发送数据
    					datagramSocket.send(new DatagramPacket(buf, buf.length,InetAddress.getByName(ipAddress), Integer.parseInt(remotePort)));
    					inputTextArea.setText("");
    				} catch (IOException e1) {
    					JOptionPane.showMessageDialog(GuiChat.this, "出错了,发送不成功");
    					e1.printStackTrace();
    				}
    			};
    		});
           // 为clearBT按钮添加事件监听器
    		clearBT.addActionListener(new ActionListener() {
    			public void actionPerformed(ActionEvent e) {
    				centerTextArea.setText(""); // 清空聊天记录的内容
    			}
    		});
    	}
    	private void initSocket() {
    		int port = DEFAULT_PORT;
    		while (true) {
    			try {
    				if (datagramSocket != null && !datagramSocket.isClosed()) {
    					datagramSocket.close();
    				}
    				try { // 判断端口号是否在1-65535之间
    					port = Integer.parseInt(JOptionPane.showInputDialog(this,"请输入端口号", "端口号", JOptionPane.QUESTION_MESSAGE));
    					if (port < 1 || port > 65535) {
    						throw new RuntimeException("端口号超出范围");
    					}
    				} catch (Exception e) {
    					JOptionPane.showMessageDialog(null,"你输入的端口不正确,请输入1-65535之间的数");
    					continue; // 端口不正确重新填写
    				}
    				// 启动DatagramSocket
    				InetAddress localAddress = null;
    				datagramSocket = new DatagramSocket(port);
    				startListen(); // 调用startListen方法
    				// 在stateLB中显示程序监听的端口号
    				try {
    					localAddress = InetAddress.getLocalHost();
    				} catch (UnknownHostException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    				stateLB.setText("本机IP为:"+localAddress.getHostAddress()+","+"已在 " + port + " 端口监听");
    				break;
    			} catch (SocketException e) { // 端口号被占用重新填写
    				JOptionPane.showMessageDialog(this, "端口已被占用,请重新设置端口");
    				stateLB.setText("当前还未启动监听");
    			}
    		}
    	}
    	private void startListen() {
    		new Thread() {
    			private DatagramPacket p;
    			public void run() {
    				byte[] buf = new byte[1024];
    				// 创建DatagramPacket
    				p = new DatagramPacket(buf, buf.length);
    				while (!datagramSocket.isClosed()) {
    					try {
    						datagramSocket.receive(p); // 接收聊天消息
    						// 添加到聊天记录框
    						centerTextArea.append(p.getAddress().getHostAddress()
    								+ ":"
    								+ ((InetSocketAddress) p.getSocketAddress())
    										.getPort() + " 对我说:\n"
    								+ new String(p.getData(), 0, p.getLength())
    								+ "\n\n");
    						// 使滚动条自动滚动到最底端
    						centerTextArea.setCaretPosition(centerTextArea.getText().length());
    					} catch (IOException e) {
    						e.printStackTrace();
    					}
    				}
    			}
    		}.start();
    	}
    	public GuiChat() {
    		setUpUI();
    		initSocket();
    		setListener();
    	}
    	public static void main(String[] args) {
    		new GuiChat();
    	}
    }
    

六、WeiChat简易聊天系统(一个不成熟的聊天代码)

  1. package cn.itcast.test4;
    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    import java.io.*;
    import java.net.*;
    public class Javatest9 {
    	/**
    	 *@Title Javatest9.java
    	 *@description 简易聊天系统
    	 *@time 2020-4-20 下午5:03:54
    	 *@author 羽落清泫
    	 *@version 1.0
    	 **/
    	public static void main(String[] args) {
    		// 实例化Chat,调用
    		new WeiChat();
    		new ServerDemo();	
    	}
    }
    class WeiChat{
    	//	private static final long serialVersionUID = 1L;//赋予一个UID,消除Chat黄色警告
    	private DatagramSocket datagramSocket; // 用于后面功能的实现
    	private JTextArea jt1;
    	public WeiChat(){
    	  JFrame f = new JFrame("简易聊天系统--发送端");
    //    f.setTitle("Swing体系--简易聊天系统");
    	  f.setSize(400, 600);	// 设置窗体大小
    	  f.setLocation(750,270);	//f.setLocation(550,270);// 设置窗体显示的位置
    //	  setResizable(false);           // 窗口大小不可调整
    //	  setLocationRelativeTo(null); // 窗口居中
    //	  // 设置流式布局管理器
    //	  f.setLayout(new FlowLayout());
    //--------------------------------------
    	  //创建菜单项
    		JMenuBar menuBar = new JMenuBar(); // 创建菜单栏
    		f.setJMenuBar(menuBar);            // 将菜单栏添加到JFrame窗口中
    		JMenu menu = new JMenu("操作");     // 创建菜单
    		JMenu menu2 = new JMenu("测试1");   // 创建菜单
    		menuBar.add(menu);                 // 将菜单添加到菜单栏上
    		menuBar.add(menu2);
    		// 创建菜单项
    		JMenuItem item1 = new JMenuItem("弹出窗口");
    		JMenuItem item2 = new JMenuItem("关闭");
    		JMenuItem item3 = new JMenuItem("模态对话框");
    		JMenuItem item4 = new JMenuItem("非模态对话框");
    		menu.add(item1);
    		menu.add(item2);
    		menu2.add(item3);
    		menu2.addSeparator();  // 添加一个分隔符
    		menu2.add(item4);
    //--------------------------------------
    		//-------------窗口NORTH---------------------
    		JLabel jl1=new JLabel("标签");	// 显示监听状态
    		jl1.setHorizontalAlignment(JLabel.RIGHT);	//文本设置左右对齐方法
    		f.add(jl1,BorderLayout.NORTH);
    		//-------------窗口CONTER--------------------
    	  jt1 = new JTextArea("在此处显示聊天内容:",80, 20);
    	  jt1.setEditable(false);	//设置文本域只显示,不可编辑
    	  jt1.setMargin(new Insets(5, 5, 5, 5));	//设置文本(聊天信息)在文本域内显示的边距
    	  jt1.setBackground(new Color(222, 222, 222));	//颜色最大值(255,255,255)
    	  jt1.setSize(100,300);
    	  f.add(new JScrollPane(jt1), BorderLayout.CENTER);
    	//-------------窗口SOUTH-----------
    	  JPanel jl0=new JPanel(new BorderLayout());	//用于装所有组件,放到窗口南部
    	  JPanel jl2 = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 5));	//按流式布局装入按钮等组件
    	  final JTextArea  jt2=new JTextArea(5, 10);			//用于文本输入
    //	  jt2.setPreferredSize(new Dimension (30,30));			//
    	  final JTextField ipTextF = new JTextField("192.168.151.161", 8);		//设置默认IP地址为:"127.0.0.1"
    	  final JTextField remotePort = new JTextField(String.valueOf("8859"), 3);	//设置默认端口号为:8859
    	  JButton but11 = new JButton("发送");
    	  jl2.add(ipTextF);
    	  jl2.add(remotePort);
    	  jl2.add(but11);
    	  jl0.add(new JScrollPane(jt2),BorderLayout.CENTER);
    	  jl0.add(jl2,BorderLayout.SOUTH);
    	  f.add(jl0,BorderLayout.SOUTH);
    	//遇到的问题,当窗口长宽过大时,窗口内文本(域)标签会自适应窗口,无法设置文本标签与窗口之间的(间隔)留白--边框间距问题---------
    	//试解决方案1:设置空的标签组件,设置BorderLayout布局为EAST、WEST,是否解决(待定)
    	//试解决方案2:设置其它面板,按方案一的方法,试解决边框间距问题(待定)
    	  // 设置点击关闭按钮时的默认操作
      	  f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      	  f.setVisible(true);
    //----------------------------------------
    //--------------------------------------
    	  	final JLabel label = new JLabel();
    		final JDialog dialog = new JDialog(f, "Dialog"); // 定义一个JDialog对话框
    		final JButton btn3 = new JButton("确定");          // 创建按钮对象
    		dialog.add(btn3); // 在对话框的内容面板添加按钮
    		// 为"模态对话框"按钮添加点击事件
    		item3.addActionListener(new ActionListener() {
    			public void actionPerformed(ActionEvent e) {
    				dialog.setSize(220, 150);                         // 设置对话框大小
    				dialog.setLocation(830, 500);                     // 设置对话框位置
    				dialog.setLayout(new FlowLayout());               // 设置布局管理器
    				// 设置对话框为模态
    				dialog.setModal(true);
    				// 如果JDialog窗口中没有添加了JLabel标签,就把JLabel标签加上
    				if (dialog.getComponents().length == 1) {
    					dialog.add(label);
    				}
    				// 否则修改标签的内容
    				label.setText("模式对话框,点击确定按钮关闭");
    				// 显示对话框
    				dialog.setVisible(true);
    			}
    		});
    		// 为"模态对话框"按钮添加点击事件
    		item4.addActionListener(new ActionListener() {
    			public void actionPerformed(ActionEvent e) {
    				dialog.setSize(220, 150);                         // 设置对话框大小
    				dialog.setLocation(830, 500);                     // 设置对话框位置
    				dialog.setLayout(new FlowLayout());               // 设置布局管理器
    				// 设置对话框为非模态
    				dialog.setModal(false);
    				// 如果JDialog窗口中没有添加了JLabel标签,就把JLabel标签加上
    				if (dialog.getComponents().length == 1) {
    					dialog.add(label);
    				}
    				// 否则修改标签的内容
    				label.setText("模式对话框,点击确定按钮关闭");
    				// 显示对话框
    				dialog.setVisible(true);
    			}
    		});
    		// 为对话框中的按钮添加点击事件
    		btn3.addActionListener(new ActionListener() {
    			public void actionPerformed(ActionEvent e) {
    				dialog.dispose();
    			}
    		});
    		//item1功能:弹出窗口
    		item1.addActionListener(new ActionListener() {
    			public void actionPerformed(ActionEvent e) {
    				// 创建一个JDialog窗口
    				dialog.setTitle("弹出窗口,测试使用...");
    				dialog.setSize(400, 200);
    				dialog.setLocation(730, 500);
    				dialog.setVisible(true);
    			}
    		});
    		//item2功能:关闭窗体
    		item2.addActionListener(new ActionListener() {
    			public void actionPerformed(ActionEvent e) {
    				System.exit(0);
    			}
    		});
    //---------------------------------------
    	//消息发出与接收代码
    	  //1. 消息发出
    		but11.addActionListener(new ActionListener(){
    			public void actionPerformed(ActionEvent e){
    				//获取信息发送的ip地址与端口
    				String ipAddress=ipTextF.getText();
    				String remote=remotePort.getText();
    				//一般来说此处需要验证ip地址与端口号是否正确
    				try {
    					//获得发送的内容
    					String sendConent =jt2.getText();
    					//获得内容放入一个数组中—————转换成ByteBuf后发送 byte[]
    					byte[] buf=sendConent.getBytes();	//byte[] buf=sendConent.getBytes("UTF-8");
    					//将信息展示到自己的聊天界面
    					jt1.append("\n"+"本地"+ipAddress+":"+remote+"说:"+"  "+jt2.getText()+"\n");
    					//发送数据-------datagramSocket方法需要抛出异常
    					datagramSocket=new DatagramSocket();
    					datagramSocket.send(new DatagramPacket(buf, buf.length,InetAddress.getByName(ipAddress), Integer.parseInt(remote)));
    					//datagramSocket.send(new DatagramPacket(buf, buf.length,InetAddress.getByName(ipAddress), Integer.parseInt(remotePort)));
    										//设置发送后,输入框清空
    					jt2.setText(null);
    				//------------以下为异常抛出,原因暂不知-----------
    				} catch (SocketException e1) {
    					// TODO Auto-generated catch block
    					e1.printStackTrace();
    				} catch (NumberFormatException e1) {
    					// TODO Auto-generated catch block
    					e1.printStackTrace();
    				} catch (UnknownHostException e1) {
    					// TODO Auto-generated catch block
    					e1.printStackTrace();
    				} catch (IOException e1) {
    					// TODO Auto-generated catch block
    					e1.printStackTrace();
    				}
    			}
    		});
    		//2. 设置监听的端口,默认为8859
    		int port = 8859;
    		while(true){
    			try{ // 判断端口号是否在1-65535之间
    				port = Integer.parseInt(JOptionPane.showInputDialog(f,"请输入端口号","端口号",JOptionPane.QUESTION_MESSAGE));
    				if (port < 1 || port > 65535) {		//JOptionPane:可以轻松地弹出一个标准对话框,提示用户获取值或通知他们某些东西	//QUESTION_MESSAGE:用于问题。 
    					throw new RuntimeException("端口号超出范围");
    				}
    			}catch(Exception e){
    				JOptionPane.showMessageDialog(null,"你输入的端口不正确,请输入1-65535之间的数");
    				continue; // 端口不正确重新填写
    			}
    			//启动DatagramSocket
    			InetAddress localAddress = null;	//表示Internet协议(IP)地址。
    				try {
    					datagramSocket = new DatagramSocket(port);
    					startChat();
    				} catch (SocketException e2) {
    					// TODO Auto-generated catch block
    					e2.printStackTrace();
    				}
    			try {
    				localAddress = InetAddress.getLocalHost();	//获取本机IP地址
    			} catch (UnknownHostException e1) {
    				// TODO Auto-generated catch block
    				e1.printStackTrace();
    			}
    			jl1.setText("本机IP为:"+localAddress.getHostAddress()+","+"已在 " + port + " 端口监听");
    			break;
    		}
    }
    //-----------------------------------------
    	//3. 定义一个接收消息的方法,可被调用
    	private void startChat(){
    		new Thread(){
    			private DatagramPacket p;
    			//DatagramPacket:实现无连接分组传送服务,每个消息从一台机器路由到另一台机器
    			public void run(){
    				byte[] buf=new byte[1024];
    				//调用DatagramPacket,并与数组绑定
    				p=new DatagramPacket(buf,buf.length);
    				while(!datagramSocket.isClosed()){
    					try {
    						datagramSocket.receive(p); // 接收聊天消息
    						// 添加到聊天记录框
    						jt1.append(p.getAddress().getHostAddress()
    								+ ":"
    								+ ((InetSocketAddress) p.getSocketAddress())
    										.getPort() + " 对我说:\n"
    								+ new String(p.getData(), 0, p.getLength())
    								+ "\n\n");
    						// 使滚动条自动滚动到最底端
    						jt1.setCaretPosition(jt1.getText().length());
    					} catch (IOException e) {
    						e.printStackTrace();
    					}
    				}
    			}
    		}.start();
    	};
    }
    class ServerDemo {
    	//	private static final long serialVersionUID = 1L;//赋予一个UID,消除Chat黄色警告
    	private DatagramSocket datagramSocket; // 用于后面功能的实现
    	private JTextArea jt1;
    	public ServerDemo(){
    	  JFrame f = new JFrame("简易聊天系统--发送端");
    //    f.setTitle("Swing体系--简易聊天系统");
    	  f.setSize(400, 600);	// 设置窗体大小
    	  f.setLocation(250,270);	//f.setLocation(550,270);// 设置窗体显示的位置
    //	  setResizable(false);           // 窗口大小不可调整
    //	  setLocationRelativeTo(null); // 窗口居中
    //	  // 设置流式布局管理器
    //	  f.setLayout(new FlowLayout());
    //--------------------------------------
    	  //创建菜单项
    		JMenuBar menuBar = new JMenuBar(); // 创建菜单栏
    		f.setJMenuBar(menuBar);            // 将菜单栏添加到JFrame窗口中
    		JMenu menu = new JMenu("操作");     // 创建菜单
    		JMenu menu2 = new JMenu("测试1");   // 创建菜单
    		menuBar.add(menu);                 // 将菜单添加到菜单栏上
    		menuBar.add(menu2);
    		// 创建菜单项
    		JMenuItem item1 = new JMenuItem("弹出窗口");
    		JMenuItem item2 = new JMenuItem("关闭");
    		JMenuItem item3 = new JMenuItem("模态对话框");
    		JMenuItem item4 = new JMenuItem("非模态对话框");
    		menu.add(item1);
    		menu.add(item2);
    		menu2.add(item3);
    		menu2.addSeparator();  // 添加一个分隔符
    		menu2.add(item4);
    //--------------------------------------
    		//-------------窗口NORTH---------------------
    		JLabel jl1=new JLabel("标签");	// 显示监听状态
    		jl1.setHorizontalAlignment(JLabel.RIGHT);	//文本设置左右对齐方法
    		f.add(jl1,BorderLayout.NORTH);
    		//-------------窗口CONTER--------------------
    	  jt1 = new JTextArea("在此处显示聊天内容:",80, 20);
    	  jt1.setEditable(false);	//设置文本域只显示,不可编辑
    	  jt1.setMargin(new Insets(5, 5, 5, 5));	//设置文本(聊天信息)在文本域内显示的边距
    	  jt1.setBackground(new Color(222, 222, 222));	//颜色最大值(255,255,255)
    	  jt1.setSize(100,300);
    	  f.add(new JScrollPane(jt1), BorderLayout.CENTER);
    	//-------------窗口SOUTH-----------
    	  JPanel jl0=new JPanel(new BorderLayout());	//用于装所有组件,放到窗口南部
    	  JPanel jl2 = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 5));	//按流式布局装入按钮等组件
    	  final JTextArea  jt2=new JTextArea(5, 10);			//用于文本输入
    //	  jt2.setPreferredSize(new Dimension (30,30));			//
    	  final JTextField ipTextF = new JTextField("192.168.151.161", 8);		//设置默认IP地址为:"127.0.0.1"
    	  final JTextField remotePort = new JTextField(String.valueOf("11111"), 3);	//设置默认端口号为:11111
    	  JButton but11 = new JButton("发送");
    	  jl2.add(ipTextF);
    	  jl2.add(remotePort);
    	  jl2.add(but11);
    	  jl0.add(new JScrollPane(jt2),BorderLayout.CENTER);
    	  jl0.add(jl2,BorderLayout.SOUTH);
    	  f.add(jl0,BorderLayout.SOUTH);
    	//遇到的问题,当窗口长宽过大时,窗口内文本(域)标签会自适应窗口,无法设置文本标签与窗口之间的(间隔)留白--边框间距问题---------
    	//试解决方案1:设置空的标签组件,设置BorderLayout布局为EAST、WEST,是否解决(待定)
    	//试解决方案2:设置其它面板,按方案一的方法,试解决边框间距问题(待定)
    	  // 设置点击关闭按钮时的默认操作
      	  f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      	  f.setVisible(true);
    //----------------------------------------
    //--------------------------------------
    //	  	final JLabel label = new JLabel();
    		final JDialog dialog = new JDialog(f, "Dialog"); // 定义一个JDialog对话框
    		final JButton btn3 = new JButton("确定");          // 创建按钮对象
    		dialog.add(btn3); // 在对话框的内容面板添加按钮
    		//item2功能:关闭窗体
    		item2.addActionListener(new ActionListener() {
    			public void actionPerformed(ActionEvent e) {
    				System.exit(0);
    			}
    		});
    //---------------------------------------
    	//消息发出与接收代码
    	  //1. 消息发出
    		but11.addActionListener(new ActionListener(){
    			public void actionPerformed(ActionEvent e){
    				//获取信息发送的ip地址与端口
    				String ipAddress=ipTextF.getText();
    				String remote=remotePort.getText();
    				//一般来说此处需要验证ip地址与端口号是否正确
    				try {
    					//获得发送的内容
    					String sendConent =jt2.getText();
    					//获得内容放入一个数组中—————转换成ByteBuf后发送 byte[]
    					byte[] buf=sendConent.getBytes();	//byte[] buf=sendConent.getBytes("UTF-8");
    					//将信息展示到自己的聊天界面
    					jt1.append("\n"+"本地"+ipAddress+":"+remote+"说:"+"  "+jt2.getText()+"\n");
    					//发送数据-------datagramSocket方法需要抛出异常
    					datagramSocket=new DatagramSocket();
    					datagramSocket.send(new DatagramPacket(buf, buf.length,InetAddress.getByName(ipAddress), Integer.parseInt(remote)));
    					//datagramSocket.send(new DatagramPacket(buf, buf.length,InetAddress.getByName(ipAddress), Integer.parseInt(remotePort)));
    										//设置发送后,输入框清空
    					jt2.setText(null);
    				//------------以下为异常抛出,原因暂不知-----------
    				} catch (SocketException e1) {
    					// TODO Auto-generated catch block
    					e1.printStackTrace();
    				} catch (NumberFormatException e1) {
    					// TODO Auto-generated catch block
    					e1.printStackTrace();
    				} catch (UnknownHostException e1) {
    					// TODO Auto-generated catch block
    					e1.printStackTrace();
    				} catch (IOException e1) {
    					// TODO Auto-generated catch block
    					e1.printStackTrace();
    				}
    			}
    		});
    		//2. 设置监听的端口,默认为11111
    		int port = 11111;
    		while(true){
    			try{ // 判断端口号是否在1-65535之间
    				port = Integer.parseInt(JOptionPane.showInputDialog(f,"请输入端口号","端口号",JOptionPane.QUESTION_MESSAGE));
    				if (port < 1 || port > 65535) {		//JOptionPane:可以轻松地弹出一个标准对话框,提示用户获取值或通知他们某些东西	//QUESTION_MESSAGE:用于问题。 
    					throw new RuntimeException("端口号超出范围");
    				}
    			}catch(Exception e){
    				JOptionPane.showMessageDialog(null,"你输入的端口不正确,请输入1-65535之间的数");
    				continue; // 端口不正确重新填写
    			}
    			//启动DatagramSocket
    			InetAddress localAddress = null;	//表示Internet协议(IP)地址。
    			try {
    				datagramSocket = new DatagramSocket(port);
    			} catch (SocketException e2) {
    				// TODO Auto-generated catch block
    				e2.printStackTrace();
    			}
    			startChat();
    			try {
    				localAddress = InetAddress.getLocalHost();	//获取本机IP地址
    			} catch (UnknownHostException e1) {
    				// TODO Auto-generated catch block
    				e1.printStackTrace();
    			}
    			jl1.setText("本机IP为:"+localAddress.getHostAddress()+","+"已在 " + port + " 端口监听");
    			break;
    		}
    }
    //-----------------------------------------
    	//3. 定义一个接收消息的方法,可被调用
    	private void startChat(){
    		new Thread(){
    			private DatagramPacket p;
    			//DatagramPacket:实现无连接分组传送服务,每个消息从一台机器路由到另一台机器
    			public void run(){
    				byte[] buf=new byte[1024];
    				//调用DatagramPacket,并与数组绑定
    				p=new DatagramPacket(buf,buf.length);
    				while(!datagramSocket.isClosed()){
    					try {
    						datagramSocket.receive(p); // 接收聊天消息
    						// 添加到聊天记录框
    						jt1.append(p.getAddress().getHostAddress()
    								+ ":"
    								+ ((InetSocketAddress) p.getSocketAddress())
    										.getPort() + " 对我说:\n"
    								+ new String(p.getData(), 0, p.getLength())
    								+ "\n\n");
    						// 使滚动条自动滚动到最底端
    						jt1.setCaretPosition(jt1.getText().length());
    					} catch (IOException e) {
    						e.printStackTrace();
    					}
    				}
    			}
    		}.start();
    	};
    }
    //--------------其他测试:可删除-----------------------------
    //public class test6 {
    //	/**
    //	 *@Title test6.java
    //	 *@description TODO
    //	 *@time 2020-4-20 下午9:07:57
    //	 *@author 羽落清泫
    //	 *@version 1.0
    //	 * @throws IOException 
    //	 **/
    //	public static void main(String[] args) throws IOException {
    //		// TODO Auto-generated method stub
    //		InetAddress localAddress = InetAddress.getLocalHost();
    //		InetAddress remoteAddress = InetAddress.getByName("www.baidu.com");
    //		System.out.println("本机的IP地址:" + localAddress.getHostAddress());
    //		System.out.println("itcast的IP地址:" + remoteAddress.getHostAddress());
    //		System.out.println("itcast的主机名为:" + remoteAddress.getHostName());
    //	}
    //}
    //该代码BUG待更新中......emmmm......
    

End.

你可能感兴趣的:(Java基础学习)