中南大學
《面向對象》課程設計
題
目
“聊天室”課程設計(java 語言)
學生姓名
學生學號
專業班級
指導教師
完成時間
目 目
錄
第一章
聊天室的描述 ------------------------------------------- 3 3
1.1聊天室的設計要求 -------------------------------------------------------------3 1.2聊天室的基本功能 -------------------------------------------------------------3 1.3設計所用參考資料 -------------------------------------------------------------6 第二章
聊天室的設計 ------------------------------------------- 6 2.1聊天室的粗略設計分析 -------------------------------------------------------6 2.2聊天室的具體設計分析 -------------------------------------------------------7 第三章
聊天室的實現 ------------------------------------------- 10
3.1聊天室所使用的類及功能的實現 -----------------------------------------10
第四章
聊天室的運行 ------------------------------------------- 30
第五章 課程設計總結 --------------------------------------------- 31
5.1 開發中所遇到的問題 -----------------------------------------------------------31 5.2 問題分析與解決方法 -----------------------------------------------------------32 5.3 經驗與教訓 ------------------------------------------------------------------------32
第一章
聊天室的描述 1 . 1聊天室的設要求
當今社會,網絡技術越來越發展,可以說,二十一世紀就是網絡的世紀。網絡迅猛發展,勢不可擋。為了實現資源共享,各式各樣的網站發展迅速,各種各樣的聊天工具不斷更新。某公司希望通過一個聊天工具加強員工和客戶之間的溝通和交流。所以制作一個聊天室勢在必行。
為了實現一個更好的網絡交互平臺,各用戶之間能夠實時方便的傳遞信息,按照用戶對系統的要求不同,可以在聊天室里實現公共聊天,也可以邀幾個私交好友私聊,同時提供了兩個用戶之間能夠傳送文件。本系統是基于方便用戶聊天,傳遞信息,共享資源,所以系統的功能主要是從以上幾個模塊著手。
本項目主要是利用 JAVA 語言制作一個聊天室,采用的是客戶/服務器。
二層的 C/S 結構是指以單一的服務器和局域網為核心,能通過客戶端與用戶進行直接對話。主要有二大功能:一是它用于檢查用戶從鍵盤等輸入的數據,顯示應用輸出的數據。為使用戶能直觀地進行操作,一般要使用圖形用戶接口(GUI),操作簡單、易學易用。在變更用戶接口時,只需改寫顯示控制和數據檢查程序,而不影響其他。檢查的內容也只限于數據的形式和值的范圍,不包括有關業務本身的處理邏輯。典型的 C/S 結構有以下特點:
1、服務器負責數據管理及程序處理。
2、客戶機負責界面描述和界面顯示。
3、客戶機向服務器提出處理要求。
4、服務器響應將處理結果返回客戶機。
5、使網絡數據流量最少。
1 1.
2聊天室的基本功能 1. 用戶注冊
2. 用戶登錄 3. 在線用戶列表 4. 用戶公聊 5. 用戶私聊 6. 好友信息維護 7. 私聊信息的維護 8. 登錄日志的維護 9. 用戶注銷 擴展功能(如果完整實現一個擴展功能,適當加分):
1. 可以切換不同的界面風格 2. 用戶可以更改個人資料,尋找密碼 3. 表情聊天 4. 文件傳遞 5. 公聊信息的維護 ? 用戶注冊 第一次用戶需要提供個人注冊信息,注冊的用戶名不能重復,密碼長度不能少于 6 位,個人信息必須提供完整,并且存儲在數據庫中。
? 用戶登錄 用戶輸入用戶名和密碼,提交給將服務器端的確認,根據從服務器中傳過來的確認信息,判斷用戶登錄的情況。并且把此次登錄的時間及登錄的 IP 記錄在服務器。
如果用戶名和密碼正確的話,則登錄聊天室主界面;如果已經在線,則輸出已經在線;否則輸出用戶名和密碼錯誤,需要重新登錄或者注冊。
? 在線用戶列表 用戶登錄之后,需要知道系統中,有哪些用戶在線,這樣可以方便用戶選擇與個別用戶私聊和傳送文件,也可以進行公聊。
? 用戶公聊 用戶輸入的用戶名和密碼都正確后,則進入聊天室。聊天主界面主要由四大版塊組成:公聊的聊天信息、在線用戶列表、好友列表,系統消息和聊天的一些操作。
聊天信息版塊設計思想:一種就是將客戶的聊天信息寫入數據庫,一種是將其寫入向量中。在本次項目中,要求學員把客戶的聊天信息寫入數據庫中。
? 用戶私聊 如果兩個人聊的話題比較隱秘,不想被其他人看到,就要使用私聊。在這里,如果說話對象是所有人的話,不能選擇私聊;從當前好友列表中選擇了一個用戶之后,則私聊對話框應該彈出來。
? 文件傳遞 兩個用戶在聊天過程中,可能需要相互間傳送文件。象用戶聊天信息和在線用戶這樣一些信息都是保存在服務器端,然后每個客戶讀取服務器端向量中的內容,此時服務器與客戶端的聯系是一對多的,而傳送文件是一對一的。所以直接傳送,不需要經過服務器端保存。
? 好友信息維護 在聊天過程中,用戶可以選擇聊天室的用戶加為自己的好友。對于加為好友的用戶,可以選擇與其進行私聊。私聊的信息用文件保存在客戶端。該模塊應該包括:
? 添加好友 ? 刪除好友 ? 私聊信息的維護 如果兩個人聊的話題比較隱秘,不想被其他人看到,就要使用私聊。而且只有好友之間才能進行私聊。要與某用戶進行私聊,必須把對方加為好友。與好友之間的聊天信息,應該以文件的方式存儲在客戶端,不顯示在公聊的版面上。
? 登錄日志的維護 用戶每次登錄之后,都記錄下用戶的登錄信息,如登錄的時間日期,登陸的 IP 等。方便用戶發現是否號碼被盜用。
? 用戶注銷 用戶可以注銷其身份,對于注銷后的用戶必須在數據庫中刪除其相應的信息。
3 1.3 設計所用參考資料
Java 編程思想(第四版)(機械工業出版社)
Java 程序設計與問題解決(人民郵電出版社)
Java 語言最新使用案例教程(清華大學出版社)
Java2 應用開發指南(第二版)(電子工業出版社)
JDK-API-1.5 中文版 網上查閱資料
第二章
聊天室的設計 2 . 1 聊天室的粗略設計分析 聊天系統平臺應有兩個部分組成:服務端和客戶端。服務端主要完成用戶信息的存儲、客戶端命令的接受與響應以及發送系統消息、信息轉發、踢人等服務端應有的功能。客戶端主要完成聊天信息的發送與接受、登錄、注銷等功能。
此 c/s 系統使用的是 TCP/IP 協議,應用了如下通訊模式:
2 2
. 2聊天室的具體設計分析 根據課程設計的要求及項目的需求分析,聊天程序應實現以下幾項功能:登錄、注冊、公聊、私聊、系統消息、踢人、文件傳送、注銷等。
當客戶程序需要與服務器程序通訊的時候,客戶程序在客戶機創建一個 socket 對象。創建了一個 Socket對象后,那么它可以通過調用 Socket 的 getInputStream()方法從服務程序獲得輸入流讀傳送來的信息,也可以通過調用 Socket 的 getOutputStream()方法獲得輸出流來發送消息。
由于 Client 使用了流套接字,所以服務程序也要使用流套接字。這就要創建一個 ServerSocket 對象,接下來服務程序進入無限循環之中,無限循環從調用 ServerSocket 的 accept()方法開始,在調用開始后 accept()方法將導致調用線程阻塞直到連接建立。在建立連接后 accept()返回一個最近創建的 Socket 對象,該 Socket對象綁定了客戶程序的 IP 地址或端口號。由于存在單個服務程序與多個客戶程序通訊的可能,服務程序循環檢測是否有客戶連接到服務器上,如果有,則創建一個線程來服務這個客戶,以此完成對客戶端的監聽。
具體流程如下圖所示:
未注冊用戶:
主界面:
已注冊用戶:
開始 結束 讀取服務器 IP 接收用戶信息 判斷信息
顯示注冊界面
顯示主界面
No Yes
寫入服務器數據庫 公聊 私聊 注銷 文件傳輸 用戶列表 主界面
第三章
聊天室的實現 3 3. 1聊天室所使用的類 及功能的實現 客戶端:
序列化后用來傳遞用戶信息的類:
class User implements Serializable {
String Name;//用戶名
String Password;//密碼
String Email;//e-mail
String Age;//年齡
String sex;// 性別
String Message;//要傳遞的信息
String Command; //命令標識
Vector vectorUserList;//在線用戶列表 } 這個經過序列化后可以用 ObjectOutputStream 和 ObjectInputStream 流來傳遞信息,而不用一行一行的讀取信息。
登錄界面類:
public class Login extends JFrame implements ActionListener{ . . . . //界面組件及其他變量聲明 public Login()
{ . . . 讀取服務器 IP 接收用戶名及密碼 判斷密碼
顯示登錄界面
顯示主界面
No Yes 開始 結束
. .//界面組件初始化 try
{
fsread= new ("c:\\ServerIPaddress.txt");
InputStreamReader inputread= new InputStreamReader(fsread);
BufferedReader bfread= new BufferedReader(inputread);
ServerIPaddress=bfread.readLine();
fsread.close();
toServer= new Socket(ServerIPaddress,1207);
}
catch(IOException e){}
//服務器 IP 地址讀取及連接的建立 public void actionPerformed(ActionEvent e) {
if(e.getSource()==button1)
{
dispose();
new Checkin(toServer);
}
if(e.getActionCommand().equals("登陸"))
{
if(textField1.getText().equals(""))
{
JOptionPane.showMessageDialog(null,"用戶名不能為空!");
}
else {
try{
User user=new User();
User userlogin=new User();
user.Name=textField1.getText();
user.Password=textField2.getText();
user.Command="Enter";
streamToServer=new ObjectOutputStream(toServer.getOutputStream());
streamFromServer=new ObjectInputStream(toServer.getInputStream());
streamToServer.writeObject((User)user);
streamToServer.flush();
userlogin=(User)streamFromServer.readObject();
if(userlogin.Command.equals("Enter"))
{
new MainFrame(toServer,user.Name);
dispose();
}
else JOptionPane.showMessageDialog(null,"用戶名或密碼錯誤!");
textField1.setText("");
textField2.setText("");
}catch(Exception ee){JOptionPane.showMessageDialog(null,"連接錯誤!");}
}
try{
streamToServer.close();
streamFromServer.close();
}catch(Exception ee){}
}
}
//按鈕動作及對服務器命令的響應
public static void main(String args[]) {
JFrame.setDefaultLookAndFeelDecorated(true);
Font font =new Font("JFrame",Font.PLAIN,14);
Enumeration keys=UIManager.getLookAndFeelDefaults().keys();
while(keys.hasMoreElements()){
Object key=keys.nextElement();
if(UIManager.get(key) instanceof Font )UIManager.put(key,font);
}
new Login();
}
//main 方法 } 注冊界面類:
public class Checkin extends JFrame
implements ActionListener{ . . .. . .
//界面組件及其他變量聲明 public Checkin(Socket toServer)
{ . . . ..
//界面組件初始化 try{ ToServer=toServer;
streamToServer = new ObjectOutputStream(ToServer.getOutputStream());
streamFromServer=new ObjectInputStream(ToServer.getInputStream()); }catch(Exception e){}
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
}
//將 Login 中建立的 socket 做參數傳遞給 Checkin public void actionPerformed(ActionEvent e) {
if(e.getActionCommand().equals("注冊"))
{
for(int t=0;t==0;){
if(textField1.getText().equals(""))
{
JOptionPane.showMessageDialog(null,"用戶名不能為空!");
t=1;
}
else if(textField3.getText().equals(textField2.getText())==false)
{
JOptionPane.showMessageDialog(null,"密碼不一致!");
t=1;
}else{
User user=new User();
user.Name=textField1.getText();
user.Password=textField2.getText();
user.Age=textField4.getText();
user.Email=textField5.getText();
user.sex=(String)checkboxGroup1.getSelectedCheckbox().getLabel();
user.Command="Login";
try{
streamToServer.writeObject((User)user);
fromServerMessage=(User)streamFromServer.readObject();
}catch(Exception ee){JOptionPane.showMessageDialog(null,"數據發送錯誤!");}
if(fromServerMessage.Command.equals("Login"))
{
dispose();
new MainFrame(ToServer,user.Name);
}
if(fromServerMessage.Command.equals("Repeat"))
{
JOptionPane.showMessageDialog(null,"用戶名已存在!");
t=1;
}
}
}
}
if(e.getActionCommand().equals("取消"))
{
dispose();
new Login();
}
}
//按鈕動作的添加及對服務器的信息傳//遞和響應 } 主界面類:
public class MainFrame extends JFrame implements ActionListener,Runnable{
. . . . .
//界面組件及其他變量聲明 public MainFrame(Socket toServer,String name) {
MainFrame1(toServer,name);
//構造函數,其中 toServer、name 為參數
}
public void MainFrame1(Socket toServer,String name) { . . . .
try{
ToServer=toServer;
streamToServer = new ObjectOutputStream(ToServer.getOutputStream());
streamFromServer = new ObjectInputStream(ToServer.getInputStream());
fromServerMessage=(User)streamFromServer.readObject();
streamToServer.flush();
vectorUserList1=(Vector)fromServerMessage.vectorUserList;
vectorUserList.setListData(vectorUserList1);
}catch(Exception ee){JOptionPane.showMessageDialog(null,"3");}
Thread thread = new Thread(this);
thread.start();
}
//建立連接并啟動監聽線程 public void run(){
try{
for(int t=1;;){
User commandFromServer=(User)streamFromServer.readObject();
String command=commandFromServer.Command;
if(command.equals("PublicChat")){
textArea2.append(commandFromServer.Name+" 對 大 家 說 :"+commandFromServer.Message);
}
if(command.equals("PrivateChat")){
textArea2.append(commandFromServer.Name+"對你說:"+commandFromServer.Message);
}
if(command.equals("add")||command.equals("lessen")){
textArea2.append(commandFromServer.Name+"對大家說:大家好!我來了");
vectorUserList.setListData(vectorUserList1);
}
if(command.equals("kick")){
lessen();
}
if(command.equals("SystemMessage")){
textArea2.append("系統消息:"+commandFromServer.Message);
}
JOptionPane.showMessageDialog(null,"用戶名不能為空!");t=0;
continue;
}
}catch(Exception e){}
}
//監聽線程對服務器信息的處理及響應
public void actionPerformed(ActionEvent e) {
if(e.getActionCommand().equals("公聊"))
sendPublicMessage();
if(e.getSource()==button2)
sendPraviteMessage();
if(e.getActionCommand().equals("注銷")){
lessen();
dispose();
try{
streamToServer.close();
streamFromServer.close();
ToServer.close();
}catch(Exception ee){}
new Login();
}
}
//對按鈕動作的處理及響應
public void sendPublicMessage(){ }
//發送公聊信息
public void sendPraviteMessage(){
}
//發送私聊信息
public void lessen(){
}
//注銷事件
服務端:
服務端序列化信息類:
class User implements Serializable {
String Name;//用戶名
String Password;//密碼
String Email;//e-mail
String Age;//年齡
String sex;// 性別
String Message;//要傳遞的信息
String Command; //命令標識
Vector vectorUserList;//在線用戶列表 } 服務器界面類:
public class Server extends JFrame
{ .
. . .
//組件及變量的定義 public Server()
{
initComponents();
//構造方法,初始化組件 }
private void initComponents()
{
//組件初始化
try
{
//建立 InetAddress 對象
InetAddress intel=InetAddress.getLocalHost();
String SerIp=intel.getHostAddress();
jLabel3.setText("服務器:"+SerIp);
}
catch(UnknownHostException e2)
{
System.out.println("發生錯誤!");
}
jPanel1.add(jLabel3);
jLabel5.setText("
0 個客戶");
jPanel1.add(jLabel5);
jList1.setModel(new AbstractListModel() {
String[] strings = {};
public int getSize() { return strings.length; }
public Object getElementAt(int i) { return strings[i]; }
});
jList1.setFont(new Font("Dialog",Font.BOLD | Font.ITALIC, 16));
jList1.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
jList1.addMouseListener(new MouseAdapter()
{
public void mousePressed(MouseEvent evt)
{
if (evt.getClickCount()==1)
{
BlackList=(String)jList1.getSelectedValue();
}
}
});
jScrollPane1.setViewportView(jList1);
jPanel1.add(jScrollPane1);
jPanel1.add(jLabel1);
getContentPane().add(jPanel1);
commandMenu.setText("選項");
msgMenuItem.setText("系統消息");
msgMenuItem.setBorder(null);
msgMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
msgMenuItemActionPerformed(evt);
}
});
commandMenu.add(msgMenuItem);
kickMenuItem.setText("踢人");
kickMenuItem.setBorder(null);
kickMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
kickMenuItemActionPerformed(evt);
}
});
commandMenu.add(kickMenuItem);
menuBar.add(commandMenu);
setJMenuBar(menuBar);
startServer();
pack(); }
private void msgMenuItemActionPerformed(ActionEvent evt)
//系統消息事件 {
try
{
User toUserMessage=new User();
String Mesage=JOptionPane.showInputDialog(null," 請 輸 入 內 容 :
"," 系 統 消 息",JOptionPane.INFORMATION_MESSAGE);
toUserMessage.Message="系統消息:"+Mesage+"\n";
toUserMessage.Command="SystemMessage";
for(int i=0;i<Server.vectorUserList.size();i++)
{
ObjectOutputStream streamToUser=(ObjectOutputStream)Server.vectorStreamToUser.elementAt(i);JOptionPane.showMessageDialog(null,"用戶名不能為空!4");
streamToUser.writeObject((User)toUserMessage);JOptionPane.showMessageDialog(null," 用 戶名不能為空!5");
streamToUser.flush();
}
}
catch(IOException e){}
}
private void kickMenuItemActionPerformed(ActionEvent evt)
//踢人事件 {
Object obj=evt.getSource();
try
{
if(obj==kickMenuItem)
{
BlackList=JOptionPane.showInputDialog(null," 請 輸 入 用 戶 名 :
"," 系 統 消 息",JOptionPane.INFORMATION_MESSAGE);
}
User toUserMessage=new User();
for(int i=0;i<Server.vectorUserList.size();i++)
{
if(BlackList.equals(Server.vectorUserList.elementAt(i)))
{
toUserMessage.Command="Kick";
toUserMessage.Message="系統消息:對不起!你已被踢出!\n";
}
else{
JOptionPane.showInputDialog(null,"無此用戶!");
}
ObjectOutputStream streamToUser=(ObjectOutputStream)Server.vectorStreamToUser.elementAt(i);JOptionPane.showMessageDialog(null,"用戶名不能為空!1");
streamToUser.writeObject((User)toUserMessage);JOptionPane.showMessageDialog(null," 用戶名不能為空!2");
streamToUser.flush();JOptionPane.showMessageDialog(null,"用戶名不能為空!3");
}
推薦訪問: 報告 課程設計 聊天室上一篇:數字信號處理實驗報告
下一篇:網絡工程設計實驗報告
同志們:今天這個大會,是市委全面落實黨要管黨、從嚴治黨要求的一項重大舉措,也是對縣市區委書記履行基層黨建工作第一責任人情況的一次集中檢閱,同時是對全市基層黨建工作的一次再部署、再落實的會議。前面,**
***年,我認真履行領班子、帶隊伍、抓黨員、保穩定的基層黨建工作思路,以學習貫徹習近平新時代中國特色社會主義思想和黨的十九大歷次全會精神為主線,以市局基層黨建工作考核細則為落腳點,落實全面從嚴治黨主體
根據會議安排,現將2022年履行抓基層黨建工作職責情況報告如下:一、履職工作特色和亮點1 突出政治建設,著力在思想認識上提高。牢固樹立抓黨建就是抓政績的理念,以“黨建工作抓引領、社區治理求突破,為民服
2022年以來,在**黨委的正確領導下,堅持以習近平新時代中國特色社會主義思想為指導,深入學習宣傳貫徹黨的二十大精神,以黨建工作為統領,扎實開展夯實“三個基本”活動,以“四化四力”行動為抓手,聚力創建
各位領導,同志們:根據會議安排,現就2022年度抓基層黨建工作情況匯報如下:一、主要做法及成效(一)強化政治引領。一是不斷強化理論武裝。堅持通過黨組會、中心組學習會和“三會一課”,第一時間、第一議題學
2022年度抓基層黨建工作述職報告按照黨委工作部署,現將本人2022年度抓基層黨建工作情況報告如下:一、2022年度抓基層黨建工作情況(一)旗幟鮮明講政治將旗幟鮮明講政治放在全局發展首要位置,積極開展
2022年,是我在數計系黨總支書記這個新崗位上度過的第一個完整的工作年度。回首一年來在校黨委的正確領導下,與數計系領導班子和全體師生共同走過的日子,艱辛歷歷在目,收獲溫潤心田。作為黨總支書記,我始終牢
按照考核要求,現將本人一年來,作為統戰部長履行職責、廉潔自律等方面情況報告如下:一、著眼增強政治素質,不斷深化理論學習堅持把旗幟鮮明講政治作為履職從政的第一位要求,帶領統戰系統干部堅決擁護“兩個確立”
**年,緊緊圍繞黨工委、管委會的決策部署,全體人員團結協作、凝心聚力,緊扣黨工委“**”基本工作思路,全力開拓進取,認真履職盡責,圓滿完成各項工作任務。一、個人思想政治狀況檸檬文苑www bgzjy
按照縣委關于開展抓基層黨建述職評議會議的有關要求,經請示縣委組織部同意,今天,我們在此召開2022年度基層黨組織書記抓基層黨建述職評議會議。1 首先,請**黨委書記,**同志述職。**黨委能夠主動研究