Swing实战和JDK8新特性

Version:邢朋辉

一、今日内容

1.课程回顾

1.TCP:传输控制协议

​ 面向连接、安全可靠、传输不限大小、性能相对不高

​ 核心类:

​ ServerSocket:服务端

​ 核心方法:

​ accept 监听、阻塞 客户端的连接

​ Socket:客户端

​ 一个服务端可以有多个客户端

​ 核心方法:

​ getInputStream 输入流 接收对方发送的数据信息 读取

​ getOutputStream 输出流 发送数据

2.UDP:数据报通信协议

​ 面向无连接、不可靠传输、传输大小不能64KB 性能高效

​ 核心类:

​ DatagramPacket 数据报包 可以实现接收、发送的数据载体

​ 核心方法:

​ 1.getLength 获取内容的长度

​ 2.setPort 设置端口号

​ DatagramSocket 数据报套接字

​ 核心方法:

​ 1.send 发送数据报包

​ 2.receive 接收数据报包

IP和端口号

2.基于swing的聊天室

3.JDK8的新特性

二、基于Swing的聊天室
2.1 需求

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mg02jDbz-1591536560844)(img/001.png)]

请实现老邢设计的聊天室,原型图如上所示。要是可以进行多人聊天。

2.2 需求分析

1.需求是什么

2.明白自己要做什么

3.思考自己要做的顺序

4.按部就班

5.开发过程中,遇河填河

1.绘制UI界面

2.添加点击事件

3.完善事件需要做的事情

项目的核心涉及:

1.服务端 实现聊天室消息的转发、在线用户等 不需要界面

2.客户端 实现聊天的程序 安装客户端 基于Swing绘制界面

消息格式:昵称:消息

2.3 需求实现

1.绘制界面 基于Swing

2.实现代码

示例代码:封装用户类 用户的信息

public class UserTalk {
	private String name;//昵称
	private String ip;//IP地址
	private int port;//端口号
	
	/**
	 * 
	 */
	public UserTalk() {
		super();
	}
	/**
	 * @param name
	 * @param ip
	 * @param port
	 */
	public UserTalk(String name, String ip, int port) {
		super();
		this.name = name;
		this.ip = ip;
		this.port = port;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getIp() {
		return ip;
	}
	public void setIp(String ip) {
		this.ip = ip;
	}
	public int getPort() {
		return port;
	}
	public void setPort(int port) {
		this.port = port;
	}
	@Override
	public String toString() {
		return ip+"-"+port+"-"+name;
	}
	@Override
	public int hashCode() {
		// TODO Auto-generated method stub
		return name.hashCode();
	}
	@Override
	public boolean equals(Object obj) {
		//校验对象的真正的数据类型
		if(obj instanceof UserTalk) {
			UserTalk ut=(UserTalk) obj;
			return name.equals(ut.name);
		}else {
			return false;
		}
	}
}

示例代码:日期工具类 提供日期的常用操作

public class DateUtil {
	//格式化日期
	public static String format(Date date) {
		SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
		return sdf.format(date);
	}
}

示例代码:封装文件操作工具类 主要实现聊天信息的本地保存

public class FileUtil {
	//封装 记录聊天日志
	public static void log(String msg) {
		//每天一个日志文件
		File f=new File("chatlog");
		if(!f.exists()) {
			f.mkdirs();
		}
		FileWriter fw=null;
		try {
			fw=new FileWriter(f.getName()+"/"+DateUtil.format(new Date())+".log",true);
			fw.write(msg+"\r\n");
			fw.flush();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			try {
				fw.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}	
	}
}

示例代码:完善聊天室服务端的类

public class TalkRoom {

	public static void main(String[] args) throws Exception{
		//1、创建套接字
		DatagramSocket socket=new DatagramSocket(10010);
		//2、集合 记录 在线的用户信息(昵称、ip、端口号 昵称唯一)
		HashSet<UserTalk> ads=new HashSet<>();
		//3、准备发送和接收的字节数组
		byte[] sarr=new byte[1024];
		byte[] rarr=new byte[1024];
		//4、实例化 数据报包
		DatagramPacket sdata=new DatagramPacket(sarr, sarr.length);
		DatagramPacket rdata=new DatagramPacket(rarr, rarr.length);
		String msg;
		System.out.println("*******聊天室*******");
		//5、循环 接收和转发消息
		while(true) {
			//接收消息
			socket.receive(rdata);
			//获取接收到的消息 消息格式:昵称:消息内容
			msg=new String(rarr,0,rdata.getLength());
			String[] marr=msg.split(":");
			//校验当前客户端是否已经记录
			UserTalk ut1=new UserTalk();
			ut1.setName(marr[0]);
			if(!ads.contains(ut1)) {
				ads.add(new UserTalk(marr[0],rdata.getAddress().getHostAddress(),rdata.getPort()));
				//用户第一次加入到聊天室,发送系统广播
				sendMsg(socket, sdata, ads, "@:欢迎"+marr[0]+"加入聊天室");
				//第一次加入聊天室,聊天室需要发送在线用户列表
				for(UserTalk ut:ads) {
					sendMsg(socket, sdata, ads, "us:"+ut);
				}
				System.err.println("在线用户:"+ads);
			}
			//记录日志信息到文件中
			FileUtil.log(msg);
			System.err.println("聊天室:"+msg);
			//转发消息 其他人 不包含发消息的人
			for(UserTalk ut:ads) {
				//不包含发消息的人
				if(!ut.getName().equals(marr[0])) {
					sdata.setAddress(InetAddress.getByName(ut.getIp()));
					sdata.setPort(ut.getPort());
					sdata.setData(msg.getBytes());
					socket.send(sdata);
				}
			}
		}
	}
	//发送全体消息
	private static void sendMsg(DatagramSocket socket,DatagramPacket sdata,HashSet<UserTalk> ads,String msg) {
		//转发消息 其他人 不包含发消息的人
		for(UserTalk ut:ads) {
			try {
				sdata.setAddress(InetAddress.getByName(ut.getIp()));
				sdata.setPort(ut.getPort());
				sdata.setData(msg.getBytes());
				socket.send(sdata);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

示例代码:聊天室的客户端程序 基于Swing UDP

public class TalkClient extends JFrame {

	//Swing组件
	private JPanel contentPane;
	private JTextField nickname; //昵称
	private JTextField port;//本地的端口号
	private JTextField tip;//聊天室的ip
	private JTextField tport; //聊天室端口号
	private JLabel lblNewLabel;
	private JPanel panel_1;
	private JList list;
	private JScrollPane scrollPane;
	private JTextField tmsg;//要发送的聊天内容

	//聊天信息
	private UserTalk user;//当前用户
	private DatagramSocket socket;//套接字对象
	private DatagramPacket sendData;//发送报包
	private DatagramPacket receiveData;//接收报包
	private byte[] sarr=new byte[1024];//发送数组
	private byte[] rarr=new byte[1024];
	private JList listchatmsg;//组件 列表 可以显示多条数据 聊天信息
	private JList listuser;//组件 列表 可以显示多条数据  在线用户
	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		//采用子线程的模式运行窗口
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					TalkClient frame = new TalkClient();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the frame.
	 */
	public TalkClient() {
		//设置窗口的logo
		setIconImage(Toolkit.getDefaultToolkit().getImage("H:\\Class\\NZ-Java-2005\\Day35\\img\\logo.PNG"));
		//设置窗口的标题
		setTitle("\u8001\u90A2\u591C\u804A\u5427");
		//设置是否具备 关闭
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		//设置大小
		setBounds(100, 100, 800, 600);
		//内容模块
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		contentPane.setLayout(new BorderLayout(0, 0));
		setContentPane(contentPane);
		
		JPanel panel = new JPanel();
		contentPane.add(panel, BorderLayout.NORTH);
		
		//声明 用来记录聊天信息
		DefaultListModel dlm=new DefaultListModel<>();
		listchatmsg = new JList(dlm);
		listchatmsg.setAutoscrolls(true);
		
		//实例化 用来记录在线用户
		DefaultListModel users=new DefaultListModel<>();
		listuser=new JList(users);
		listuser.setAutoscrolls(true);
		
		
		
		//聊天室 基本信息的设置 
		lblNewLabel = new JLabel("\u804A\u5929\u5BA4\u8BBE\u7F6E\uFF1A");
		panel.add(lblNewLabel);
		//昵称
		nickname = new JTextField();
		nickname.setText("\u72D7\u86CB");
		nickname.setToolTipText("");
		panel.add(nickname);
		nickname.setColumns(10);
		
		//本机端口号
		port = new JTextField();
		port.setText("8807");
		port.setToolTipText("");
		panel.add(port);
		port.setColumns(10);
		
		//聊天室ip
		tip = new JTextField();
		tip.setText("127.0.0.1");
		tip.setToolTipText("");
		panel.add(tip);
		tip.setColumns(10);
		
		//聊天室端口号
		tport = new JTextField();
		tport.setText("10010");
		tport.setToolTipText("");
		panel.add(tport);
		tport.setColumns(10);
		
		//进入聊天室 按钮
		JButton btnconnect = new JButton("\u8FDB\u5165\u804A\u5929\u5BA4");
		//设置 按钮的点击事件
		btnconnect.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				//发起消息发送,进入聊天室
				//刷新左侧的 在线用户、接收 系统消息  线程
				//校验输入的值 是否合法
				try {
					//实例化当前的用户信息
					user=new UserTalk(nickname.getText(),InetAddress.getLocalHost().getHostAddress(),Integer.parseInt(port.getText()));
					System.err.println(user);
					//实例化 发送的数据报包
					sendData=new DatagramPacket(sarr, sarr.length, InetAddress.getByName(tip.getText()), Integer.parseInt(tport.getText()));
					//实例化 接收消息的数据报包
					receiveData=new DatagramPacket(rarr, rarr.length);
					//实例化 套接字对象
					socket=new DatagramSocket(user.getPort());
					
					//发送连接消息
					sendData.setData((user.getName()+":我来啦").getBytes());
					socket.send(sendData);
					//把接收到的消息,添加到聊天区
					dlm.addElement(user.getName()+":我来啦");
					System.err.println(user.getName());
					//开启接收消息的线程
					new Thread(new Runnable() {
						
						@Override
						public void run() {
							// TODO Auto-generated method stub
							while(true) {
								try {
									//接收消息 
									socket.receive(receiveData);
									String m=new String(rarr,0,receiveData.getLength());
									String[] arr=m.split(":");
									switch (arr[0]) {
									case "@"://系统消息
										//把接收到的消息,添加到聊天区
										dlm.addElement(arr[1]);
										break;
									case "us"://在线用户列表
										if(!users.contains(arr[1])) {
											users.addElement(arr[1]);
										}
										break;
									default://用户消息
										//把接收到的消息,添加到聊天区
										dlm.addElement(m);
										break;
									}
								} catch (IOException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								}
							}
						}
					}).start();
					//进入到聊天室 按钮变为不可用
					btnconnect.setEnabled(false);
				} catch (Exception e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}
		});
		btnconnect.setForeground(Color.RED);
		panel.add(btnconnect);
		
		
		panel_1 = new JPanel();
		panel_1.setBorder(new BevelBorder(BevelBorder.LOWERED, null, null, null, null));
		contentPane.add(panel_1, BorderLayout.WEST);
		panel_1.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));	
				contentPane.add(panel_1, BorderLayout.WEST);
		panel_1.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
		panel_1.add(listuser);
	
		
		scrollPane = new JScrollPane();
		contentPane.add(scrollPane, BorderLayout.CENTER);
		
		scrollPane.setViewportView(listchatmsg);
		
		//发送聊天内容
		JPanel panel_3 = new JPanel();
		contentPane.add(panel_3, BorderLayout.SOUTH);
		
		tmsg = new JTextField();
		tmsg.setHorizontalAlignment(SwingConstants.LEFT);
		tmsg.setText("\u8BF7\u8F93\u5165\u804A\u5929\u5185\u5BB9");
		panel_3.add(tmsg);
		tmsg.setColumns(50);
		//发送按钮
		JButton btnsend = new JButton("\u53D1\u9001\u6D88\u606F");
		btnsend.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				//消息发送
				String m=user.getName()+":"+tmsg.getText();
				sendData.setData(m.getBytes());
				try {
					//发送消息
					socket.send(sendData);
					tmsg.setText("");
					//把接收到的消息,添加到聊天区
					System.err.println(m);
					dlm.addElement(m);
				} catch (IOException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}
		});
		panel_3.add(btnsend);
	}
}
2.4 运行测试

1.先启动 TalkRoom 聊天室服务端 端口号 10010

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OFpcLEHO-1591536560848)(img/002.png)]

2.启动 客户端程序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dbhJDj6L-1591536560850)(img/003.png)]

3.填写聊天室的设置信息,并点击 进入聊天室 按钮

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FRkol3fa-1591536560853)(img/004.png)]

4.发送消息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lN4d72Vl-1591536560855)(img/005.png)]

5.可以查看聊天内容的日志文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4LxuyESk-1591536560857)(img/006.png)]

2.5 程序结构图

整个程序分为2部分,第一部分:聊天室服务端,第二部分:聊天室客户端

第一部分:聊天室服务端 TalkRoom

涉及到的技术:

​ 1.集合、数组、面向对象

​ 2、UDP、IO流

实现的作用:

​ 1.记录当前在线的所有用户

​ 2.接收客户端发送消息并且讲消息转发到各个客户端

​ 3.发送系统消息

​ 1.上线通知 消息格式:@:xxxx

​ 2.在线用户列表 消息格式: us:ip-端口号-昵称

消息格式:

​ 整个消息的组成: 前缀:消息内容

​ 整个消息分为三类:

​ 1.聊天消息 昵称:消息内容

​ 2.上线通知 消息格式:@:xxxx

​ 3.在线用户列表 消息格式: us:ip-端口号-昵称

第二部分:聊天室的客户端

涉及到的技术:

​ 1.集合、常用类、数组

​ 2.线程、UDP、Swing(了解)

实现的功能:

​ 1.界面布局

​ 2.按钮的点击事件 1.加入聊天室 2.发送消息

​ 3.发送消息 到聊天室

​ 4.接收聊天室的消息,并根据三种消息格式进行拆分

程序的缺陷:

1.不能优雅的推出聊天室

2.聊天内容没有左右分离

3.聊天界面,简洁

4.打包exe软件

思考:程序的升级? V2.0

三、JDK8的新特性
3.1 jdk8概述

jdk目前的最新版本是jdk14

目前企业主流的版本:jdk7和jdk8

2014年公布新版本:jdk8 带来了很大变化

特性列表:

1.Lambda表达式

2.方法引用

3.Stream

4.时间Api

3.2 Lambda表达式

Lambda表达式:简化的匿名内部类。简化代码,让代码紧凑型更强。

语法格式:(参数)->{抽象方法的实现}

比如:实现线程、比较器接口comparator、函数式接口

函数式接口:Functional Interfaces 在接口中只有一个抽象方法。

jdk提供的函数式通用接口

Function<T,R>

Consumer

Supplier

示例代码:基于Lambda实现比较器接口

public class Lambda_Main01 {

	public static void main(String[] args) {
		//原来的写法 匿名内部类
		TreeSet<Integer> set=new TreeSet<Integer>(new Comparator<Integer>() {
			@Override
			public int compare(Integer o1, Integer o2) {
				// TODO Auto-generated method stub
				return o1-o2;
			}
		});
		
		//现在的写法 基于Lambda表达式
		TreeSet<Integer> set2=new TreeSet<Integer>((o1,o2)-> {
			return o1-o2;
		});
	}
}

示例代码:Function<T,R>的应用

public class Lambda_Main02 {
	public static void main(String[] args) {
		//演示 Lambda的函数式接口
		//常用的函数式通用接口 Function<T,R>
		List<Integer> list=Arrays.asList(1,3,5,7,2,4);
		
		//函数式通用接口 需要参数 有返回值
		Function<Integer, Integer> f=(Integer i)->{return ++i;};
		
		//应用
		for(Integer i:list) {
			System.err.println(f.apply(i));
		}
	}
	//函数式接口
	public interface MyTest{
		Integer add(Integer i);	
	}
}
3.3 方法引用

jdk8方法引用:凡是使用:: 的引用模型就是方法引用,主要目的是为了简化Lambda表达式。还可以简化静态方法的调用

规则: 使用 双冒号 调用一些方法

1.代替 Lambda表达式作为参数的形式

2.对象名:: 实例方法名

3.类名:: 静态方法

示例代码:方法引用的常用形式

public class Method_Main01 {
	public static void main(String[] args) {
		//演示 方法引用 ::
		
		//1.最早的写法 匿名内部类
		d(new Parint() {
			@Override
			public void show(String msg) {
				// TODO Auto-generated method stub
				System.out.println(msg);
			}
		});
		
		//2.原来的写法 基于Lambda表达式
		d((s)->{System.out.println(s);});
		
		
		//3.使用方法引用 简化 使用Lambda表达式作为参数传递的形式
		d(System.out::println);
	}
	
	//定义函数
	public static void d(Parint p) {
		p.show("方法引用");
	}
	//函数式接口 
	public interface Parint{
		void show(String msg);
	}
}
public class Method_Main02 {

	public static void main(String[] args) {
		Date d=new Date();
		//方法引用 对象名::实例方法名
		Supplier<Long> s=d::getTime;
		System.err.println(s.get());
		//方法引用  类名:: 静态方法
		Supplier<Long> s2=System::currentTimeMillis;
		System.err.println("当前的毫秒数:"+s2.get());
		
		System.err.println(Math.abs(-2));
		
		ms(-22,Math::abs);
		
	}
	//自定义静态方法
	public static void ms(int num,Calcable c) {
		System.err.println(c.js(num));
	}
	//自定义函数式接口
	public static interface Calcable{
		double js(int num);
	}
}
3.4 Stream

Stream:jdk 8新增一个抽象的流 可以声明式的处理数据 操作集合、数据库等的元素

常用的方法:

1.sorted 排序

2.limit 限制 需要的元素个数

3.filter 过滤 筛选

4.forearch 遍历

public class Stream_Main01 {

	public static void main(String[] args) {
		//实例化集合
		List<Integer> list=Arrays.asList(11,22,10,4,6,19);
		//排序并遍历  sorted排序 升序   forEach遍历  方法引用  Lambda表达式
		list.stream().sorted().forEach(System.out::println);
		System.out.println();
		//输入集合中元素大于15 的元素 过滤 
		list.stream().filter(i->{return i>15;}).limit(1).forEach(System.out::println);
		
	
		Random rm=new Random();
		//限制
		rm.ints(100).limit(10).forEach(System.out::println);
	}
}
3.5 新的时间API

jdk8更新了时间类

LocalDate 日期类 包含:年月日

LocalDateTime:时间类

示例代码:演示新日期的使用

public class Date_Main {

	public static void main(String[] args) {
		//日期类
		LocalDate ld=LocalDate.now();
		System.err.println(ld);
		//时间类
		LocalDateTime ldt=LocalDateTime.now();
		System.err.println(ldt);
		
		//昨天
		LocalDate ld2=LocalDate.of(ld.getYear(), ld.getMonth(), ld.getDayOfMonth()-1);
		System.err.println(ld2);
	}
}
四、一阶段考核项目

sorted排序 升序 forEach遍历 方法引用 Lambda表达式
list.stream().sorted().forEach(System.out::println);
System.out.println();
//输入集合中元素大于15 的元素 过滤
list.stream().filter(i->{return i>15;}).limit(1).forEach(System.out::println);

	Random rm=new Random();
	//限制
	rm.ints(100).limit(10).forEach(System.out::println);
}

}




##### 3.5 新的时间API

> jdk8更新了时间类
>
> LocalDate 日期类 包含:年月日
>
> LocalDateTime:时间类 

示例代码:演示新日期的使用

```java
public class Date_Main {

	public static void main(String[] args) {
		//日期类
		LocalDate ld=LocalDate.now();
		System.err.println(ld);
		//时间类
		LocalDateTime ldt=LocalDateTime.now();
		System.err.println(ldt);
		
		//昨天
		LocalDate ld2=LocalDate.of(ld.getYear(), ld.getMonth(), ld.getDayOfMonth()-1);
		System.err.println(ld2);
	}
}
四、一阶段考核项目
4.1. 需求
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值