【Java】JavaSocket编程开发聊天室-总览与部分客户端界面
1.實(shí)驗(yàn)要求.
- 用Java圖形用戶界面編寫(xiě)聊天室服務(wù)器端和客戶端, 支持多個(gè)客戶端連接到一個(gè)服務(wù)器。每個(gè)客戶端能夠輸入賬號(hào)。
- 可以實(shí)現(xiàn)群聊(聊天記錄顯示在所有客戶端界面)。
- 完成好友列表在各個(gè)客戶端上顯示。
- 可以實(shí)現(xiàn)私人聊天,用戶可以選擇某個(gè)其他用戶,單獨(dú)發(fā)送信息。
- 服務(wù)器能夠群發(fā)系統(tǒng)消息,能夠強(qiáng)行讓某些用戶下線。
- 客戶端的上線下線要求能夠在其他客戶端上面實(shí)時(shí)刷新。
2.實(shí)驗(yàn)平臺(tái)及語(yǔ)言.
實(shí)驗(yàn)選擇語(yǔ)言為Java,開(kāi)發(fā)平臺(tái)為Eclipse IDE for Enterprise Java Developers.
Version: 2019-06 (4.12.0)
3.項(xiàng)目完整代碼.
JavaSocket編程開(kāi)發(fā)聊天室ThreeStrikes.
4.設(shè)計(jì)思路.
- 整個(gè)項(xiàng)目采用Client-Server設(shè)計(jì)模式,粗略地可以分為兩個(gè)部分,即客戶端Client與服務(wù)器端Server。客戶端與服務(wù)器端進(jìn)行交互的方式是:客戶端封裝自己需要進(jìn)行的操作,例如發(fā)送文本消息、發(fā)送窗口抖動(dòng)、登錄、退出等,成為一類(lèi)抽象的請(qǐng)求-plea,每一種不同的plea實(shí)例化之后通過(guò)不同的標(biāo)識(shí)屬性值來(lái)進(jìn)行區(qū)分,而后將請(qǐng)求送達(dá)服務(wù)器端。服務(wù)器端采用多線程策略,為每一個(gè)到達(dá)的客戶端請(qǐng)求建立一個(gè)線程,專(zhuān)門(mén)為該客戶端服務(wù),接收到客戶端傳來(lái)的plea后,服務(wù)器端內(nèi)部進(jìn)行一系列的處理(判斷該請(qǐng)求是否合法、是否正確,比如你不能向自己發(fā)送消息、你不能用錯(cuò)誤的賬號(hào)和密碼進(jìn)行登錄),之后服務(wù)器端封裝自己的處理結(jié)果,例如允許登錄、允許客戶端發(fā)送消息等,成為一類(lèi)抽象的回答-reply,每一種不同的reply實(shí)例化之后也通過(guò)不同的標(biāo)識(shí)屬性值來(lái)進(jìn)行區(qū)分,而后將回答返還給客戶端。
- 在具體的實(shí)現(xiàn)過(guò)程中,我們不可能將所有的功能都實(shí)現(xiàn)在同一個(gè)類(lèi)中。比方說(shuō),按照我們上面的分析,我們只設(shè)計(jì)4個(gè)類(lèi):Client、Server、Plea、Reply就從邏輯上完成了整個(gè)項(xiàng)目。但這顯然是不合理的,每一個(gè)類(lèi)中會(huì)有太多的功能,例如Client類(lèi)中,既要進(jìn)行登錄、注冊(cè)、聊天界面的設(shè)計(jì),又要完成發(fā)送消息、接收消息等業(yè)務(wù)代碼的實(shí)現(xiàn),這樣的代碼即使不出差錯(cuò)地寫(xiě)出來(lái)了,也是不忍回首的。我的想法是,從界面設(shè)計(jì)入手。用戶最先進(jìn)入的界面是登錄界面,而后產(chǎn)生分支——或是選擇注冊(cè),或是選擇直接進(jìn)入聊天室,在界面設(shè)計(jì)的過(guò)程中,不斷進(jìn)行功能之間的解耦合(例如登錄界面中就不會(huì)考慮到發(fā)送消息的功能),不斷細(xì)化整個(gè)客戶端的分類(lèi),同時(shí)也不斷實(shí)現(xiàn)每一個(gè)界面上需要實(shí)現(xiàn)的功能。
- 下面我們從客戶端Client部分入手,講述整個(gè)項(xiàng)目的實(shí)現(xiàn)及其細(xì)節(jié)。
5.Client客戶端.
ClientLauncher.
ClientLauncher是用戶看到的客戶端的入口,由于服務(wù)器端Server是需要先于客戶端Client啟動(dòng)的,所以我們講述時(shí),會(huì)假定已經(jīng)有一個(gè)"Server"已經(jīng)在等待著為我們服務(wù)了。整個(gè)ClientLauncher的代碼并不是很長(zhǎng),我們?cè)谙旅嬷苯咏o出其main函數(shù):
public static void main(String[] args) {//Connect with a Server.Make_Connection();//Client appearance.JFrame.setDefaultLookAndFeelDecorated(true);JDialog.setDefaultLookAndFeelDecorated(true);try{String LookAndFeel = UIManager.getCrossPlatformLookAndFeelClassName();UIManager.setLookAndFeel(LookAndFeel);}catch(Exception e){e.printStackTrace();}new ClientLogin();}可以看出ClientLauncher中實(shí)際上只做了兩件事:1、進(jìn)行客戶端與服務(wù)端連接的初始化建立;2、給出整個(gè)UI的風(fēng)格確定(即代碼中的getCrossPlatformLookAndFeelClassName())。
在Make_Connection()中,我們所做的事情就是從預(yù)先配置好的屬性文件中,按名讀取"IP"與"Port"用于建立從客戶端到服務(wù)器端的Socket,并且通過(guò)該Socket我們能夠?qū)B接的輸入流和輸出流進(jìn)行操作。關(guān)于屬性文件的操作,可以參看《Eclipse項(xiàng)目中創(chuàng)建.properties屬性文件及其中屬性》。
注意到ClientLauncher的最后,我們通過(guò)new創(chuàng)建了一個(gè)ClientLogin對(duì)象,顧名思義,這就是用戶登錄的界面。關(guān)于Java的各種顯示風(fēng)格,只需要更改setLookAndFeel()中的參數(shù)即可,這里使用的CrossPlatform是一種不依賴(lài)于操作系統(tǒng)的界面風(fēng)格,在每一種OS上都能夠展示出來(lái)。
ClientLogin.
ClientLauncher以調(diào)出ClientLogin的界面結(jié)束,我們下面直接給出ClientLogin的構(gòu)造器代碼:
public ClientLogin() {Initialize();setVisible(true); }由于需要GUI,所以我們讓ClientLogin繼承了JFrame類(lèi),這也是需要setVisible(true)讓整個(gè)GUI顯示出來(lái)的原因。Initialize()方法中進(jìn)行的是整個(gè)登陸界面的控件擺放,包括輸入賬號(hào)、密碼的輸入框、登錄按鈕、注冊(cè)按鈕以及一個(gè)出于美觀考慮的Logo,除此之外,Initialize()方法中還完成了各種控件和事件監(jiān)聽(tīng)器的綁定。最后的GUI如下圖所示:
界面設(shè)計(jì)的細(xì)節(jié)描述如下:
- 設(shè)置界面上的字體,示例代碼以JLabel為例,實(shí)際上很多控件都可以通過(guò)setFonts()方法來(lái)進(jìn)行字體更改。
至于自己的電腦上已經(jīng)安裝了哪些字體,以Win10為例,可以在C:\Windows\Fonts文件夾中查看。
- 設(shè)置邊框,例如上圖中包含Login Info的邊框。
代碼段中createEtchedBorder()的意思是創(chuàng)建蝕刻風(fēng)格的邊框,而下面依據(jù)中的createTitleBorder則是在已經(jīng)創(chuàng)建好的蝕刻邊框上加入文字信息,我們對(duì)比其中的參數(shù)以及上圖中的最終UI效果,不難看出其中參數(shù)的作用。更多關(guān)于邊框的歸納知識(shí),可以參看這篇文章。
- 設(shè)置背景色,無(wú)法通過(guò)直接調(diào)用setBackground(Color)來(lái)實(shí)現(xiàn),雖然調(diào)用這一方法確實(shí)設(shè)置了背景色,但你卻無(wú)法看到它,因?yàn)槌尸F(xiàn)出來(lái)的是contentPane的背景色。問(wèn)題的關(guān)鍵在于,JComponent控件中的Opaque屬性默認(rèn)是false的,Opaque意為不透明,該屬性為false也就意味著這一控件透明,所以最終的GUI會(huì)透過(guò)該控件而顯示出底層的顏色。
關(guān)于Color,我們可以使用Java預(yù)定義的值,例如Color.BLUE、Color.BLACK,也可以向上述代碼中,通過(guò)RGB值來(lái)創(chuàng)建一個(gè)Color實(shí)例。至于如何查看某處顏色的RGB值,可以參看圖片任意點(diǎn)的RGB值。
- JButton的事件監(jiān)聽(tīng)器綁定,這是GUI程序中很常見(jiàn)的一種操作。
通過(guò)addActionListener()方法,我們可以將一個(gè)"動(dòng)作"綁定到一個(gè)按鈕上,當(dāng)這個(gè)按鈕被點(diǎn)擊時(shí),就執(zhí)行綁定到上面的動(dòng)作。其中關(guān)于匿名內(nèi)部類(lèi)的語(yǔ)法,就不再贅述。
- 驗(yàn)證賬號(hào)的正確性。上面給出的GUI界面中,有【Sign Up】和【Sign in】?jī)蓚€(gè)JButton,它們分別對(duì)應(yīng)于進(jìn)入注冊(cè)界面注冊(cè)一個(gè)新賬號(hào)和使用已有的賬號(hào)登錄進(jìn)入聊天室。我們先敘述ClientRegister類(lèi)中的內(nèi)容,而后再講述,如何驗(yàn)證賬號(hào)的正確性。
ClientRegister.
在ClientLogin的GUI上點(diǎn)擊【Sign Up】會(huì)進(jìn)入ClientRegister的界面,客戶端注冊(cè)類(lèi)的構(gòu)造器和客戶端登錄類(lèi)完全一樣,區(qū)別就在于它們各自的Initialize()方法中所進(jìn)行的界面設(shè)計(jì)以及綁定到控件的動(dòng)作。ClientRegister中涉及昵稱(chēng)、密碼、再次確認(rèn)密碼、性別、頭像這些輸入型控件以及完成注冊(cè)、重填信息以及取消注冊(cè)這些輔助功能按鈕的設(shè)置,最后的GUI界面如下所示:
界面設(shè)計(jì)上的細(xì)節(jié)描述如下:
- 空布局null,這種布局策略相較于我們常見(jiàn)的邊界布局BorderLayout、流式布局FlowLayout來(lái)說(shuō),程序員需要做的事情變多了,但好處是控件的擺放更為靈活。對(duì)于一個(gè)控件,我們可以通過(guò)方法setBounds(int x,int y,int width,int height)來(lái)精確控制它在最終GUI中的位置。需要注意的是,setBounds()方法中的參數(shù)不是相較于整個(gè)屏幕而言,而是相較于采用null布局的這個(gè)界面而言。
- 單選按鈕JRadioButton,單選按鈕并沒(méi)有很復(fù)雜的用法,我們上述的GUI中用它來(lái)給用戶提供性別選擇。
其中Male按鈕的構(gòu)造器中的第二個(gè)參數(shù),是設(shè)置該按鈕是否默認(rèn)選中,并且該參數(shù)默認(rèn)為false。
- 下拉框JComboBox,下拉框是一種很便捷的展示形式,我們這里用它來(lái)進(jìn)行頭像的展示,頭像圖片的.png文件都是存放在項(xiàng)目下的文件夾中的。下拉框的具體效果如下圖所示:
上述代碼段有關(guān)GUI中下拉框的部分,.png文件的位置是可以自由設(shè)置的。這里的兩個(gè)方法setMaximunRowCount(int x)是指下列的視圖中最多顯示幾個(gè)完整的item,我們從上面的下拉框效果圖中也可以看出這一點(diǎn),而setSelectedIndex(int x)則是設(shè)置默認(rèn)選中的item的序列號(hào)(從0開(kāi)始).
- 記錄完成注冊(cè)流程的用戶,當(dāng)用戶完成了信息的正確輸入之后點(diǎn)擊了OK按鈕,我們就需要將這一用戶的信息保存到本地的.db文件(是服務(wù)器端Server完成這一工作的,客戶端不應(yīng)該擁有修改記錄所有用戶信息的.db文件,.db文件同樣是在前面提到的屬性文件中完成配置的),用于登錄時(shí)的賬號(hào)驗(yàn)證。顯然,記錄下完成注冊(cè)的用戶信息并不是客戶端自己能夠完成的事情,所以這里需要和服務(wù)器端Server進(jìn)行交互。首先客戶端向Server發(fā)送標(biāo)記為【注冊(cè)】的請(qǐng)求以及表示該用戶的【抽象用戶數(shù)據(jù)】,而后等待Server的回復(fù)。這里我們先不展開(kāi)敘述Server所作的工作,理想地認(rèn)為Server能夠給出正確的回復(fù)(例如對(duì)于已有用戶的識(shí)別)。客戶端得到Server的回復(fù)之后,它檢查這個(gè)回復(fù),如果Server回復(fù)中標(biāo)記為了【成功】,客戶端的注冊(cè)界面就給出注冊(cè)成功的信息,否則引導(dǎo)用戶進(jìn)行重填或者退出注冊(cè)。當(dāng)一個(gè)用戶進(jìn)行登錄時(shí),客戶端也會(huì)向Server發(fā)送一個(gè)標(biāo)記為【登錄】的請(qǐng)求以及表示這一用戶的【抽象用戶數(shù)據(jù)】,理想的Server就對(duì)這一請(qǐng)求進(jìn)行處理,判斷是否密碼正確、是否存在這一用戶以及該用戶是否已經(jīng)登錄,從而給出回復(fù)信息,客戶端再根據(jù)回復(fù)中的標(biāo)記,給出錯(cuò)誤信息或者成功進(jìn)入聊天界面。
ClientChat簡(jiǎn)述.
在ClientLogin的GUI上點(diǎn)擊【Sign in】會(huì)進(jìn)入ClientChat的界面,也就是聊天室的主要界面,大同小異的構(gòu)造器就不再贅述。ClientChat的最終GUI如下所示,我們給出了兩個(gè)客戶端的界面:
ClientChat的界面相較于前面的登錄界面、注冊(cè)界面都復(fù)雜了很多,主要分為五個(gè)板塊:左上角的群聊消息區(qū)、左下角的編輯消息區(qū)、右上角的在線用戶列表、右下角的【自己】信息區(qū)以及一些給出輔助功能的區(qū)域(例如有著發(fā)送和退出的按鈕區(qū)、私聊和常見(jiàn)聊天室功能的按鈕區(qū)以及系統(tǒng)狀態(tài)的提示區(qū))。并且在上面展示的GUI中,已經(jīng)進(jìn)行了消息發(fā)送的演示,兩張圖對(duì)比起來(lái)看,可以很清楚看出發(fā)送消息的時(shí)間、邏輯關(guān)系。
在JavaSocket編程開(kāi)發(fā)聊天室-客戶端核心部分中會(huì)詳細(xì)敘述ClientChat的內(nèi)容.
總結(jié)
以上是生活随笔為你收集整理的【Java】JavaSocket编程开发聊天室-总览与部分客户端界面的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: router+x
- 下一篇: Java内存模型_基础