java實(shí)現(xiàn)多人聊天工具(socket+多線程)
大一下學(xué)期的java期末課程設(shè)計(jì):java實(shí)現(xiàn)多人聊天工具,分享一下
課設(shè)要求
多人聊天工具
- 服務(wù)器要求1:能夠看到所有在線用戶(hù)(25%)
- 服務(wù)器要求2:能夠強(qiáng)制用戶(hù)下線(25%)
- 客戶(hù)端要求1:能夠看到所有在線用戶(hù)(25%)
- 客戶(hù)端要求2:能夠向某個(gè)用戶(hù)發(fā)送消息(25%)
相關(guān)知識(shí)點(diǎn)
1.服務(wù)端能夠看到所有在線用戶(hù)
服務(wù)端繼承了JFrame,實(shí)現(xiàn)可視化,通過(guò)socket實(shí)現(xiàn)服務(wù)端與客戶(hù)端的連接,服務(wù)端每接收一個(gè)連接,把傳進(jìn)來(lái)的用戶(hù)名和對(duì)應(yīng)的socket連接封裝成一個(gè)User對(duì)象,把User對(duì)象存進(jìn)一個(gè)ArrayList的用戶(hù)列表并把User對(duì)象通過(guò)取用戶(hù)名方法取得用戶(hù)名存進(jìn)一個(gè)ArrayList的用戶(hù)名列表,添加一個(gè)JPanel組件,將ArrayList中的內(nèi)容通過(guò)循環(huán)顯示JPanel中并布局在窗體的右邊,在每當(dāng)有人上線或者下線,刷新JPanel組件。
2.服務(wù)端能夠強(qiáng)制用戶(hù)下線
創(chuàng)建一個(gè)布局在窗體的下方的JPanel,在此JPanel中分別添加JLabel用于顯示提示文字,添加JTextField用于獲取服務(wù)端想要強(qiáng)制用戶(hù)下線的ID,添加JButton用于綁定強(qiáng)制用戶(hù)下線的事件監(jiān)聽(tīng),事件監(jiān)聽(tīng)中將獲取的JTextField的內(nèi)容與用戶(hù)名列表進(jìn)行逐一匹配,匹配上則創(chuàng)建JSON格式的鍵值對(duì)對(duì)象,通過(guò)用戶(hù)列表循環(huán)廣播告知其他用戶(hù),并在用戶(hù)列表和用戶(hù)名列表中分別刪除該用戶(hù)信息。
3.客戶(hù)端能夠看到所有在線用戶(hù)
客戶(hù)端繼承了JFrame,實(shí)現(xiàn)可視化,添加了一個(gè)布局在窗口右邊的JPanel,把從服務(wù)端接收到的用戶(hù)名列表中的信息放進(jìn)去。
4.客戶(hù)端要求能夠向某個(gè)用戶(hù)發(fā)送消息
客戶(hù)端私發(fā)消息通過(guò)在消息后面加入-和目標(biāo)用戶(hù)名,傳給服務(wù)端,服務(wù)端截取目標(biāo)用戶(hù)名,在用戶(hù)名列表中判斷是否存在此人,有則判斷是否是私發(fā),私發(fā)則向目標(biāo)用戶(hù)發(fā)送消息,沒(méi)有則向全部用戶(hù)發(fā)送消息。
5.運(yùn)用JDBC實(shí)現(xiàn)持久化存儲(chǔ)用戶(hù)信息
數(shù)據(jù)庫(kù)連接池運(yùn)用了阿里巴巴的durid,定義一個(gè)JDBCUtils類(lèi),提供靜態(tài)代碼塊加載配置文件,初始化連接池對(duì)象,通過(guò)Spring框架的JDBCTemplate對(duì)象進(jìn)行sql語(yǔ)句的執(zhí)行,在UserDao中提供了登錄和注冊(cè)方法,登錄方法運(yùn)用queryForObject方法進(jìn)行登錄查詢(xún),如果查到返回一個(gè)User對(duì)象,查不到則返回空,注冊(cè)方法直接插入新記錄,此處建表語(yǔ)句中把用戶(hù)名設(shè)置成了主鍵,保證了用戶(hù)名的唯一性,注冊(cè)失敗有警告彈窗提示。
這里加了一個(gè)ChatTest類(lèi)用于繞過(guò)數(shù)據(jù)庫(kù)賬號(hào)校驗(yàn),可以直接進(jìn)入客戶(hù)端進(jìn)行連接。
6.使用JSONObject對(duì)象封裝數(shù)據(jù)
在數(shù)據(jù)的傳輸中運(yùn)用了鍵值對(duì)的形式進(jìn)行傳輸,客戶(hù)端傳輸給服務(wù)端的數(shù)據(jù)包中,通過(guò)判斷private鍵的值來(lái)確認(rèn)是否私發(fā),通過(guò)username鍵告知服務(wù)端客戶(hù)端的用戶(hù)名,通過(guò)msg鍵傳輸具體消息,服務(wù)端傳輸給客戶(hù)端的數(shù)據(jù)包中,通過(guò)判斷user_list鍵的值來(lái)確認(rèn)在線用戶(hù)及人數(shù)
7.使用Maven構(gòu)建管理項(xiàng)目
項(xiàng)目中運(yùn)用到了JDBC相關(guān)內(nèi)容和JSONObject對(duì)象,導(dǎo)入了一些依賴(lài)jar包,其中倉(cāng)庫(kù)和配置文件都是用的idea默認(rèn)配置。
類(lèi)圖
項(xiàng)目框架
核心代碼
1.maven配置文件pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>MyChat</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>15</maven.compiler.source> <maven.compiler.target>15</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>net.sf.json-lib</groupId> <artifactId>json-lib</artifactId> <version>2.4</version> <classifier>jdk15</classifier> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.45</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.6</version> </dependency> </dependencies> </project>
2.服務(wù)器端Server.java
import java.awt.image.BufferedImage; import java.io.*; import java.net.*; import java.util.*; import java.awt.*; import javax.imageio.ImageIO; import javax.swing.*; import javax.swing.border.TitledBorder; import net.sf.json.JSONObject; //繼承JFrame實(shí)現(xiàn)可視化 public class Server extends JFrame{ //用戶(hù)列表,用于存放連接上的用戶(hù)信息 ArrayList<User> user_list = new ArrayList<>(); //用戶(hù)名列表,用于顯示已連接上的用戶(hù) ArrayList<String> username_list = new ArrayList<>(); //消息顯示區(qū)域 JTextArea show_area = new JTextArea(); //用戶(hù)名顯示區(qū)域 JTextArea show_user = new JTextArea(10, 10); //socket的數(shù)據(jù)輸出流 DataOutputStream outputStream = null; //socket的數(shù)據(jù)輸入流 DataInputStream inputStream = null; //從主函數(shù)里面開(kāi)啟服務(wù)端 public static void main(String[] args) { new Server(); } //構(gòu)造函數(shù) public Server() { //設(shè)置流式布局 setLayout(new BorderLayout()); //VERTICAL_SCROLLBAR_AS_NEEDED設(shè)置垂直滾動(dòng)條需要時(shí)出現(xiàn) //HORIZONTAL_SCROLLBAR_NEVER設(shè)置水平滾動(dòng)條不出現(xiàn) //創(chuàng)建信息顯示區(qū)的畫(huà)布并添加到show_area JScrollPane panel = new JScrollPane(show_area,ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); //設(shè)置信息顯示區(qū)標(biāo)題 panel.setBorder(new TitledBorder("信息顯示區(qū)")); //布局到中央 add(panel,BorderLayout.CENTER); //設(shè)置信息顯示區(qū)為不可編輯 show_area.setEditable(false); //創(chuàng)建用于顯示用戶(hù)的畫(huà)布 final JPanel panel_east = new JPanel(); //添加流式布局 panel_east.setLayout(new BorderLayout()); //設(shè)置標(biāo)題 panel_east.setBorder(new TitledBorder("在線用戶(hù)")); //在用戶(hù)顯示區(qū)添加show_uesr panel_east.add(new JScrollPane(show_user), BorderLayout.CENTER); //設(shè)置用戶(hù)顯示區(qū)域?yàn)椴豢删庉? show_user.setEditable(false); //將顯示用戶(hù)的畫(huà)布添加到整體布局的右側(cè) add(panel_east, BorderLayout.EAST); //創(chuàng)建關(guān)于踢下線用戶(hù)的畫(huà)布 final JPanel panel_south = new JPanel(); //創(chuàng)建標(biāo)簽 JLabel label = new JLabel("輸入要踢下線用戶(hù)的ID"); //創(chuàng)建輸入框 JTextField out_area = new JTextField(40); //創(chuàng)建踢下線按鈕 JButton out_btn = new JButton("踢下線"); //依次添加進(jìn)畫(huà)布 panel_south.add(label); panel_south.add(out_area); panel_south.add(out_btn); //將踢下線用戶(hù)的畫(huà)布添加到整體布局的下側(cè) add(panel_south,BorderLayout.SOUTH); //設(shè)置踢下線按鈕的監(jiān)聽(tīng) out_btn.addActionListener(e -> { try { //用于存儲(chǔ)踢下線用戶(hù)的名字 String out_username; //從輸入框中獲取踢下線用戶(hù)名 out_username = out_area.getText().trim(); //用于判斷蓋用戶(hù)是否被踢下線 boolean is_out=false; //遍歷用戶(hù)列表依次判斷 for (int i = 0; i < user_list.size(); i++){ //比較用戶(hù)名,相同則踢下線 if(user_list.get(i).getUsername().equals(out_username)){ //獲取被踢下線用戶(hù)對(duì)象 User out_user = user_list.get(i); //使用json封裝將要傳遞的數(shù)據(jù) JSONObject data = new JSONObject(); //封裝全體用戶(hù)名,廣播至所有用戶(hù) data.put("user_list", username_list); //廣播的信息內(nèi)容 data.put("msg", out_user.getUsername() + "被管理員踢出\n"); //服務(wù)端消息顯示區(qū)顯示相應(yīng)信息 show_area.append(out_user.getUsername() + "被你踢出\n"); //依次遍歷用戶(hù)列表 for (User value : user_list) { try { //獲取每個(gè)用戶(hù)列表的socket連接 outputStream = new DataOutputStream(value.getSocket().getOutputStream()); //傳遞信息 outputStream.writeUTF(data.toString()); } catch (IOException ex) { ex.printStackTrace(); } } //將被踢用戶(hù)移出用戶(hù)列表 user_list.remove(i); //將被踢用戶(hù)移出用戶(hù)名列表 username_list.remove(out_user.getUsername()); //刷新在線人數(shù) show_user.setText("人數(shù)有 " + username_list.size() + " 人\n"); //刷新在線用戶(hù) for (String s : username_list) { show_user.append(s + "\n"); } //判斷踢出成功 is_out=true; break; } } //根據(jù)是否踢出成功彈出相應(yīng)提示 if(is_out){ JOptionPane.showMessageDialog(null,"踢下線成功","提示", JOptionPane.WARNING_MESSAGE); } if(!is_out){ JOptionPane.showMessageDialog(null,"不存在用戶(hù)","提示", JOptionPane.WARNING_MESSAGE); } //重置輸入框 out_area.setText(""); } catch(Exception ex) { ex.printStackTrace(); } }); //設(shè)置該窗口名 setTitle("服務(wù)器 "); //引入圖片 BufferedImage img; try { //根據(jù)圖片名引入圖片 img = ImageIO.read(Server.class.getResource("/a.jpg")); //設(shè)置其為該窗體logo setIconImage(img); } catch (IOException exception) { exception.printStackTrace(); } //設(shè)置窗體大小 setSize(700, 700); //設(shè)置窗體位置可移動(dòng) setLocationRelativeTo(null); //設(shè)置窗體關(guān)閉方式 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //設(shè)置窗體可見(jiàn) setVisible(true); //socket連接相關(guān)代碼 try { //開(kāi)啟socket服務(wù)器,綁定端口11111 ServerSocket serverSocket = new ServerSocket(11111); //信息顯示區(qū)打印服務(wù)器啟動(dòng)時(shí)間 show_area.append("服務(wù)器啟動(dòng)時(shí)間 " + new Date() + "\n"); //持續(xù)接收連接 while (true) { //接收連接 Socket socket = serverSocket.accept(); //創(chuàng)建用戶(hù)對(duì)象 User user = new User(); //判斷是否連接上 if (socket != null) { //獲取輸入流 inputStream = new DataInputStream(socket.getInputStream()); //讀取輸入流 String json = inputStream.readUTF(); //創(chuàng)建信息對(duì)象 JSONObject data = JSONObject.fromObject(json); //信息顯示區(qū)打印用戶(hù)上線 show_area.append("用戶(hù) " + data.getString("username") + " 在" + new Date() + "登陸系統(tǒng)"+"\n"); //創(chuàng)建新用戶(hù) user = new User(); //存儲(chǔ)socket對(duì)象 user.setSocket(socket); //獲取輸入流用戶(hù)名 user.setUsername(data.getString("username")); //添加進(jìn)用戶(hù)列表 user_list.add(user); //添加進(jìn)用戶(hù)名列表 username_list.add(data.getString("username")); //刷新在線人數(shù) show_user.setText("人數(shù)有 " + username_list.size() + " 人\n"); //刷新在線用戶(hù) for (String s : username_list) { show_user.append(s + "\n"); } } //封裝信息對(duì)象 JSONObject online = new JSONObject(); //設(shè)置接收信息對(duì)象 online.put("user_list", username_list); //設(shè)置信息內(nèi)容 online.put("msg", user.getUsername() + "上線了"); //依次遍歷,將信息廣播給所有在線用戶(hù) for (User value : user_list) { //獲取輸出流 outputStream = new DataOutputStream(value.getSocket().getOutputStream()); //給所有用戶(hù)輸出上線信息 outputStream.writeUTF(online.toString()); } //開(kāi)啟新線程,持續(xù)接收該socket信息 new Thread(new ServerThread(socket)).start(); } } catch (IOException ex) { ex.printStackTrace(); } } //線程代碼 class ServerThread implements Runnable { //存放全局變量socket private final Socket socket; //構(gòu)造函數(shù),初始化socket public ServerThread(Socket socket) { this.socket = socket; } @Override public void run() { try { //獲取輸入流 DataInputStream inputStream = new DataInputStream(socket.getInputStream()); //持續(xù)接收信息 while (true) { //獲取傳遞進(jìn)來(lái)的信息 String json = inputStream.readUTF(); //封裝成json格式 JSONObject data = JSONObject.fromObject(json); //通過(guò)json里面的private判斷是否私發(fā) boolean is_private = false; //私發(fā)處理 for (int i = 0; i < user_list.size(); i++) { //找到私發(fā)對(duì)象 if (user_list.get(i).getUsername().equals(data.getString("private"))) { //構(gòu)建私發(fā)信息內(nèi)容 String msg = data.getString("time") +"\n" + data.getString("username") + " 給你發(fā)了一條私密消息,其它用戶(hù)看不到" + "\n" + data.getString("msg"); //用該方法指定對(duì)象發(fā)送信息 send_msg(i, msg); //將發(fā)送成功反饋給原用戶(hù) for (int j = 0; j < user_list.size(); j++) { //找到發(fā)信息用戶(hù) if(user_list.get(j).getUsername().equals(data.getString("username"))){ //構(gòu)建反饋信息內(nèi)容 String msg2 = data.getString("time")+"\n你成功向"+user_list.get(i).getUsername() +"發(fā)送了一條私密消息\n" +data.getString("msg"); //用該方法指定對(duì)象發(fā)送信息 send_msg(j,msg2); } } //將該操作打印到服務(wù)器監(jiān)視窗 show_area.append(data.getString("username") +data.getString("time")+ "私發(fā)給" + data.getString("private") + ":\n" + data.getString("msg") + "\n"); //判斷是私發(fā) is_private = true; break; } } //非私發(fā)的情況 if (!is_private) { //構(gòu)建信息內(nèi)容 String msg = data.getString("username") + " " + data.getString("time") + ":\n" + data.getString("msg"); //添加到服務(wù)器顯示 show_area.append(msg + "\n"); //依次發(fā)給所有在線用戶(hù) for (int i = 0; i < user_list.size(); ) { send_msg(i, msg); i++; } } } } catch (IOException e) { e.printStackTrace(); } } //發(fā)送信息給指定用戶(hù)的方法 public void send_msg(int i, String msg) { //構(gòu)建對(duì)象 JSONObject data = new JSONObject(); //封裝信息 data.put("user_list", username_list); data.put("msg", msg); //獲取目標(biāo)對(duì)象 User user = user_list.get(i); try { //獲取輸出流 outputStream = new DataOutputStream(user.getSocket().getOutputStream()); //寫(xiě)信息 outputStream.writeUTF(data.toString()); } catch (IOException e) { //如果沒(méi)有找到,則說(shuō)明該用戶(hù)已經(jīng)下線 User out_user = user_list.get(i); //重復(fù)刪除操作 user_list.remove(i); username_list.remove(out_user.getUsername()); //重新構(gòu)建信息 JSONObject out = new JSONObject(); out.put("user_list", username_list); out.put("msg", out_user.getUsername() + "下線了\n"); //將其下線通知廣播給所有用戶(hù) for (User value : user_list) { try { outputStream = new DataOutputStream(value.getSocket().getOutputStream()); outputStream.writeUTF(out.toString()); } catch (IOException ex) { ex.printStackTrace(); } } } } } }
代碼太多了,懶得注釋了,大家應(yīng)該看得懂
3.客戶(hù)端登錄界面Client.java
import javax.imageio.ImageIO; import javax.swing.*; import java.awt.image.BufferedImage; import java.io.IOException; public class Client extends JFrame{ public static void main(String[] args) { new Client(); } public Client(){ setTitle("登陸界面"); BufferedImage img; try { img = ImageIO.read(Server.class.getResource("/a.jpg")); setIconImage(img); } catch (IOException exception) { exception.printStackTrace(); } setLayout(null); setSize(500,500); setLocationRelativeTo(null); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setLayout(null); setResizable(false); JLabel username_label = new JLabel("用戶(hù)名"); username_label.setBounds(60,100,100,50); add(username_label); JLabel password_label = new JLabel("密碼"); password_label.setBounds(60,200,100,50); add(password_label); JTextField username_field = new JTextField(); username_field.setBounds(110,100,300,50); add(username_field); JPasswordField password_field = new JPasswordField(); password_field.setBounds(110,200,300,50); add(password_field); JButton login = new JButton("登陸"); login.setBounds(130,300,100,50); add(login); JButton register = new JButton("注冊(cè)"); register.setBounds(280,300,100,50); add(register); setVisible(true); login.addActionListener(e -> { String username = username_field.getText(); String password = String.valueOf(password_field.getPassword()); if(username.length()!=0 && password.length()!=0){ User user = new User(); user.setUsername(username); user.setPassword(password); UserDao dao = new UserDao(); User u = dao.login(user); if(u!=null){ setVisible(false); new Chat(username); }else{ JOptionPane.showMessageDialog(null,"登錄失敗,賬號(hào)或密碼錯(cuò)誤","提示", JOptionPane.WARNING_MESSAGE); } }else { JOptionPane.showMessageDialog(null,"登錄失敗,賬號(hào)或密碼不能為空","提示", JOptionPane.WARNING_MESSAGE); } }); register.addActionListener(e -> { setVisible(false); new Register(); }); } }
4.客戶(hù)端注冊(cè)界面Register.java
import javax.imageio.ImageIO; import javax.swing.*; import java.awt.image.BufferedImage; import java.io.IOException; public class Register extends JFrame { public Register(){ setTitle("注冊(cè)界面"); BufferedImage img; try { img = ImageIO.read(Server.class.getResource("/a.jpg")); this.setIconImage(img); } catch (IOException exception) { exception.printStackTrace(); } setLayout(null); setSize(500,500); setLocationRelativeTo(null); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setLayout(null); setResizable(false); JLabel username_label = new JLabel("用戶(hù)名"); username_label.setBounds(60,50,100,50); add(username_label); JLabel password_label = new JLabel("密碼"); password_label.setBounds(60,150,100,50); add(password_label); JLabel password_label2 = new JLabel("請(qǐng)?jiān)俅屋斎朊艽a"); password_label2.setBounds(20,250,100,50); add(password_label2); JTextField username_field = new JTextField(); username_field.setBounds(110,50,300,50); add(username_field); JPasswordField password_field = new JPasswordField(); password_field.setBounds(110,150,300,50); add(password_field); JPasswordField password_field2 = new JPasswordField(); password_field2.setBounds(110,250,300,50); add(password_field2); JButton register_success = new JButton("注冊(cè)"); register_success.setBounds(130,350,100,50); add(register_success); JButton back = new JButton("返回"); back.setBounds(280,350,100,50); add(back); setVisible(true); register_success.addActionListener(e -> { String username = username_field.getText(); String password = String.valueOf(password_field.getPassword()); String password2 = String.valueOf(password_field2.getPassword()); System.out.println(password); System.out.println(password2); if(username.length()==0 || password.length()==0){ JOptionPane.showMessageDialog(null,"注冊(cè)失敗,賬號(hào)或密碼不能為空","提示", JOptionPane.WARNING_MESSAGE); }else if (!password.equals(password2)) { JOptionPane.showMessageDialog(null,"注冊(cè)失敗,前后密碼不匹配","提示", JOptionPane.WARNING_MESSAGE); }else{ System.out.println(); System.out.println(password); User user = new User(); user.setUsername(username); user.setPassword(password); UserDao dao = new UserDao(); int flag = dao.register(user); if(flag!=0){ JOptionPane.showMessageDialog(null,"注冊(cè)成功,歡迎您登錄","提示", JOptionPane.WARNING_MESSAGE); }else{ //建表語(yǔ)句中設(shè)置了user為主鍵,重復(fù)則建表失敗 JOptionPane.showMessageDialog(null,"注冊(cè)失敗,賬號(hào)已經(jīng)存在","提示", JOptionPane.WARNING_MESSAGE); } } }); back.addActionListener(e ->{ setVisible(false); new Client(); }); } }
5.客戶(hù)端聊天界面Chat.java
import java.awt.image.BufferedImage; import java.io.*; import java.net.*; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.awt.*; import javax.imageio.ImageIO; import javax.swing.*; import javax.swing.border.TitledBorder; import net.sf.json.JSONArray; import net.sf.json.JSONObject; public class Chat extends JFrame{ JTextArea show_area = new JTextArea(); JTextArea show_user = new JTextArea(10, 10); DataOutputStream outputStream; DataInputStream inputStream; String username; ArrayList<String> username_list = new ArrayList<>(); boolean is_stop = false; public Chat(final String username) { this.username = username; final JPanel panel_south = new JPanel(); panel_south.setLayout(new BorderLayout()); panel_south.setBorder(new TitledBorder("寫(xiě)消息區(qū),若私聊,在內(nèi)容后添加(-用戶(hù)名)")); JTextField send_area = new JTextField(40); panel_south.add(send_area, BorderLayout.CENTER); JButton send_btn = new JButton("發(fā)送"); panel_south.add(send_btn,BorderLayout.EAST); add(panel_south, BorderLayout.SOUTH); send_btn.addActionListener(e -> { try { if (is_stop) { show_area.append("你已被踢出,不能發(fā)送消息\n"); JOptionPane.showMessageDialog(null,"你已被踢出,不能發(fā)送消息,進(jìn)程已經(jīng)關(guān)閉","提示", JOptionPane.WARNING_MESSAGE); System.exit(0); } else { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String time = sdf.format(new Date()); String msg = send_area.getText().trim(); if (!msg.equals("")) { String[] msg1 = msg.split("-"); JSONObject data = new JSONObject(); data.put("username", username); data.put("msg", msg1[0]); data.put("time", time); try { data.put("private", msg1[1]); } catch (ArrayIndexOutOfBoundsException e1) { data.put("private", ""); } outputStream.writeUTF(data.toString()); } } send_area.setText(""); } catch (Exception ex) { ex.printStackTrace(); } }); JScrollPane panel = new JScrollPane(show_area,ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); panel.setBorder(new TitledBorder("信息顯示區(qū)")); add(panel,BorderLayout.CENTER); show_area.setEditable(false); final JPanel panel_east = new JPanel(); panel_east.setLayout(new BorderLayout()); panel_east.setBorder(new TitledBorder("在線用戶(hù)")); panel_east.add(new JScrollPane(show_user), BorderLayout.CENTER); show_user.setEditable(false); add(panel_east, BorderLayout.EAST); setTitle("用戶(hù) " + username); BufferedImage img; try { img = ImageIO.read(Server.class.getResource("/a.jpg")); this.setIconImage(img); } catch (IOException exception) { exception.printStackTrace(); } setSize(500, 500); setLocationRelativeTo(null); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); JSONObject data = new JSONObject(); data.put("username", username); data.put("msg", null); try { Socket socket = new Socket("127.0.0.1", 11111); inputStream = new DataInputStream(socket.getInputStream()); outputStream = new DataOutputStream(socket.getOutputStream()); outputStream.writeUTF(data.toString()); new Thread(new Read()).start(); } catch (IOException e) { show_area.append("服務(wù)器無(wú)響應(yīng)"); JOptionPane.showMessageDialog(null,"服務(wù)器無(wú)響應(yīng)","提示", JOptionPane.WARNING_MESSAGE); } } public class Read implements Runnable { @Override public void run() { try { while (true) { String json = inputStream.readUTF(); JSONObject data = JSONObject.fromObject(json); String msg = data.getString("msg"); if (msg.contains("踢出") && msg.contains(username)) { is_stop = true; show_area.append(username + ",你已經(jīng)被踢出群聊\n"); JOptionPane.showMessageDialog(null,"你已經(jīng)被踢出群聊","提示", JOptionPane.WARNING_MESSAGE); System.exit(0); } else { show_area.append(msg + "\n"); show_area.selectAll(); username_list.clear(); JSONArray jsonArray = data.getJSONArray("user_list"); for (Object o : jsonArray) { username_list.add(o.toString()); } show_user.setText("人數(shù)有 " + jsonArray.size() + " 人\n"); for (String s : username_list) { show_user.append(s + "\n"); } } } } catch (Exception e) { e.printStackTrace(); } } } }
6.用戶(hù)實(shí)體User.java
import java.net.Socket; public class User { private String username; private String password; private Socket socket; 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; } public Socket getSocket() { return socket; } public void setSocket(Socket socket) { this.socket = socket; } }
7.JDBC工具類(lèi)
import com.alibaba.druid.pool.DruidDataSourceFactory; import javax.sql.DataSource; import java.io.InputStream; import java.util.Properties; public class JDBCUtils { private static DataSource ds; static { try { Properties pro = new Properties(); InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"); pro.load(is); ds = DruidDataSourceFactory.createDataSource(pro); } catch (Exception exception) { exception.printStackTrace(); } } public static DataSource getDataSource(){ return ds; } }
8.UserDao.java連接數(shù)據(jù)庫(kù)
import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; public class UserDao { private final JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource()); public User login(User login_user) { try { //編寫(xiě)sql String sql = "select * from user where username = ? and password = ?"; User user = template.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), login_user.getUsername(), login_user.getPassword()); return user; } catch (DataAccessException e) { e.printStackTrace(); return null; } } public int register(User register_user) { try { String sql = "insert into user values (null ,?,?)"; int count = template.update(sql,register_user.getUsername(),register_user.getPassword()); return count; } catch (DataAccessException e) { e.printStackTrace(); return 0; } } }
運(yùn)行結(jié)果
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- java socket實(shí)現(xiàn)聊天室 java實(shí)現(xiàn)多人聊天功能
- 基于java編寫(xiě)局域網(wǎng)多人聊天室
- java編程實(shí)現(xiàn)多人聊天室功能
- Java基于Tcp/ip連接的多人交互聊天室
- java使用MulticastSocket實(shí)現(xiàn)基于廣播的多人聊天室
- Java SE實(shí)現(xiàn)多人聊天室功能
- Java NIO Selector用法詳解【含多人聊天室實(shí)例】
- Java多線程實(shí)現(xiàn)多人聊天室功能
- Java基于中介者模式實(shí)現(xiàn)多人聊天室功能示例
- java實(shí)現(xiàn)多人聊天系統(tǒng)
相關(guān)文章
詳解JavaWeb如何實(shí)現(xiàn)文件上傳和下載功能
這篇文章主要介紹了如何利用JavaWeb實(shí)現(xiàn)文件的上傳和下載功能,文中的示例代碼講解詳細(xì),對(duì)我們的學(xué)習(xí)或工作有一定的幫助,感興趣的小伙伴可以學(xué)習(xí)一下2021-12-12Spring、SpringMvc和SpringBoot的區(qū)別及說(shuō)明
Spring框架提供了全面的Java開(kāi)發(fā)解決方案,核心包括IOC和AOP,SpringMvc作為其中的WEB層開(kāi)發(fā)框架,通過(guò)復(fù)雜的XML配置管理前端視圖和后臺(tái)邏輯,SpringBoot則簡(jiǎn)化了配置,專(zhuān)注于微服務(wù)接口開(kāi)發(fā),支持嵌入式服務(wù)器,提高了開(kāi)發(fā)效率2024-10-10mybatis 獲取無(wú)數(shù)據(jù)的字段不顯示的問(wèn)題
這篇文章主要介紹了mybatis 獲取無(wú)數(shù)據(jù)的字段不顯示的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07Java實(shí)現(xiàn)音頻添加自定義時(shí)長(zhǎng)靜音的示例代碼
這篇文章主要介紹了一個(gè)Java工具類(lèi),可以實(shí)現(xiàn)給一個(gè)wav音頻添加自定義時(shí)長(zhǎng)靜音。文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編學(xué)習(xí)一下2022-01-01spring boot 統(tǒng)一JSON格式的接口返回結(jié)果的實(shí)現(xiàn)
這篇文章主要介紹了spring boot 統(tǒng)一JSON格式的接口返回結(jié)果的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10java中同類(lèi)對(duì)象之間的compareTo()和compare()方法對(duì)比分析
這篇文章主要介紹了java中同類(lèi)對(duì)象之間的compareTo()和compare()方法對(duì)比分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09