基于Socket的简易聊天工具

基于Socket的简易聊天工具

​ 简易聊天工具,该聊天工具有服务器端和客户端两个方面,服务端通过套接字与服务器建立连接,服务器会接受客户端的请求,并对客户端做出响应。而客户端则会通过与服务器建立连接,来进行客户端之间P2P的信息交流。

简易聊天工具的功能:

​ 1、登录、注册

​ 2、公聊:多个客户端可以互相通话。每个客户端都可以收到其他客户端的发言。

​ 3、私聊:客户端可以指定一个客户端进行对话,其他客户端收不到信息。

项目设计

1.界面设计

a.注册界面
b.登陆界面
c.聊天界面

2.类的设计

a.UserInfo:用户信息类型
b.DbUtil:工具类,用于存储用户信息到数据库中
c.LoginFrame:登陆窗口
d.RegisterFrame:注册窗口
e.ChatFrame:聊天窗口,客户端
f.ChatServer:服务器

程序编写

1.ChatServer

​ a. 先定义服务端的端口号:8088
​ b. 定义start方法,用于服务器端得主要逻辑的封装
​ c. 在start方法中,调用accept方法,响应客户端
​ d. 获取客户端得输入流,来接受信息
​ e. 获取输出流,向客户端发送数据

2.ChatFrame

​ a. 先实例化Socket对象,指定服务器的ip和port,用于发送请求连接
​ b. 定义start方法,封装客户端的运行逻辑
​ c. 获取客户端的输出流,向服务端发送数据
​ d. 获取客户端的输入流,接受服务端发送的数据

​ ==注意:==如果想让客户端发信息的同时,又收信息,即并发。因此需要多线程技术。

窗体的设计

1.ChatFrame的窗体设计:借用Swing框架

a. 继承JFrame
b.添加 panel,showText,nameText,inputText属性
c.定义init方法,给属性初始化,同时设置窗体的属性信息,如:居中,不可拉伸,可见性等等
d.在start方法中,添加监听器,重写keyReleased方法,监听enter键。接受inputText的信息,调用sendMessage方法进行发送
e.定义sendMessage方法

注意:修改了服务端的代码:返回的数据为客户端发送的数据

2.修改ChatServer

​ a.处理多个客户端
​ 目标:可以运行多个客户端,然后自己能收到自己的信息

公聊的设计

需求:
​ 一个客户端发送的数据,所有的客户端都要收到。

实现:
​ 服务器端可以收到客户端A的数据message,同时服务器端有所有客户端的socket,也就是说服务器端可以有所有客户端的pw,即可以遍历所有的pw 发送数据message。

  1. 设计一个Map属性,用于存储所有的客户端名称与pw得映射关系
  2. 遍历pws,发送某个客户端的信息给所有的客户端。

私聊的设计

需求:
​ 一个客户端发送的数据,只有@××××的那个客户端可以收到消息。

实现:
​ 服务器端可以收到客户端A的数据message,然后读取数据message中是否包含@符号,是则在遍历所有的客户名称是否有该用户,有该用户则把消息单独发送给@××××用户

显示在线的姓名

​ 1.将所有在线人命保存到一个线性表中。然后将线性表发送给每一个客户端。使之显示在nameText文本框中。
​ 2.当有离线的,要及时删除此姓名。

代码实现

1、数据库连接的工具类

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/*连接数据库的工具类*/
public class DbUtil {

	//使用的是mysql-connector-java-8.0.16.jar
	public static final String URL = "jdbc:mysql://localhost:3308/wechat?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC";
	public static final String DRIVER_NAME = "com.mysql.cj.jdbc.Driver";
	public static final String USER_NAME = "root";
	public static final String PASSWORD = "123456";

	private static Connection connection;

	static {
		try {
			Class.forName(DRIVER_NAME);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

	private static Connection getConn() {
		if (connection == null) {
			try {
				connection = DriverManager.getConnection(URL, USER_NAME, PASSWORD);
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return connection;
	}

	/**
	 * 添加用户
	 * @param user
	 */
	public static void save(UserInfo user) {
		// 调用jdbc,连接数据库,存入信息

		Connection conn = getConn();
		String sql = "INSERT INTO admin(username,password) VALUES (?, ?)";
		try {
			PreparedStatement pst = conn.prepareStatement(sql);
			pst.setString(1, user.getUsername());
			pst.setString(2, user.getPassword());
			pst.execute();
		} catch (SQLException e) {
			e.printStackTrace();
		}

	}

	/**
	 * 登陆校验使用
	 */
	public static int query(UserInfo u) {

		Connection conn = getConn();
		List<Object> params = new ArrayList<Object>();
		String sql = "SELECT * FROM admin WHERE 1=1";

		if (u.getId() != null) {
			sql += " and id=?";
			params.add(u.getId());
		}
		if (u.getUsername() != null) {
			sql += " and username=?";
			params.add(u.getUsername());
		}
		if (u.getPassword() != null) {
			sql += " and password=?";
			params.add(u.getPassword());
		}

		try {
			PreparedStatement pst = conn.prepareStatement(sql);
			for (int i = 0; i < params.size(); i++) {
				Object obj = params.get(i);
				if(obj instanceof Long) {
					pst.setLong(i + 1, (Long) obj);
				} else if(obj instanceof String) {
					pst.setString(i + 1, (String) obj);
				} else if(obj instanceof String) {
					pst.setString(i + 1, (String) obj);
				}
			}
			ResultSet rs = pst.executeQuery();
			if(rs.next()) {
				return 1;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return 0;
	}

}

2、用户实体类

public class UserInfo {
	private Long id;
	private String username;	
	private String password;

	public UserInfo() {
	}

	
	public UserInfo(Long id, String username, String password) {
		this.id = id;
		this.username = username;
		this.password = password;
	}


	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}


	@Override
	public String toString() {
		return "UserInfo [id=" + id + ", username=" + username + ", password=" + password + "]";
	}

}

3、服务端

package com.ccu;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;

public class ChatServer {
	/* 添加ServerSocket属性 */
	private ServerSocket server;
	/* 定义Map属性,用于存储用户和输出流对象的映射关系 */
	private Map<String, PrintWriter> pws;
	/* 定义一个线性表集合,存储所有的在线姓名 */
	private LinkedList<String> onlinenames;

	/* 构造器 */
	public ChatServer() {
		try {
			// 初始化属性
			/*
			 * ServerSocket(int port) port:当前程序的端口号
			 */
			server = new ServerSocket(8088);
			pws = new HashMap<String, PrintWriter>();
			onlinenames = new LinkedList<String>();

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// 保持用户名和输出流对象
	public void savePW(String username, PrintWriter pw) {
		if (username == null || username.length() == 0) {
			return;
		}
		pws.put(username, pw);
	}

	// 溢出用户名和输出流对象
	public void removePW(String username) {
		if (username == null || username.length() == 0) {
			return;
		}
		pws.remove(username);
	}

	/**
	 * 用于服务器启动时运行的主要逻辑
	 */
	public void start() {
		try {
			/*
			 * accept():是一个阻塞方法,用于响应客户端的请求,如果响应成功,会返回与之请求的客户端的socket对象。
			 * 此对象用于标记客户端,其提供了一套IO流用于数据的传输
			 */
			while (true) {
				System.out.println("----------等待客户端连接-----------");
				Socket socket = server.accept();
				System.out.println("------一个客户端已经连接成功-------");

				// 将刚连接上的客户端socket封装到一个线程中,是之与其他线程进并发.:注意:多个客户端就可以同时工作。
				Runnable r = new GetClientInfoHandler(socket);
				Thread t = new Thread(r);
				t.start();
			}

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

	public static void main(String[] args) {
		// 实例化一个服务器对象
		ChatServer s = new ChatServer();
		// 开启服务器
		s.start();
	}

	/*
	 * 定义内部类,处理单个客户端发送的数据
	 */
	class GetClientInfoHandler implements Runnable {
		private Socket socket;

		public GetClientInfoHandler(Socket socket) {
			this.socket = socket;
		}

		@Override
		public void run() {
			String username = null;
			try {
				// 处理客户端数据
				InputStream is = socket.getInputStream();
				BufferedReader br = new BufferedReader(new InputStreamReader(is, "utf-8"));

				OutputStream os = socket.getOutputStream();
				PrintWriter pw = new PrintWriter(new OutputStreamWriter(os, "utf-8"), true);
				// 获取客户端第一次发送来的数据,即用户名
				username = br.readLine();
				// 将username和pw作为映射关系存储
				savePW(username, pw);
				// 保存在线人数
				onlinenames.add(username);

				sendOnlinenames("在线人的姓名:" + onlinenames.toString());

				String line = "";
				while ((line = br.readLine()) != null) {
					if (!privateChat(username, line)) {// 私聊模块自己完成
						sendPublicMessage(username, line);
					}
				}

			} catch (Exception e) {
				// e.printStackTrace();
				// 客户端下线,将用户名和输出流这个键值对移除掉
				removePW(username);
				System.out.println(username + "下线了");
				offLine(username);
				// 移除在线人名单
				onlinenames.remove(username);
				sendOnlinenames("在线人的姓名:" + onlinenames.toString());
			}
		}

	}

	public void sendPublicMessage(String username, String message) {
		// 遍历Map,取出所有的输出流,来发送line这条信息
		Set<String> usernames = pws.keySet();
		for (String uname : usernames) {
			pws.get(uname).println(username + ":" + message);
		}
	}

	/**
	 * 私聊方法
	 * 
	 */
	public boolean privateChat(String username, String line) {
		if (!line.contains("@")) {
			return false;
		}
		int end = line.indexOf("@");
		//获取@对象
		String name = line.substring(end + 1);
		//判断@对象是否存在
		if(!pws.containsKey(name)) {
			return false;
		}
		
		//获取发言者
		//System.out.println("发言者" + username);
		//获取发言者说的内容
		String content = line.substring(0, line.indexOf("@"));
		pws.get(name).println(username + "私密我:" + content);
		pws.get(username).println(line);
		return true;
	}

	public void sendOnlinenames(String onlinenames) {
		// 遍历Map,取出所有的输出流,来发送line这条信息
		Set<String> usernames = pws.keySet();
		for (String uname : usernames) {
			pws.get(uname).println(onlinenames);
		}
	}

	public void offLine(String username) {
		// 遍历Map,取出所有的输出流,来发送line这条信息
		Set<String> usernames = pws.keySet();
		for (String uname : usernames) {
			pws.get(uname).println(username + "离线了");
		}
	}
}

4、客户端

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

public class ChatFrame extends JFrame {
	/* 定义Sockt属性 */
	private Socket socket;
	/* 添加面板属性,三个文本框属性 */
	private JPanel panel;
	private JTextArea showText;
	private JTextArea nameText;
	private JTextArea inputText;

	// 登陆用户名
	private String username;

	/* 构造器 */
	public ChatFrame(String username) {
		try {

			// 初始化属性 本机ip: localhost,127.0.0.1
			/*
			 * Socket(String ip,int port) ip:服务器端的ip port:服务器端的程序的端口号
			 */
			socket = new Socket("localhost", 8088);
			/* 调用init方法 */
			init();

			this.username = username;
			this.setTitle(username);

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/* 封装一个方法init,用于窗体属性的初始化 */
	public void init() {
		// 设置窗体的大小:宽 800,高550
		setSize(800, 550);
		panel = new JPanel();
		// 设置文本框: 第一个参数为:行数, 第二个参数为列数
		showText = new JTextArea(25, 53);
		nameText = new JTextArea(25, 15);
		inputText = new JTextArea(5, 70);

		// 窗体居中
		this.setLocationRelativeTo(null);
		// 设置窗体不可拉伸
		this.setResizable(false);
		// 关闭窗体,默认停止程序
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		// 设置窗体的布局,为边框布局
		this.setLayout(new BorderLayout());
		// 将面板设置到窗体上,放置在中间
		this.add(panel, BorderLayout.CENTER);

		// 设置面板的布局
		panel.setLayout(new FlowLayout());

		showText.setEditable(false);// 设置不可编辑
		// 创建滚动条对象
		JScrollPane scroll = new JScrollPane(showText);
		// 设置垂直滚动条
		scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
		panel.add(scroll);// 注意,将滚动条对象填入面板中

		nameText.setEditable(false);
		scroll = new JScrollPane(nameText);
		// 设置垂直滚动条
		scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
		panel.add(scroll);

		panel.add(inputText);

		// 设置窗体显示
		this.setVisible(true);
	}

	/**
	 * 用于启动客户端程序,运行主要逻辑
	 */
	public void start() {
		try {
			// 发送用户名给服务器,让服务器记录姓名
			sendMessage(username);

			// 定义一个线程,来处理服务端发送来的数据
			Runnable r = new GetServerInfoHandler();
			Thread t = new Thread(r);
			t.start();

			// 添加键盘的监听器
			KeyListener l = new KeyAdapter() {
				// 重写 键盘释放方法
				@Override
				public void keyReleased(KeyEvent e) {
					// 获取回车键,进行发送数据
					if (e.getKeyCode() == KeyEvent.VK_ENTER) {
						// 获取输入文本框里的内容
						String content = inputText.getText().trim();
						// System.out.println("文本框的内容为:" + content);
						// 发送信息
						sendMessage(content);
						// 清空文本框的内容
						inputText.setText("");
					}
				}
			};
			// 注册监听器
			inputText.addKeyListener(l);
			inputText.requestFocus();// 获取焦点

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 释放资源,关闭流操作
			try {
				// socket.close();
			} catch (Exception e2) {
				e2.printStackTrace();
			}
		}

	}

	public static void main(String[] args) {
		// 实例化一个客户端对象
		ChatFrame c = new ChatFrame("jack" + (int) (Math.random() * Integer.MAX_VALUE));
		// 启动客户端
		c.start();
	}

	/**
	 * 定义一个内部类,实现Runnable接口,定义任务体为接受服务端发送来的数据
	 */
	class GetServerInfoHandler implements Runnable {
		public void run() {
			try {
				/* 获取输入流,接受 服务端发送的数据 */
				InputStream is = socket.getInputStream();
				BufferedReader br = new BufferedReader(new InputStreamReader(is, "utf-8"));
				String line = "";
				while ((line = br.readLine()) != null) {
					// 将收到的信息显示在showText上
					if (line.contains("在线人的姓名")) { // "在线人的姓名:[,,,,,,,, ]"
						// 获取所有的姓名
						int startindex = line.indexOf("[") + 1;
						int endIndex = line.indexOf("]");
						String info = line.substring(startindex, endIndex);
						String[] names = info.split(",");
						nameText.setText(null);
						for (String name : names) {
							nameText.append(name + "\r\n");
						}
					} else {
						showText.append(line + "\r\n");
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 
	 */
	public void sendMessage(String content) {
		PrintWriter pw = null;
		try {
			OutputStream os = socket.getOutputStream();
			pw = new PrintWriter(new OutputStreamWriter(os, "utf-8"), true);
			pw.println(content);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

5、注册页面

import java.awt.Font;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPasswordField;
import javax.swing.JTextField;

public class RegisterFrame extends JFrame {
	private static JButton RegisterFrameButton;// 註冊按钮
	private static JLabel RegisterFramePanel;// 注册的版面
	private static JTextField userText;// 用户名
	private static JPasswordField pwdText;// 密码
	private static JLabel userLabel;
	private static JLabel pwdLabel;

	public RegisterFrame() {// 初始化登陆界面
		init();
	}

	public void init() {
		Font font = new Font("黑体", Font.PLAIN, 20);// 设置字体
		this.setSize(800, 550);
		// 给註冊界面添加背景图片
		ImageIcon bgim = new ImageIcon(LoginFrame.class.getResource("login.png"));// 背景图案
		bgim.setImage(
				bgim.getImage().getScaledInstance(bgim.getIconWidth(), bgim.getIconHeight(), Image.SCALE_DEFAULT));
		RegisterFramePanel = new JLabel();
		RegisterFramePanel.setIcon(bgim);

		userLabel = new JLabel("用户名");
		userLabel.setBounds(200, 100, 60, 50);
		userLabel.setFont(font);

		pwdLabel = new JLabel("密码");
		pwdLabel.setBounds(200, 200, 60, 50);
		pwdLabel.setFont(font);

		// 加入文本框
		userText = new JTextField("");
		userText.setBounds(350, 100, 250, 50);
		userText.setFont(font);

		pwdText = new JPasswordField("");// 密码输入框
		pwdText.setBounds(350, 200, 250, 50);
		pwdText.setFont(font);

		RegisterFrameButton = new JButton("注册");
		RegisterFrameButton.setBounds(300, 300, 200, 50);
		RegisterFrameButton.setFont(font);

		RegisterFramePanel.add(userText);
		RegisterFramePanel.add(pwdText);

		RegisterFramePanel.add(userLabel);
		RegisterFramePanel.add(pwdLabel);
		RegisterFramePanel.add(RegisterFrameButton);

		this.add(RegisterFramePanel);
		this.setTitle("注册");
		this.setVisible(true);
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		this.setLocationRelativeTo(null);
		this.setResizable(false);// 设置窗口不可随意拉伸
	}

	public void start() {

		ActionListener RegisterFrameButton_ls = new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				int result = 0;
				while (true) {
					// 获取注册界面的输入的用户名和密码
					String username = userText.getText();
					char[] password = pwdText.getPassword();
					String str = String.valueOf(password); // 将char数组转化为string类型

					// 验证用户名和密码
					UserInfo user = new UserInfo();
					user.setUsername(username);
					result = DbUtil.query(user);
					if (result == 1) {
						JOptionPane.showMessageDialog(null, "对不起!该用户名已被注册!请您重新输入!", "提示", JOptionPane.ERROR_MESSAGE);
						break;
					} else {
						user.setPassword(str);
						DbUtil.save(user);
						// 点击注册按钮,跳转到登录页面
						JOptionPane.showMessageDialog(null, "恭喜您注册成功!", "提示", JOptionPane.INFORMATION_MESSAGE);
						LoginFrame client = new LoginFrame();
						client.start();// 为跳转的界面
						dispose();// 销毁当前界面
						break;
					}
				}
			}
		};

		RegisterFrameButton.addActionListener(RegisterFrameButton_ls);
	}

	public static void main(String[] args) {
		RegisterFrame register = new RegisterFrame();
		register.start();
	}
}

6、登录页面

import java.awt.Font;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPasswordField;
import javax.swing.JTextField;

public class LoginFrame extends JFrame {
	private static int count = 0;
	private static JButton LoginFrameButton;// 登陆按钮
	private static JButton RegisterFrameButton;// 退出按钮
	private static JLabel LoginFramePanel;// 登录的版面
	private static JTextField userText;// 用户名
	private static JPasswordField pwdText;// 密码
	private static JLabel userLabel;
	private static JLabel pwdLabel;

	public LoginFrame() {// 初始化登陆界面
		init();
	}

	public void init() {
		Font font = new Font("黑体", Font.PLAIN, 20);// 设置字体
		this.setSize(800, 550);
		// 给登陆界面添加背景图片
		ImageIcon bgim = new ImageIcon(LoginFrame.class.getResource("login.png"));// 背景图案
		bgim.setImage(
				bgim.getImage().getScaledInstance(bgim.getIconWidth(), bgim.getIconHeight(), Image.SCALE_DEFAULT));
		LoginFramePanel = new JLabel();
		LoginFramePanel.setIcon(bgim);

		userLabel = new JLabel("用户名");
		userLabel.setBounds(200, 100, 60, 50);
		userLabel.setFont(font);

		pwdLabel = new JLabel("密码");
		pwdLabel.setBounds(200, 200, 60, 50);
		pwdLabel.setFont(font);

		// 加入文本框
		userText = new JTextField("");
		userText.setBounds(350, 100, 250, 50);
		userText.setFont(font);

		pwdText = new JPasswordField("");// 密码输入框
		pwdText.setBounds(350, 200, 250, 50);
		pwdText.setFont(font);

		LoginFrameButton = new JButton("登陆"); // 更改成LoginFrameButton
		LoginFrameButton.setBounds(250, 300, 100, 50);
		LoginFrameButton.setFont(font);

		RegisterFrameButton = new JButton("注册");
		RegisterFrameButton.setBounds(450, 300, 100, 50);
		RegisterFrameButton.setFont(font);

		LoginFramePanel.add(userText);
		LoginFramePanel.add(pwdText);

		LoginFramePanel.add(userLabel);
		LoginFramePanel.add(pwdLabel);
		LoginFramePanel.add(LoginFrameButton);
		LoginFramePanel.add(RegisterFrameButton);

		this.add(LoginFramePanel);
		this.setTitle("登录");
		this.setVisible(true);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setLocationRelativeTo(null);
		this.setResizable(false);// 设置窗口不可随意拉伸
	}

	public void start() {
		/**
		 * 处理点击事件 1.登陆按钮点击事件,判断账号密码是否正确,若正确,弹出监测信息界面 否则,无响应(暂时无响应)
		 * :后可在登陆界面添加一个logLabel提示用户是否用户密码正确 2.退出按钮,直接退出程序
		 */
		// 登陆点击事件
		ActionListener LoginFrameButton_ls = new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {

				int result = 0;

				while (true) {
					// 获取登陆界面的输入的用户名和密码
					String username = userText.getText();
					char[] password = pwdText.getPassword();
					String str = String.valueOf(password); // 将char数组转化为string类型

					//验证用户名和密码
					UserInfo user = new UserInfo();
					user.setUsername(username);
					user.setPassword(str);
					result = DbUtil.query(user);
					if (result != 1) {
						JOptionPane.showMessageDialog(null, "对不起!您的输入有误!请重新输入", "提示", JOptionPane.ERROR_MESSAGE);
						break;
					} else {
						// 设置
						// 登陆成功,页面跳转
						ChatFrame client = new ChatFrame(username);
						client.start();// 为跳转的界面
						dispose();// 销毁当前界面
						break;
					}
				}
			}
		};
		
		ActionListener RegisterFrameButton_ls = new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				// 点击注册按钮,跳转到注册页面
				RegisterFrame client = new RegisterFrame();
				client.start();// 为跳转的界面
				dispose();// 销毁当前界面
			}
		};
		
		
		LoginFrameButton.addActionListener(LoginFrameButton_ls);
		RegisterFrameButton.addActionListener(RegisterFrameButton_ls);
	}

	public static void main(String[] args) {
		LoginFrame login = new LoginFrame();
		login.start();
	}
}

7、数据库表结构

/*
 Navicat Premium Data Transfer

 Source Server         : 3308
 Source Server Type    : MySQL
 Source Server Version : 50622
 Source Host           : localhost:3308
 Source Schema         : wechat

 Target Server Type    : MySQL
 Target Server Version : 50622
 File Encoding         : 65001

 Date: 08/07/2019 18:36:51
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for admin
-- ----------------------------
DROP TABLE IF EXISTS `admin`;
CREATE TABLE `admin`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `password` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Records of admin
-- ----------------------------
INSERT INTO `admin` VALUES (1, 'mayun', 'my');
INSERT INTO `admin` VALUES (2, 'wangjianlin', 'wjl');
INSERT INTO `admin` VALUES (8, 'dongmingzhu', 'dmz');
INSERT INTO `admin` VALUES (9, 'mahuateng', 'mht');

SET FOREIGN_KEY_CHECKS = 1;

8、效果图

登录

登录

注册

注册

在这里插入图片描述

聊天页面

  • 6
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

lgm灵均

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

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

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

打赏作者

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

抵扣说明:

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

余额充值