日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java实现qq聊天(超详细)

發布時間:2023/12/10 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java实现qq聊天(超详细) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

java語言實踐課內容:聊天室小程序或QQ

功能要求:
聊天室:使用圖形用戶界面,能實現一個聊天室中多人聊天,可以兩人私聊。
QQ:實現類似QQ登錄、聊天等功能。
注意:有一定等級。完全照搬別人的代碼,不超過70分。
提示:使用socket通信
前面是逐步講解,要是想看最終代碼,請直接找到該文章的最下面
//

準備工作
建立包,類,文件
插入圖片要創建一個文件夾,文件夾里保存的就是所需要的圖片啦,比如我創建的文件夾為image;
兩個設備上進行通信,要用到socket通信協議,即客戶端的內容先傳到服務器,在服務器上處理,傳回客戶端


image素材文件里存放的圖片
鏈接:https://pan.baidu.com/s/1zns86NC6Qm80xKZHMIRSbA
提取碼:3f6w

//

1.首先我們先建一個qq登陸界面

成品圖如下:

詳細代碼及注釋如下

// 客戶端的登陸界面 package com.qq.client.view; //抽象窗口工具包 import javax.swing.*; import java.awt.*; import java.awt.event.*;public class QqClientlLogin extends JFrame{ //JFrame的子類JLabel jup; //定義上部需要的組件 //標簽//定義中部需要的組件JPanel jmid ;JLabel jmid_num1,jmid_key1;JTextField jmid_num2; //文本框JPasswordField jmid_key2; //密碼框JCheckBox jmid_rember,jmid_automatic; //復選框JPanel jdown; //JPanel 面板JButton jdown_1,jdown_2; //定義下部需要的組件public QqClientlLogin() //構造方法{//處理上部 jup=new JLabel(new ImageIcon("image/up3.png"));//處理中部jmid=new JPanel(new GridLayout(3,3));//網格布局 3行3列Font font = new Font("宋體", Font.PLAIN, 25); //創建1個字體實例jmid_num1=new JLabel("QQ號碼:",JLabel.CENTER); jmid_key1=new JLabel("QQ密碼:",JLabel.CENTER);jmid_num1.setFont(font); jmid_key1.setFont(font); //字體大小jmid_num2= new JTextField() ; jmid_key2=new JPasswordField();jmid_rember=new JCheckBox("自動登錄");jmid_automatic=new JCheckBox("記住密碼");jmid_rember.setFont(font); jmid_automatic.setFont(font); //字體大小jmid_rember.setForeground(Color.blue); //設置字體顏色jmid_automatic.setForeground(Color.blue);jmid.add(jmid_num1);jmid.add(jmid_num2);jmid.add(jmid_key1);jmid.add(jmid_key2);jmid.add(jmid_rember);jmid.add(jmid_automatic);//處理下部jdown=new JPanel(new FlowLayout()); //流式布局jdown_1=new JButton(new ImageIcon("image/denglu.png"));jdown_2=new JButton(new ImageIcon("image/tuichu.png"));jdown.add(jdown_1);jdown.add(jdown_2);setLocation(300,300); //窗口的位置add(jup,"North"); //放在最北部 add(jmid,"Center"); //放在中間add(jdown,"South"); //放在南部setSize(700,540); //設置大小 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //結束窗口所在的應用程序 setVisible(true); //可見,默認是不可見}public static void main(String[] args){QqClientlLogin qqClientlLogin=new QqClientlLogin();} }

//

2.好友列表界面

成品圖如下:

要建立兩個卡片的轉換,即點擊卡片一的"黑名單"轉到第二個卡片界面,點擊第二個卡片的"我的好友",轉到第一個界面上
此時,就需要創建監聽器的類,用到ActionListener接口
除此之外,我還建立了鼠標監聽MouseListener接口,當鼠標停留在好友是,好友編號變紅,離開時變回黑色,雙擊好友時,可得到該好友的編號(并進入與該好友的聊天界面)
詳細代碼及注釋如下

//好友列表(也包括黑名單) package com.qq.client.view;import javax.swing.*; import java.awt.*; import java.awt.event.*;public class QqFriendList extends JFrame implements ActionListener,MouseListener { //負責創建監聽器的類, 點擊按鈕觸發ActionListener事件; 鼠標監聽MouseListener // 第一張卡片(我的好友);JPanel jup1,jmid1,jdown1; //jup1即為總JPanel;JButton jup1_1,jdown1_1;JScrollPane jmid1_1; //滑動窗口;//第二張卡片(黑名單);JPanel jup2,jup2_button,jmid2;JButton jup2_1,jup2_2;JScrollPane jmid2_1; //滑動窗口;//把整個JFrame設置成CardLayout布局CardLayout cl;public QqFriendList (){ Font font = new Font("宋體", Font.PLAIN, 35); //創建字體實例 //處理第一張卡片(我的好友);jup1=new JPanel(new BorderLayout()); //第一張卡片的總JPane,BorderLayout()布局;jup1_1=new JButton("我的好友");jup1_1.setFont(font); //字體//假設有50個好友,具體是服務器返回的結果(好友信息存放在服務器)jmid1=new JPanel(new GridLayout(50,1,4,4)); //(4,4)行間距和列間距//給jmid1初始化50個好友JLabel []jlist1=new JLabel [50]; //數組;for ( int i=0; i<jlist1.length ; i++ ){jlist1[i]=new JLabel(i+1+" ",new ImageIcon("image/touxiang.png"),JLabel.LEFT);jlist1[i].addMouseListener(this);jmid1.add(jlist1[i]); }jmid1_1=new JScrollPane(jmid1);jdown1_1=new JButton("黑名單");jdown1_1.addActionListener(this); //給jdown1_1按鈕增加一個監聽器,這個監聽器對象就是“QqFriendList ”類型的,//當用戶點擊了jdown1_1按鈕時,會程序自動前往QqFriendList類的“actionPerformed”方法中,處理產生的事件。jdown1_1.setFont(font); //字體jdown1=new JPanel(new GridLayout(1,1));//黑名單按鈕jdown1.add(jdown1_1); //加入按鈕;jup1.add(jup1_1,"North");jup1.add(jmid1_1,"Center");jup1.add(jdown1,"South");//處理第二張卡片(黑名單) jup2=new JPanel(new BorderLayout()); //第二張卡片的總JPane,BorderLayout()布局;jup2_1=new JButton("我的好友");jup2_1.addActionListener(this); //監聽jup2_2=new JButton("黑名單");jup2_1.setFont(font); //字體jup2_2.setFont(font);jup2_button=new JPanel(new GridLayout(2,1));//黑名單按鈕jup2_button.add(jup2_1);jup2_button.add(jup2_2);//假設有20個黑名單,具體是服務器返回的結果(好友信息存放在服務器)jmid2=new JPanel(new GridLayout(20,1,4,4)); //(4,4)行間距和列間距//給jmid2初始化20個好友JLabel []jlist2=new JLabel [20]; //數組;for ( int i=0; i<jlist2.length ; i++ ){jlist2[i]=new JLabel(i+1+" ",new ImageIcon("image/heitou.png"),JLabel.LEFT);jmid2.add(jlist2[i]);}jmid2_1=new JScrollPane(jmid2);jup2.add(jup2_button,"North");jup2.add(jmid2_1); cl=new CardLayout();setLayout(cl);add(jup1,"1"); //第一張卡片jup1;add(jup2,"2"); //第二張卡片jup2;setLocation(300,300); //窗口的位置setSize(440,800);setVisible(true); }public static void main(String[] args) {// TODO Auto-generated method stubQqFriendList qqFriendList=new QqFriendList();}public void actionPerformed(ActionEvent arg0){ //如果點擊了黑名單按鈕,就顯示第二張卡片if(arg0.getSource()==jdown1_1){cl.show(this.getContentPane(), "2"); //用getContentPane()方法獲得JFrame的內容面板}elseif(arg0.getSource()==jup2_1){cl.show(this.getContentPane(), "1");}}public void mouseEntered(MouseEvent arg0) { //進入組件觸發鼠標事件// TODO Auto-generated method stubJLabel jl=(JLabel)arg0.getSource(); //變成JLable形式//getSource()獲取鼠標事件的事件源;jl.setForeground(Color.red); //設置前景色}public void mouseExited(MouseEvent arg0) { //鼠標離開組件觸發的鼠標事件// TODO Auto-generated method stubJLabel jl=(JLabel)arg0.getSource(); jl.setForeground(Color.black);}public void mouseClicked(MouseEvent arg0) { //點擊鼠標觸發鼠的標事件// TODO Auto-generated method stub//響應用戶雙擊的事件,并得到好友的編號.if(arg0.getClickCount()==2) //getClickCount() 獲取鼠標被單機的次數{//得到該好友的編號 //getText() 的意思是:返回數據窗口控件中 懸浮在當前行列之上的String friendNum=((JLabel)arg0.getSource()).getText();//System.out.println("你希望和 "+friendNum+" 聊天");}}public void mousePressed(MouseEvent arg0) { //按下按鼠標鍵觸發的鼠標事件// TODO Auto-generated method stub}public void mouseReleased(MouseEvent arg0) { //釋放鼠標鍵觸發的鼠標事件// TODO Auto-generated method stub}}

3.聊天界面,用服務器判斷登錄qq,對象流

這部分的代碼成果圖:

注:正常是要有數據庫來存qq賬號密碼信息的,秉著由簡至難的原則,此處先不設計數據庫,直接用服務器判斷
有了上訴兩個界面的設置,相信設置聊天界面應該很好模擬退出
聊天界面初步成果:

//與好友聊天的界面 package com.qq.client.view; import javax.swing.*; import java.awt.*; import java.awt.event.*; public class QqChat extends JFrame {Font font = new Font("宋體", Font.PLAIN, 20); JTextArea jta; //文本域 存聊天內容JTextField jtf; //文本框JButton jb;JPanel jp;String ownerId;String friendId;public QqChat(String owner,String friend){jta=new JTextArea();jtf=new JTextField(25); //25個字符那么寬jb=new JButton("發送");jb.setFont(font);jp=new JPanel();jp.add(jtf);jp.add(jb); add(jta,"Center");add(jp,"South");setTitle(owner+"正在和 "+friend+" 聊天"); //設置標題setIconImage((new ImageIcon("image/qq.png").getImage())); //獲取圖像setLocation(800,400); //窗口的位置setSize(600, 500);setVisible(true);}public static void main(String[] args) {// TODO Auto-generated method stubQqChat qqChat=new QqChat("1"); //傳入好友1,你正在和1聊天;}

思考一下,如果是要與其余好友聊天應該如何表示呢?
在 QqFriendList中,我們雙擊得到好友的編號,只需把編號傳到QqChat中即可

現在來實現登錄操作:當用戶點擊登錄后,把qq號碼和密碼發送給QqServer(服務器)去驗證,如果該用戶合法,返回true,否則返回false;
以對象流的方式讀取客戶端發來的賬號和密碼,在網絡間傳遞對象流,
避免直接讀入由特殊符號,空格,換行等干擾

對象流是一種高級流,可以方便我們將java中的任何對象進行讀寫操作。 java.io.objectoutputstream對象輸出流,可以將對象轉換為一組字節寫出。 java.io.objectinputstream對象輸入流,可以讀取一組字節轉換為原對象, 還原為原對象的條件是讀取這個字節應該是對象輸出流將一個對象轉換的字節。一個對象要想序列化,該類必須實現java.io.Serializable 接口 Serializable 是一個標記接口,不實現此接口的類將不會使任何狀態序列化或反序列化,會拋出NotSerializableException 。 使用ObjectOutputStream對象中的方法writeObject,把對象寫入到文件中

在這里,我們還要用到socket socket是兩臺主機之間的一個連接
網絡上的兩個程序通過一個雙向的通信連接實現數據的交換,這個連接的一端稱為一個socket。
建立網絡通信連接需要一對socket,兩個socket之間形成一個管道(通道),進行信息流的傳輸(聯想IO流中文件和程序之間讀寫)。

ServerSocket與Socket入門詳解
分別在Qqclient(客戶端)和QqServe(服務端)項目里建立com.qq.common包,包里存放Message.java和User.java兩個類
User類就是獲得用戶輸入的賬號和密碼

//用戶信息類 package com.qq.common;public class User implements java.io.Serializable{private String userId;private String passwd;public String getUserId(){return userId;}public void setUserId(String userId) {this.userId = userId;}public String getPasswd(){return passwd;}public void setPasswd(String passwd){this.passwd=passwd;} }

對發送服務端的信息規定一些規則
mesType為true 表明登陸成功
mesType為false 表明登錄失敗
所以Message就是用來判斷的

package com.qq.common; public class Message implements java.io.Serializable { //序列化 private String mesType;public String getMesType(){return mesType;}public void setMesType(String mesType){this.mesType =mesType;} }

主要思想

要在第一部分qq登錄界面的代碼中加上監聽(登錄按鈕),將得到的賬戶和密碼信息逐步傳入到破服務器里面,再有服務器返回,判斷是否能登錄,如果能,打開好友列表界面,
否則,觸發提示框"用戶名或密碼錯誤".
客戶端
注意:我判斷的是如果密碼為"123456"即為正確

// 客戶端的登陸界面 package com.qq.client.view; //抽象窗口工具包 import javax.swing.*; import java.awt.*; import java.awt.event.*; import com.qq.client.model.*; import com.qq.common.*; public class QqClientlLogin extends JFrame implements ActionListener{ //JFrame的子類JLabel jup; //定義上部需要的組件 //標簽//定義中部需要的組件JPanel jmid ;JLabel jmid_num1,jmid_key1;JTextField jmid_num2; //文本框JPasswordField jmid_key2; //密碼框JCheckBox jmid_rember,jmid_automatic; //復選框JPanel jdown; //JPanel 面板JButton jdown_1,jdown_2; //定義下部需要的組件public QqClientlLogin() //構造方法{//處理上部 jup=new JLabel(new ImageIcon("image/up3.png"));//處理中部jmid=new JPanel(new GridLayout(3,3));//網格布局 3行3列Font font = new Font("宋體", Font.PLAIN, 25); //創建1個字體實例jmid_num1=new JLabel("QQ號碼:",JLabel.CENTER); jmid_key1=new JLabel("QQ密碼:",JLabel.CENTER);jmid_num1.setFont(font); jmid_key1.setFont(font); //字體大小jmid_num2= new JTextField() ; jmid_key2=new JPasswordField();jmid_rember=new JCheckBox("自動登錄");jmid_automatic=new JCheckBox("記住密碼");jmid_rember.setFont(font); jmid_automatic.setFont(font); //字體大小jmid_rember.setForeground(Color.blue); //設置字體顏色jmid_automatic.setForeground(Color.blue);jmid.add(jmid_num1);jmid.add(jmid_num2);jmid.add(jmid_key1);jmid.add(jmid_key2);jmid.add(jmid_rember);jmid.add(jmid_automatic);//處理下部jdown=new JPanel(new FlowLayout()); //流式布局jdown_1=new JButton(new ImageIcon("image/denglu.png"));//響應用戶點擊登錄jdown_1.addActionListener(this); //監控jdown_2=new JButton(new ImageIcon("image/tuichu.png"));jdown.add(jdown_1);jdown.add(jdown_2);setLocation(300,300); //窗口的位置add(jup,"North"); //放在最北部 add(jmid,"Center"); //放在中間add(jdown,"South"); //放在南部setSize(700,540); //設置大小 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //結束窗口所在的應用程序 setVisible(true); //可見,默認是不可見}public static void main(String[] args){QqClientlLogin qqClientlLogin=new QqClientlLogin();} public void actionPerformed(ActionEvent arg0){if(arg0.getSource()==jdown_1); //請求登錄{User u=new User();u. setUserId(jmid_num2.getText().trim()); //trim() 方法用于 刪除字符串的頭尾空白符u. setPasswd(new String (jmid_key2.getPassword())); //字符串;QqClientUser qqclientuser=new QqClientUser();if(qqclientuser.checkUser(u)){new QqFriendList(u.getUserId()); //好友列表this.dispose(); //關閉登陸界面}else{JOptionPane.showMessageDialog(this,"用戶名或密碼錯誤");//JOptionPane彈窗,消息提示框//showMessageDialog這個方法里有兩個參數//第一個參數-確定Frame在其中顯示的對話框//第二個參數message就是我們要在提示框里顯示的信息}}} } //好友列表(也包括黑名單) package com.qq.client.view;import javax.swing.*; import java.awt.*; import java.awt.event.*;public class QqFriendList extends JFrame implements ActionListener,MouseListener { //負責創建監聽器的類, 點擊按鈕觸發ActionListener事件; 鼠標監聽MouseListener String owner; // 第一張卡片(我的好友);JPanel jup1,jmid1,jdown1; //jup1即為總JPanel;JButton jup1_1,jdown1_1;JScrollPane jmid1_1; //滑動窗口;//第二張卡片(黑名單);JPanel jup2,jup2_button,jmid2;JButton jup2_1,jup2_2;JScrollPane jmid2_1; //滑動窗口;//把整個JFrame設置成CardLayout布局CardLayout cl;public QqFriendList (String ownerId){ Font font = new Font("宋體", Font.PLAIN, 35); //創建字體實例 owner=ownerId;//處理第一張卡片(我的好友);jup1=new JPanel(new BorderLayout()); //第一張卡片的總JPane,BorderLayout()布局;jup1_1=new JButton("我的好友");jup1_1.setFont(font); //字體//假設有50個好友,具體是服務器返回的結果(好友信息存放在服務器)jmid1=new JPanel(new GridLayout(50,1,4,4)); //(4,4)行間距和列間距//給jmid1初始化50個好友JLabel []jlist1=new JLabel [50]; //數組;for ( int i=0; i<jlist1.length ; i++ ){jlist1[i]=new JLabel(i+1+"",new ImageIcon("image/touxiang.png"),JLabel.LEFT);jlist1[i].addMouseListener(this);jmid1.add(jlist1[i]); }jmid1_1=new JScrollPane(jmid1);jdown1_1=new JButton("黑名單");jdown1_1.addActionListener(this); //給jdown1_1按鈕增加一個監聽器,這個監聽器對象就是“QqFriendList ”類型的,//當用戶點擊了jdown1_1按鈕時,會程序自動前往QqFriendList類的“actionPerformed”方法中,處理產生的事件。jdown1_1.setFont(font); //字體jdown1=new JPanel(new GridLayout(1,1));//黑名單按鈕jdown1.add(jdown1_1); //加入按鈕;jup1.add(jup1_1,"North");jup1.add(jmid1_1,"Center");jup1.add(jdown1,"South");//處理第二張卡片(黑名單) jup2=new JPanel(new BorderLayout()); //第二張卡片的總JPane,BorderLayout()布局;jup2_1=new JButton("我的好友");jup2_1.addActionListener(this); //監聽jup2_2=new JButton("黑名單");jup2_1.setFont(font); //字體jup2_2.setFont(font);jup2_button=new JPanel(new GridLayout(2,1));//黑名單按鈕jup2_button.add(jup2_1);jup2_button.add(jup2_2);//假設有20個黑名單,具體是服務器返回的結果(好友信息存放在服務器)jmid2=new JPanel(new GridLayout(20,1,4,4)); //(4,4)行間距和列間距//給jmid2初始化20個好友JLabel []jlist2=new JLabel [20]; //數組;for ( int i=0; i<jlist2.length ; i++ ){jlist2[i]=new JLabel(i+1+" ",new ImageIcon("image/heitou.png"),JLabel.LEFT);jmid2.add(jlist2[i]);}jmid2_1=new JScrollPane(jmid2);jup2.add(jup2_button,"North");jup2.add(jmid2_1); cl=new CardLayout();setLayout(cl);add(jup1,"1"); //第一張卡片jup1;add(jup2,"2"); //第二張卡片jup2;setTitle(ownerId);//顯示自己的編號setLocation(300,300); //窗口的位置setSize(440,800);setVisible(true); }public static void main(String[] args) {// TODO Auto-generated method stubQqFriendList qqFriendList=new QqFriendList();}public void actionPerformed(ActionEvent arg0){ //如果點擊了黑名單按鈕,就顯示第二張卡片if(arg0.getSource()==jdown1_1){cl.show(this.getContentPane(), "2"); //用getContentPane()方法獲得JFrame的內容面板}elseif(arg0.getSource()==jup2_1){cl.show(this.getContentPane(), "1");}}public void mouseEntered(MouseEvent arg0) { //進入組件觸發鼠標事件// TODO Auto-generated method stubJLabel jl=(JLabel)arg0.getSource(); //變成JLable形式//getSource()獲取鼠標事件的事件源;jl.setForeground(Color.red); //設置前景色}public void mouseExited(MouseEvent arg0) { //鼠標離開組件觸發的鼠標事件// TODO Auto-generated method stubJLabel jl=(JLabel)arg0.getSource(); jl.setForeground(Color.black);}public void mouseClicked(MouseEvent arg0) { //點擊鼠標觸發鼠的標事件// TODO Auto-generated method stub//響應用戶雙擊的事件,并得到好友的編號.if(arg0.getClickCount()==2) //getClickCount() 獲取鼠標被單機的次數{//得到該好友的編號 //getText() 的意思是:返回數據窗口控件中 懸浮在當前行列之上的String friendNum=((JLabel)arg0.getSource()).getText();//System.out.println("你希望和 "+friendNum+" 聊天");new QqChat(owner,friendNum); //傳入編號}}public void mousePressed(MouseEvent arg0) { //按下按鼠標鍵觸發的鼠標事件// TODO Auto-generated method stub}public void mouseReleased(MouseEvent arg0) { //釋放鼠標鍵觸發的鼠標事件// TODO Auto-generated method stub } } package com.qq.client.model; import com.qq.common.*; public class QqClientUser {public boolean checkUser(User u){return new QqClientConServer().sendLoginInfotoSSErver(u);} } //客戶端鏈接服務器的部分 package com.qq.client.model;import java.util.*; import java.net.*; import java.io.*; import com.qq.common.*; public class QqClientConServer{//發送第一次請求,登錄請求public boolean sendLoginInfotoSSErver(Object o) //發送對象到服務器{ boolean b=false;try{ Socket s=new Socket("127.0.0.1",9999); //傳入要連接主機與端口ObjectOutputStream oos=new ObjectOutputStream(s.getOutputStream()); //輸出流oos.writeObject(o); //把o發出去ObjectInputStream ois=new ObjectInputStream(s.getInputStream());Message ms=(Message)ois.readObject(); if(ms.getMesType().equals("1"))b=true;}catch (Exception e){e.printStackTrace();}finally{}return b;} }

服務端
除了需要的Message.java和User.java兩個類還需要

//服務器端控制界面,可以完成啟動服務器,關閉服務器,可以管理和監控用戶 package com.qq.server.view;import javax.swing.*; import java.awt.*; import java.awt.event.*; import com.qq.server.model.MyQqServer; public class ControlPanel extends JFrame implements ActionListener{JPanel jp1;JButton jstart,jend;public ControlPanel(){ Font font = new Font("宋體",Font.PLAIN,30);jp1=new JPanel();jstart=new JButton("啟動服務器");jstart.addActionListener(this);jend=new JButton("關閉服務器");jstart.setFont(font); jend.setFont(font);jstart.setForeground(Color.BLUE); jend.setForeground(Color.BLUE);jp1.add(jstart);jp1.add(jend);add(jp1);setLocation(150,150);setSize(900,900);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //結束窗口所在的應用程序 setVisible(true);}public static void main(String[] args) {// TODO Auto-generated method stubControlPanel controlpanel =new ControlPanel();}public void actionPerformed(ActionEvent arg0){if(arg0.getSource()==jstart){new MyQqServer();}} } //qq服務器,監聽,等待某個qq客戶端鏈接 package com.qq.server.model;import java.io.*; //(I/O)流庫,提供大量的流類 import java.net.*;//導入網絡包 import java.util.*; //實用工具類,提供了一些實用的方法和數據結構 import com.qq.common.*;public class MyQqServer {public MyQqServer (){//try-catch語句處理異常try{ //ServerSocket類表示服務器socket//在9999監聽System.out.println("服務器正在9999監聽");//簡單判斷一下是否啟動服務端ServerSocket ss=new ServerSocket(9999);while(true) //服務器可多次監聽{Socket s=ss.accept() ; //阻塞,等待連接(與客戶端)//接收客戶端發來的信息ObjectInputStream ois=new ObjectInputStream(s.getInputStream());User u=(User)ois.readObject();System.out.println("用戶Id:"+u.getUserId()+" 密碼"+u.getPasswd()); Message m=new Message();ObjectOutputStream oos=new ObjectOutputStream(s.getOutputStream());if(u.getPasswd().equals("123456")){//返回一個成功登錄的信息m.setMesType("1"); //mesType1 =1 表明登陸成功oos.writeObject(m); }else{m.setMesType("2"); oos.writeObject(m); s.close(); //關閉連接(流)}}}catch(Exception e){e.printStackTrace();//將錯誤信息全部打印}finally{}} }

4.一對一的聊天

進程概念:進程是代碼在數據集合上的一次運行活動,是系統進行資源分配和調度的基本單位。
線程概念:線程是進程的一個執行路徑,一個進程中至少有一個線程,進程中的多個線程共享進程的資源。

此處要用線程用來接收客戶端的消息,因為不僅僅一個用戶(可實現多用戶登錄)
要在message類里面加入,用戶編號,接受方,發送信息(即獲得聊天界面文本框的內容)等
在chat類里面,加入讀取,文本域中顯示聊天代碼等內容
在管理客戶端線程中使用HashMap<關鍵字,值>記錄發送者與服務器的socket,關鍵字記錄用戶編號,值記錄socket

每個包(類)或多或少都有所更改,完整代碼如下,希望對大家有所幫助,同時請大佬指正錯誤%%%

//
客戶端代碼

package com.qq.common;public class Message implements java.io.Serializable { //序列化private String mesType;private String sender;//發送者private String getter; //接收者private String con; //信息public String getSender(){return sender;}public void setSender(String sender){this.sender=sender;}public String getGetter(){return getter;}public void setGetter(String getter){this.getter=getter;}public String getCon(){return con;}public void setCon(String con){this.con=con;}public String getMesType(){return mesType;}public void setMesType(String mesType){this.mesType =mesType;} } //用戶信息類 package com.qq.common;public class User implements java.io.Serializable{private String userId;private String passwd;public String getUserId(){return userId;}public void setUserId(String userId) {this.userId = userId;}public String getPasswd(){return passwd;}public void setPasswd(String passwd){this.passwd=passwd;}} // 客戶端的登陸界面 package com.qq.client.view; //抽象窗口工具包 import javax.swing.*; import java.awt.*; import java.awt.event.*; import com.qq.client.model.*; import com.qq.common.*; public class QqClientlLogin extends JFrame implements ActionListener{ //JFrame的子類JLabel jup; //定義上部需要的組件 //標簽//定義中部需要的組件JPanel jmid ;JLabel jmid_num1,jmid_key1;JTextField jmid_num2; //文本框JPasswordField jmid_key2; //密碼框JCheckBox jmid_rember,jmid_automatic; //復選框JPanel jdown; //JPanel 面板JButton jdown_1,jdown_2; //定義下部需要的組件public QqClientlLogin() //構造方法{//處理上部 jup=new JLabel(new ImageIcon("image/up3.png"));//處理中部jmid=new JPanel(new GridLayout(3,3));//網格布局 3行3列Font font = new Font("宋體", Font.PLAIN, 25); //創建1個字體實例jmid_num1=new JLabel("QQ號碼:",JLabel.CENTER); jmid_key1=new JLabel("QQ密碼:",JLabel.CENTER);jmid_num1.setFont(font); jmid_key1.setFont(font); //字體大小jmid_num2= new JTextField() ; jmid_key2=new JPasswordField();jmid_rember=new JCheckBox("自動登錄");jmid_automatic=new JCheckBox("記住密碼");jmid_rember.setFont(font); jmid_automatic.setFont(font); //字體大小jmid_rember.setForeground(Color.blue); //設置字體顏色jmid_automatic.setForeground(Color.blue);jmid.add(jmid_num1);jmid.add(jmid_num2);jmid.add(jmid_key1);jmid.add(jmid_key2);jmid.add(jmid_rember);jmid.add(jmid_automatic);//處理下部jdown=new JPanel(new FlowLayout()); //流式布局jdown_1=new JButton(new ImageIcon("image/denglu.png"));//響應用戶點擊登錄jdown_1.addActionListener(this); //監控jdown_2=new JButton(new ImageIcon("image/tuichu.png"));jdown.add(jdown_1);jdown.add(jdown_2);setLocation(300,300); //窗口的位置add(jup,"North"); //放在最北部 add(jmid,"Center"); //放在中間add(jdown,"South"); //放在南部setSize(700,540); //設置大小 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //結束窗口所在的應用程序 setVisible(true); //可見,默認是不可見}public static void main(String[] args){QqClientlLogin qqClientlLogin=new QqClientlLogin();} public void actionPerformed(ActionEvent arg0){if(arg0.getSource()==jdown_1); //請求登錄{User u=new User();u. setUserId(jmid_num2.getText().trim()); //trim() 方法用于 刪除字符串的頭尾空白符u. setPasswd(new String (jmid_key2.getPassword())); //字符串;QqClientUser qqclientuser=new QqClientUser();if(qqclientuser.checkUser(u)){QqFriendList qqList=new QqFriendList(u.getUserId()); //好友列表this.dispose(); //關閉登陸界面}else{JOptionPane.showMessageDialog(this,"用戶名或密碼錯誤");//JOptionPane彈窗,消息提示框//showMessageDialog這個方法里有兩個參數//第一個參數-確定Frame在其中顯示的對話框//第二個參數message就是我們要在提示框里顯示的信息}}} } //好友列表(也包括黑名單) package com.qq.client.view;import javax.swing.*; import java.awt.*; import java.awt.event.*;public class QqFriendList extends JFrame implements ActionListener,MouseListener { //負責創建監聽器的類, 點擊按鈕觸發ActionListener事件; 鼠標監聽MouseListener String owner; // 第一張卡片(我的好友);JPanel jup1,jmid1,jdown1; //jup1即為總JPanel;JButton jup1_1,jdown1_1;JScrollPane jmid1_1; //滑動窗口;//第二張卡片(黑名單);JPanel jup2,jup2_button,jmid2;JButton jup2_1,jup2_2;JScrollPane jmid2_1; //滑動窗口;//把整個JFrame設置成CardLayout布局CardLayout cl;public QqFriendList (String ownerId){ Font font = new Font("宋體", Font.PLAIN, 35); //創建字體實例 owner=ownerId;//處理第一張卡片(我的好友);jup1=new JPanel(new BorderLayout()); //第一張卡片的總JPane,BorderLayout()布局;jup1_1=new JButton("我的好友");jup1_1.setFont(font); //字體//假設有50個好友,具體是服務器返回的結果(好友信息存放在服務器)jmid1=new JPanel(new GridLayout(50,1,4,4)); //(4,4)行間距和列間距//給jmid1初始化50個好友JLabel []jlist1=new JLabel [50]; //數組;for ( int i=0; i<jlist1.length ; i++ ){jlist1[i]=new JLabel(i+1+" ",new ImageIcon("image/touxiang.png"),JLabel.LEFT);jlist1[i].addMouseListener(this);jmid1.add(jlist1[i]); }jmid1_1=new JScrollPane(jmid1);jdown1_1=new JButton("黑名單");jdown1_1.addActionListener(this); //給jdown1_1按鈕增加一個監聽器,這個監聽器對象就是“QqFriendList ”類型的,//當用戶點擊了jdown1_1按鈕時,會程序自動前往QqFriendList類的“actionPerformed”方法中,處理產生的事件。jdown1_1.setFont(font); //字體jdown1=new JPanel(new GridLayout(1,1));//黑名單按鈕jdown1.add(jdown1_1); //加入按鈕;jup1.add(jup1_1,"North");jup1.add(jmid1_1,"Center");jup1.add(jdown1,"South");//處理第二張卡片(黑名單) jup2=new JPanel(new BorderLayout()); //第二張卡片的總JPane,BorderLayout()布局;jup2_1=new JButton("我的好友");jup2_1.addActionListener(this); //監聽jup2_2=new JButton("黑名單");jup2_1.setFont(font); //字體jup2_2.setFont(font);jup2_button=new JPanel(new GridLayout(2,1));//黑名單按鈕jup2_button.add(jup2_1);jup2_button.add(jup2_2);//假設有20個黑名單,具體是服務器返回的結果(好友信息存放在服務器)jmid2=new JPanel(new GridLayout(20,1,4,4)); //(4,4)行間距和列間距//給jmid2初始化20個好友JLabel []jlist2=new JLabel [20]; //數組;for ( int i=0; i<jlist2.length ; i++ ){jlist2[i]=new JLabel(i+1+" ",new ImageIcon("image/heitou.png"),JLabel.LEFT);jmid2.add(jlist2[i]);}jmid2_1=new JScrollPane(jmid2);jup2.add(jup2_button,"North");jup2.add(jmid2_1); cl=new CardLayout();setLayout(cl);add(jup1,"1"); //第一張卡片jup1;add(jup2,"2"); //第二張卡片jup2;setTitle(ownerId);//顯示自己的編號setLocation(300,300); //窗口的位置setSize(440,800);setVisible(true); }public static void main(String[] args) {// TODO Auto-generated method stub//QqFriendList qqFriendList=new QqFriendList();} public void actionPerformed(ActionEvent arg0){ //如果點擊了黑名單按鈕,就顯示第二張卡片if(arg0.getSource()==jdown1_1){cl.show(this.getContentPane(), "2"); //用getContentPane()方法獲得JFrame的內容面板}elseif(arg0.getSource()==jup2_1){cl.show(this.getContentPane(), "1");}}public void mouseEntered(MouseEvent arg0) { //進入組件觸發鼠標事件// TODO Auto-generated method stubJLabel jl=(JLabel)arg0.getSource(); //變成JLable形式//getSource()獲取鼠標事件的事件源;jl.setForeground(Color.red); //設置前景色}public void mouseExited(MouseEvent arg0) { //鼠標離開組件觸發的鼠標事件// TODO Auto-generated method stubJLabel jl=(JLabel)arg0.getSource(); jl.setForeground(Color.black);}public void mouseClicked(MouseEvent arg0) { //點擊鼠標觸發鼠的標事件// TODO Auto-generated method stub//響應用戶雙擊的事件,并得到好友的編號.if(arg0.getClickCount()==2) //getClickCount() 獲取鼠標被單機的次數{//得到該好友的編號 //getText() 的意思是:返回數據窗口控件中 懸浮在當前行列之上的String friendNum=((JLabel)arg0.getSource()).getText();//System.out.println("你希望和 "+friendNum+" 聊天");QqChat qqChat=new QqChat(owner,friendNum); //傳入編號Thread t=new Thread(qqChat); t.start(); // 啟動線程}}public void mousePressed(MouseEvent arg0) { //按下按鼠標鍵觸發的鼠標事件// TODO Auto-generated method stub}public void mouseReleased(MouseEvent arg0) { //釋放鼠標鍵觸發的鼠標事件// TODO Auto-generated method stub } } //與好友聊天的界面//因為客戶端,要處于讀取的狀態,因此我們把它做成一個線程 package com.qq.client.view; import javax.swing.*; import java.awt.*; import java.io.*; import java.awt.event.*; import com.qq.common.*; import com.qq.client.model.*; public class QqChat extends JFrame implements ActionListener,Runnable{ //監聽發送按鈕Font font = new Font("宋體", Font.PLAIN, 20); //實現Runnable接口實現多線程,JTextArea jta; //文本域 存聊天內容JTextField jtf; //文本框JButton jb;JPanel jp;String ownerId;String friendId;public QqChat(String owner,String friend){ ownerId= owner;friendId=friend;jta=new JTextArea();jtf=new JTextField(25); //25個字符那么寬jb=new JButton("發送");jb.addActionListener(this);jb.setFont(font);jp=new JPanel();jp.add(jtf);jp.add(jb); add(jta,"Center");add(jp,"South");setTitle(owner+"正在和 "+friend+" 聊天"); //設置標題setIconImage((new ImageIcon("image/qq.png").getImage())); //獲取圖像setLocation(800,400); //窗口的位置setSize(600, 500);setVisible(true);}//寫一個方法,讓它顯示消息public void showMessage(Message m){String info=m.getSender()+" 給"+m.getGetter()+" 發送:"+m.getCon()+"\r\n";this.jta.append(info);}public void actionPerformed(ActionEvent arg0) {// TODO Auto-generated method stubif(arg0.getSource()==jb)//如果用戶點擊了發送按鈕{Message m=new Message();m.setSender(this.ownerId);m.setGetter(this.friendId);m.setCon(jtf.getText()); //文本框中得到 //發送給服務器 要拿到socket,可以把socket寫成靜態的,從類里面拿出來;try { ObjectOutputStream oos=new ObjectOutputStream(QqClientConServer.s.getOutputStream());oos.writeObject(m);} catch (Exception e) {e.printStackTrace();} } }public void run(){while(true){ //一直處于讀取狀態(如果讀不到就等待)try{ObjectInputStream ois=new ObjectInputStream(QqClientConServer.s.getInputStream());Message m =(Message)ois.readObject(); //顯示String info=m.getSender()+"給"+m.getGetter()+"發送"+m.getCon()+"\r\n";this.jta.append(info); //(添加)追加到文本域}catch(Exception e){e.printStackTrace();}}} } package com.qq.client.model; import com.qq.common.*; public class QqClientUser {public boolean checkUser(User u){return new QqClientConServer().sendLoginInfotoSSErver(u);} } //客戶端鏈接服務器的部分 package com.qq.client.model;import java.util.*; import java.net.*; import java.io.*; import com.qq.common.*; public class QqClientConServer{public static Socket s;//發送第一次請求,登錄請求public boolean sendLoginInfotoSSErver(Object o) //發送對象到服務器{ boolean b=false;try{ s=new Socket("127.0.0.1",9999); //傳入要連接主機與端口ObjectOutputStream oos=new ObjectOutputStream(s.getOutputStream()); //輸出流oos.writeObject(o); //把o發出去ObjectInputStream ois=new ObjectInputStream(s.getInputStream());Message ms=(Message)ois.readObject(); if(ms.getMesType().equals("1"))b=true;}catch (Exception e){e.printStackTrace();}finally{}return b;} }

服務端代碼(message,user與客戶端一樣,這里不在寫出,直接復制過去就可以)

//服務器端控制界面,可以完成啟動服務器,關閉服務器,可以管理和監控用戶 package com.qq.server.view;import javax.swing.*; import java.awt.*; import java.awt.event.*; import com.qq.server.model.MyQqServer; public class ControlPanel extends JFrame implements ActionListener{JPanel jp1;JButton jstart,jend;public ControlPanel(){ Font font = new Font("宋體",Font.PLAIN,30);jp1=new JPanel();jstart=new JButton("啟動服務器");jstart.addActionListener(this);jend=new JButton("關閉服務器");jstart.setFont(font); jend.setFont(font);jstart.setForeground(Color.BLUE); jend.setForeground(Color.BLUE);jp1.add(jstart);jp1.add(jend);add(jp1);setLocation(150,150);setSize(900,900);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //結束窗口所在的應用程序 setVisible(true);}public static void main(String[] args) {// TODO Auto-generated method stubControlPanel controlpanel =new ControlPanel();}public void actionPerformed(ActionEvent arg0){if(arg0.getSource()==jstart){new MyQqServer();}} } //qq服務器,監聽,等待某個qq客戶端鏈接 package com.qq.server.model;import java.io.*; //(I/O)流庫,提供大量的流類 import java.net.*;//導入網絡包 import java.util.*; //實用工具類,提供了一些實用的方法和數據結構 import com.qq.common.*;public class MyQqServer {public MyQqServer (){//try-catch語句處理異常try{ //ServerSocket類表示服務器socket//在9999監聽System.out.println("服務器正在9999監聽");//簡單判斷一下是否啟動服務端ServerSocket ss=new ServerSocket(9999);while(true) //服務器可多次監聽{Socket s=ss.accept() ; //阻塞,等待連接(與客戶端)//接收客戶端發來的信息ObjectInputStream ois=new ObjectInputStream(s.getInputStream());User u=(User)ois.readObject();System.out.println("用戶Id:"+u.getUserId()+" 密碼"+u.getPasswd()); Message m=new Message();ObjectOutputStream oos=new ObjectOutputStream(s.getOutputStream());if(u.getPasswd().equals("123456")){//返回一個成功登錄的信息m.setMesType("1"); //mesType1 =1 表明登陸成功oos.writeObject(m); //單開一個線程,讓該線程與該客戶端保持通信SerConClientThread scct=new SerConClientThread(s);ManageClientThread.addClientThread(u.getUserId(),scct);//放到HashMapscct.start(); //啟動與該客戶端通信的線程}else{m.setMesType("2"); oos.writeObject(m); s.close(); //關閉連接(流)}}}catch(Exception e){e.printStackTrace();//將錯誤信息全部打印}finally{}} } //服務器和某個客戶端的通信線程 package com.qq.server.model;import java.net.*; import java.io.*; import com.qq.common.*; public class SerConClientThread extends Thread //繼承Thread類 { Socket s;public SerConClientThread(Socket s){this.s=s; //把服務器和該客戶端的連接賦給s;}public void run(){while(true){//這里該線程就可以接受客戶端的信息try{ObjectInputStream ois=new ObjectInputStream(s.getInputStream());Message m=(Message)ois.readObject();System.out.println(m.getSender()+"給 "+m.getGetter()+"發送: "+m.getCon());//判斷接受到客戶端的信息//拿到發送者與服務器的socket,此時就需要hashmap;SerConClientThread sc=ManageClientThread.getClientThread(m.getGetter());ObjectOutputStream oos=new ObjectOutputStream(sc.s.getOutputStream()); //接受人的通信線程;oos.writeObject(m);}catch(Exception e){e.printStackTrace();}}} } //管理客戶端線程 package com.qq.server.model;import java.util.*;public class ManageClientThread { public static HashMap hm=new HashMap<String, SerConClientThread>();//向hm中添加一個客戶通訊線程public static void addClientThread(String uid,SerConClientThread ct){hm.put(uid, ct);}//返回socketpublic static SerConClientThread getClientThread(String uid){return (SerConClientThread) hm.get(uid);}}

總結

以上是生活随笔為你收集整理的java实现qq聊天(超详细)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。