Vorher geschrieben:
Letztes Wochenende habe ich mir einige Zeit genommen, um das anfängliche Design und das detaillierte Design eines einfachen Socket-Chat-Programms aufzuzeichnen, das ich geschrieben habe. Schließlich wartete ich auf das Soft -Prüfungszertifikat, das ich vor dem Abschluss am Dienstag abgelegt habe, und verbrachte dann den Tag der Zeit. Heute war Freitag, und ich hatte vor, das detaillierte Design des Kunden und des gemeinsamen Moduls aufzuzeichnen, da ich ab diesem Wochenende mit anderen Dingen beschäftigt sein werde.
Design:
Das Kundendesign ist hauptsächlich in zwei Teile unterteilt, nämlich das Design des Sockel-Kommunikationsmoduls und das Design von UI.
Client Socket Communication Design:
Das Design hier ähnelt tatsächlich dem Design des Servers. Der Unterschied besteht darin, dass der Server Herzschlagpakete erhält, während der Client Herzschlagpakete sendet. Da der Client nur mit einem Server kommuniziert (die Kommunikation zwischen den Clients wird auch vom Server verteilt), wird nur ein Thread -Pool mit Größe 2 verwendet, um diese beiden Dinge zu verarbeiten (Newfixed Threadpool (2)). Die entsprechenden Verarbeitungsklassen werden empfohlen und Keepalivedog. Wenn der Empfänger initialisiert wird, wird ein Rückruf als Rückruf an den Client gesendet. Empfängt die Servernachricht. Die Standardimplementierung von Callback ist defaultCallback. DefaultCallback wird über HF nach verschiedenen Ereignissen an verschiedene Handler verteilt. Der Kundeninhaber speichert die aktuellen Kundeninformationen. Das Design lautet wie folgt:
Die spezifische Implementierung des Socket -Kommunikationsmoduls:
[Client.java]
Der Client ist der Eingang zum Client, um eine Verbindung zum Server herzustellen. Um einen Client zu erstellen, müssen Sie einen Rückruf als Rückruf angeben, wenn der Client die Servernachricht empfängt. Anschließend startet die Start () -Methode des Clients das Anhören des Servers (Empfangeneristener). Wenn der Empfänger die vom Server gesendeten Daten empfängt, wird die Callback (Callback) -Methode aufgerufen, um sie zu verarbeiten. Gleichzeitig muss der Client auch ein Herzschlagpaket senden, um den Server darüber zu informieren, dass er weiterhin mit dem Server verbunden ist. Das Herzschlagpaket wird vom Kunden aufbewahrt. Alive () wird von Keepalivivedog gestartet und implementiert; Diese beiden Schritte werden durch einen Thread -Pool von NeufixedThreadpool (2) mit einer festen Größe von 2 ausgeführt. Der spezifische Code des Clients ist wie folgt (die beiden anderen Methoden werden hier ausgesetzt, um den Socket und den Benutzer zu erhalten, zu dem der aktuelle Socket gehört):
/** * Client * @author yaolin * */public class Client {privater endgültiger Socket Socket; private Zeichenfolge von; privater Final Executorservice Pool; privater Abrufrückruf; öffentlicher Client (Callback Callback) löst IOException {this.socket = new Socket (ConstantValue.server_ip, ConstantValue.Server_port) aus; this.pool = Executors.NewFixedThreadpool (2); this.callback = callback; } public void start () {pool.execute (neuer Empfänger (Socket, Rückruf)); } public void keepalive (String von) {this.from = from; Pool.execute (neuer Keepalivivedog (Socket, From)); } public Socket Getocket () {return Socket; } public String getfrom () {return from; }}[Keepalivivedog.java]
Nachdem der Client eine Verbindung mit dem Server hergestellt hat (dieses Programm bezieht sich auf die erfolgreiche Anmeldung, da der Socket des Clients nach dem erfolgreichen Login vom Server verwaltet wird), ist es notwendig, ein Heartbeat -Paket jedes Mal an den Server zu senden, um dem Server immer noch in Kontakt mit dem Server in Kontakt zu sein. Der Code von Keepalivedog wird wie folgt implementiert (er kann später an NewsschonedThreadpool (1) angepasst werden, sodass der Code hier ebenfalls angepasst wird):
/*** KeepAlivivedog: Sagen Sie den Server mit, dass dieser Client ausgeführt wird. * * @author yaolin */public class keepalivedog implementiert runnable {privater endgültiger Socket Socket; private endgültige Zeichenfolge von; public keeTalivedog (Socket Socket, String von) {this.socket = Socket; this.from = from; } @Override public void run () {while (socket! = Null &&! Socket.isclosed ()) {try {printwriter out = new printwriter (socket.getOutputStream ()); Alivemessage message = new Alivemessage (); message.setfrom (von); out.println (json.tojson (message)); out.flush (); Thread.sleep (constantValue.keep_alive_period * 1000); } catch (Ausnahme e) {loggerutil.Error ("Client -Send -Nachricht fehlgeschlagen!" + e.getMessage (), e); }}}}[RecreenivInistener.java]
Die Start () -Methode des Clients startet das Hören auf den Server und wird vom Empfänger implementiert. Nachdem die Nachricht vom Server empfangen wurde, ruft der Empfänger die Methode des Rückrufbacks zurück, um den Rückruf die spezifische Geschäftslogik zu verarbeiten. Daher ist der Empfänger nur für das Anhören der Nachrichten auf dem Server verantwortlich, und die spezifische Verarbeitung wird per Callback behandelt. Es sollte hier erwähnt werden, dass, wenn der Nachrichtentyp ein Dateityp ist, das Ausführungsintervall für den Konfigurieren des Callback -Callbacks im Rahmen des Dateiflusses zum Server lesen kann, anstatt direkt die nächste Schleife einzugeben. Das Design hier ähnelt dem Server. Der spezifische Implementierungscode von Recivelistener ist wie folgt:
öffentliche Klasse Recorivelistener implementiert Runnable {private endgültige Socket Socket; privater Abrufrückruf; öffentlicher Empfänger (Socket Socket, Callback -Rückruf) {this.socket = Socket; this.callback = callback; } @Override public void run () {if (socket! = Null) {while (! SocTet.isclosed ()) {try {InputStream is = socket.getInputStream (); String line = null; StringBuffer sb = null; if (is.available ()> 0) {bufferedReader buf = new bufferedReader (neuer InputStreamReader (IS)); sb = new StringBuffer (); while (is.available ()> 0 && (line = bufr.readline ())! = null) {sb.append (line); } Loggerutil.trach ("empfangen [" + sb.toString () + "] at" + New Date ()); callback.dowork (Socket, sb.toString ()); Basemessage message = json.parseObject (sb.toString (), basemessage.class); if (message.gettType () == messagetype.file) {// Pause, um Datei loggerutil.trach zu empfangen ("Client: Pause, um Datei zu empfangen"); Thread.sleep (ConstantValue.Message_period); }} else {thread.sleep (constantValue.message_period); }} catch (Ausnahme e) {loggerutil.Error ("Client -Send -Nachricht fehlgeschlagen!" + e.getMessage (), e); }}}}}}}[Callback.java, defaultCallback.java]
Aus den oben genannten oben sehen wir, dass die Verarbeitung von Nachrichten durch den Client ein Rückruf von Callback ist und der Rückruf nur eine Schnittstelle ist. Alle Rückrufimplementierungen implementieren die Schnittstelle, um Nachrichten entsprechend ihren Anforderungen zu verarbeiten. Hier ist die Standardimplementierung von Callback defaultCallback. DefaultCallback verarbeitet nur drei Arten von Nachrichten, nämlich Chat -Nachrichten, Dateimeldungen und Rückgabenachrichten. Für Chat -Nachrichten wird DefaultCallback die entsprechende Schnittstelle über die Router -Route in der Benutzeroberfläche (siehe UI -Design finden Sie für Details) und dann die Nachricht im entsprechenden Chat -Feld an. Für Dateimeldungen schreibt DefaultCallback die Datei in den in der Konfiguration angegebenen Pfad (die Datei wird hier ohne die Erlaubnis des Benutzers empfangen. Dieses Design ist also nicht sehr freundlich, also vorerst). Für Rückgabenachrichten wird DefaultCallback gemäß dem Schlüssel in der Rückgabenachricht zu verschiedenen Handlern aufgerufen. Der spezifische Code lautet wie folgt:
public interface callback {public void dowork (Socket Server, Objektdaten); } public class defaultCallback implementiert Callback {@Override public void dowork (Socket -Server, Objektdaten) {if (data! Switch (message.gettType ()) {case messagetype.chat: HandlechatMessage (Daten); brechen; case MessAgetype.file: HandleFilemessage (Server, Daten); brechen; case messagetype.return: HandlereturnMessage (Daten); brechen; }}} private void HandlechatMessage (Objektdaten) {ChatMessage m = json.ParseObject (data.toString (), chatMessage.class); String tabkey = m.getfrom (); // von jComponent comp = router.getView (chatroomview.class) .getComponent (chatroomview.chattabbed); if (Comp Instanceof jtabbedpane) {jtabbedpane tab = (jtabbedpane) comp; int index = tab.indexoftab (Tabey); if (index == -1) {tab.addtab (Tabkey, ResultHolder.get (tabkey) .getScrollPane ()); } JTextArea textArea = resultHolder.get (Tabey) .GIETTEXTAREA (); textArea.setText (new StringBuffer () .Append (textArea.getText ()). append (System.lineseParator ()). Append (System.LineSeParator ()) .Append ("[") .Append (M.Getowner (). append ("]:") .Andend (). .ToString ()); // scrollen Sie in die untere textarea.setCaretposition (textArea.getText (). Länge ()); }} private void handleFileMessage (Socket -Server, Objektdaten) {FileMessage Message = json.ParseObject (Data.ToString (), fileMessage.class); if (message.getSize ()> 0) {outputStream os = null; try {if (server! = null) {inputStream is = server.getInputStream (); Datei Dir = new Datei (constantValue.client_receive_dir); if (! Dir.Exists ()) {dir.mkdirs (); } os = new FileOutputStream (neue Datei (pathutil.combination (constantValue.client_receive_dir, neues Datum (). GetTime () + message.getName ()))); int total = 0; while (! server.isclosed ()) {if (is.available ()> 0) {byte [] buff = new byte [constantValue.buff_size]; int len = -1; while (is.available ()> 0 && (len = is.read (buff))! = -1) {os.write (Buff, 0, len); Gesamt += Len; Loggerutil.debug ("empfangen Buff [" + len + "]"); } os.flush (); if (total> = message.getSize ()) {loggerutil.info ("empfangen Buff [OK]"); brechen; }}}}}} catch (Ausnahme E) {loggerutil.Error ("Datei fehlgeschlagen!" + e.getMessage (), e); } endlich {if (os! = null) {try {os.close (); } catch (Ausnahme ignorieren) {} os = null; }}}} private void HandlereturnMessage (Objektdaten) {returnMessage m = json.parseObject (data.toString (), returnMessage.class); if (stringutil.isnotEmpty (m.getkey ()) {switch (m.getkey ()) {case key.notify: // client benachrichtigen, um die USR -Liste HF.GetHandler (key.notify) .handle (Daten) zu aktualisieren; brechen; case key.login: hf.getHandler (key.login) .Handle (Daten); brechen; case key.register: hf.getHandler (key.register) .Handle (Daten); brechen; case key.listuser: hf.getHandler (key.listuser) .Handle (Daten); brechen; case key.tip: hf.getHandler (key.tip) .Handle (Daten); brechen; }}}}[Handler.java, Hf.java, ListUserhdl.java ...]
Die Handler -Komponente ist für die Verarbeitung von Nachrichten des Rückgabenachrichtentyps des Servers verantwortlich. DefaultCallback verteilt Nachrichten nach verschiedenen Schlüssel an verschiedene Handler. Dies ist auch eine einfache Fabrikkomponente. Es ähnelt den vom Server empfangenen Daten. Das vollständige Klassendiagramm lautet wie folgt:
Der Code für diesen Abschnitt ist unten angegeben. Um den Raum zu reduzieren, wird der gesamte von Handler implementierte Code gesammelt.
public interface Handler {public Object Handle (Objekt obj); } public class hf {public static Handler Gethandler (String Key) {Switch (Key) {case key.notify: return New NotifyHdl (); case key.login: return New LoginHdl (); Fallschlüssel.register: Neue RegisterHDL () zurückgeben; case key.listuser: Neue ListUserHdl () zurückgeben; case key.tip: Neue tiHdl () zurückgeben; } return null; }} öffentliche Klasse ListUserHDL implementiert Handler {@Override public Object Handle (Objekt obj) {if (obj! if (rm.issuccess () && rm.getContent ()! JComponent comp = router.getView (chatroomview.class) .getComponent (chatroomview.listusrlist); if (compinformof jlist) {@SuppressWarnings ("deaktiviert") // jlist <string> listusrlist = (jlist <string>) comp; List <String> listUser = new LinkedList <String> (); listUser.addall (dto.getListUser ()); Collections.sort (ListUser); listUser.add (0, ConstantValue.to_all); listUSrlist.setListData (listUser.toArray (neuer String [] {})); }}} catch (Ausnahme e) {loggerutil.Error ("Handle ListUSR fehlgeschlagen!" + e.getMessage (), e); }} return null; }} öffentliche Klasse loginhdl implementiert Handler {@Override public Object Handle (Objekt obj) {if (obj! = null) {try {returnMessage rm = json.ParseObject (obj.toString (), returnMessage.class); if (rm.issuccess ()) {Router.getView (RegisterAndloginView.class) .Trash (); Router.getView (chatroomview.class) .create (). Display (); ClientHolder.getClient (). Keepalive (rm.getto ()); // keep ...} else {container container = router.getView (RegisterandLoginView.class) .Container (); if (container! }}} catch (Ausnahme E) {loggerutil.Error ("Handle Anmeldung fehlgeschlagen!" + e.getMessage (), e); }} return null; }} öffentliche Klasse NotifyHdl implementiert Handler {@Override public Object Handle (Objekt obj) {if (obj! = null) {try {returnMessage rm = json.ParseObject (obj.toString (), returnMessage.class); if (rm.issuccess () && rm.getContent ()! JComponent comp = router.getView (chatroomview.class) .getComponent (chatroomview.listusrlist); if (compinformof jlist) {@SuppressWarnings ("deaktiviert") // jlist <string> listusrlist = (jlist <string>) comp; List <string> listUser = modeltolist (listUSrlist.getModel ()); if (dto.isflag ()) {if (! listUser.contains (dto.getUnername ())) {listUser.add (dto.getUnername ()); listUser.remove (constantValue.to_all); Collections.sort (ListUser); listUser.add (0, ConstantValue.to_all); }} else {listUser.remove (dto.getUnername ()); } listUSrlist.setListData (listUser.toArray (neuer String [] {})); }}} catch (Ausnahme E) {loggerutil.Error ("Handle -NoFity fehlgeschlagen!" + e.getMessage (), e); }} return null; } private list <string> modeltolist (listModel <string> listModel) {list <string> list = new LinkedList <string> (); if (listModel! }} Rückgabeliste; }} public class RegisterHdl implementiert Handler {@Override public Object Handle (Objekt obj) {if (obj! Container container = router.getView (RegisterAndloginView.Class) .Container (); if (container! } else {joptionpane.showMessagedialog (Container, rm.getMessage ()); }}} catch (Ausnahme e) {loggerutil.Error ("Handle Register fehlgeschlagen!" + e.getMessage (), e); }} return null; }} öffentliche Klasse TIPHDL implementiert Handler {@Override public Object Handle (Objekt obj) {if (obj! if (M.ISSUCCESS () && m.getContent ()! = null) {String tabkey = M.GetFrom (); String tip = M.GetContent (). ToString (); JComponent comp = router.getView (chatroomview.class) .getComponent (chatroomview.chattabbed); if (Comp Instanceof jtabbedpane) {jtabbedpane tab = (jtabbedpane) comp; int index = tab.indexoftab (Tabey); if (index == -1) {tab.addtab (Tabkey, ResultHolder.get (tabkey) .getScrollPane ()); } JTextArea textArea = resultHolder.get (Tabey) .GIETTEXTAREA (); textArea.setText (new StringBuffer () .Append (textArea.getText ()). append (system.lineseParator ()). append (System.lineseParator ()) .Append ("[") .Append (M.Getowner (). append ("]. // scrollen Sie in die untere textarea.setCaretposition (textArea.getText (). Länge ()); }}} catch (Ausnahme e) {loggerutil.Error ("Handle Tipp fehlgeschlagen!" + e.getMessage (), e); }} return null; }} Es gibt eine andere Klasse für das Socket -Kommunikationsmodul, dh der Clientinhaber, der zum Speichern des aktuellen Clients verwendet wird, der dem Sockholder auf dem Server ähnelt.
/** * @author yaolin */Public Class ClientHolder {public static Client Client; public static client getClient () {return client; } public static void setClient (Client Client) {clientHolder.client = client; }}Spezifische Implementierung des UI -Moduls:
Das obige Aufzeichnung des Designs des Socket -Kommunikationsmoduls. Als nächstes nehme ich das Designmodul der Benutzeroberfläche auf. Ich habe nicht vor, die Benutzeroberfläche alleine zu schreiben. Schließlich ist das Schreiben zu hässlich, also kann ich Klassenkameraden oder Freunde bitten, mir zu helfen, es später zu klopfen. Daher übergeben ich die UI -Ereignisverarbeitung der Aktion, um sie zu verarbeiten, und trennen einfach die UI -Design- und Ereignisantwort. Alle UIS erben JFrame und implementieren die Ansichtsschnittstelle. Die obige Handler -Implementierungsklasse wird über Router erhalten (sie wird direkt zurückgegeben, wenn sie existiert, und wird erstellt und gespeichert, wenn es nicht existiert). Die Ansicht liefert die UI -Erstellung (), den Container () erhalten, die Komponenten in der UI getComponent (), Display Display () und recycelner Müll () erhalten. Ergebniswrapper und Resultholder dienen nur zum Erstellen und Speichern von Chat -Registerkarten. Das Design lautet wie folgt:
[Router.java, View.java]
Alle UIS erben JFrame und implementieren die Ansichtsschnittstelle. Die Handler -Implementierungsklasse erhält die angegebene Benutzeroberfläche über Router (sie wird direkt zurückgegeben, wenn sie existiert, und erstellt und speichert, wenn sie nicht existiert). Die Ansicht liefert die UI -Erstellung (), erhält Container () und erhält die Komponenten in der UI getComponent (), Anzeige Display () und recycelt truash (). Die spezifische Implementierung ist wie folgt:
/*** Route anzeigen* @author yaolin*/public class Router {private statische Karte <String, Ansicht> listroute = new Hashmap <String, Ansicht> (); public static View GetView (Klasse <?> clazz) {view v = listroute.get (clazz.getName ()); if (v == null) {try {v = (view) class.forname (clazz.getName ()). newInstance (); listroute.put (clazz.getName (), v); } catch (Ausnahme e) {loggerutil.Error ("Ansicht fehlgeschlagen!" + e.getMessage (), e); }} return v; }} /** * Kanonische Schnittstellen für alle Schnittstellen * @author yaolin * */public interface View {/** * */public View create (); / ** * */ öffentlicher Container Container (); / ** * @param key */ public JComponent getComponent (String Key); / ** * */ public void display (); / ** * */ public void truash (); }[RegisterandLoginView.java, Chatroomview.java]
Da ich die Benutzeroberfläche nicht alleine schreiben möchte, habe ich hier einfach zwei UI -Schnittstellen geschrieben, nämlich die Registrierung und Anmeldestelle und die Chat -Schnittstelle. Hier sind zwei hässliche Schnittstellen:
Registrieren Sie die Anmeldeschnittstelle
Chat -Schnittstelle
Im Folgenden finden Sie die spezifischen Codes für diese beiden Schnittstellen:
/*** Register und Login* @author yaolin*/public class RegisterandLoginView erweitert JFrame Implements View {private statische endgültige lange Serialversionuid = 63220888074312546736L; private endgültige Register und loginaction action = new RegisterandLoginaction (); privat statischer boolean create = false; @Override public view create () {if (! Create) {init (); Create = true; } zurückgeben; } public container container () {create (); return getContentPane (); } @Override public JComponent getComponent (String Key) {return null; } @Override public void display () {setVisible (true); } @Override public void tRash () {dispose (); } private void init () {// AttributsetSize (500, 300); setResizable (falsch); setLocationRelativeto (null); // Container jpanel panel = new Jpanel (); panel.setLayout (null); // Komponente // Benutzername jlabel lbusername = new JLabel (i18n.text_username); lbusername.setBounds (100, 80, 200, 30); Final JTextField tfusername = new JTextField (); tfusername.setBounds (150, 80, 230, 30); panel.Add (lbusername); panel.Add (tfusername); // Passwort jLabel lbpassword = new JLabel (i18n.text_password); lbpassword.setBounds (100, 120, 200, 30); Final JPasswordfield pfpassword = new Jpasswordfield (); pFpassword.setBounds (150, 120, 230, 30); panel.Add (lbpassword); Panel.Add (PfPassword); // btnregister Jbutton btnregister = new Jbutton (i18n.btn_register); btnregister.setBounds (100, 175, 80, 30); // BtnLogin Final Jbutton btnlogin = new Jbutton (i18n.btn_login); Btnlogin.SetBounds (200, 175, 80, 30); // btncancel Jbutton btnexit = new Jbutton (i18n.btn_exit); btnexit.setBounds (300, 175, 80, 30); panel.Add (btnregister); panel.Add (Btnlogin); panel.Add (btnexit); // Ereignis pfpassword.addKeyListener (neuer KeyAdapter () {public void keypressed (endgültig keyEvent e) {if (e.getKeyCode () == keyEvent.vk_enter) btnlogin.doclick (); actionPerformed (endgültiger ActionEvent e) {if (Stringutil.isempty (tfusername.getText ()) || StringUtil.isempty (neuer String (pfpassword.getPassword ()) {joptionpane.showmessagedialog (GetContentPane (), I18N.info_Register_Data); action.Handleregister (tfusername.getText (), new String (pFpassword.getPassword ()); StringUtil.isEmpty (neuer String (pfpassword.getPassword ()) {joptionpane.showMessagedialog (getContentPane (), I18N.info_login_Empty_data); }); // Ende von AddActionListener btNexit.AddactionListener (new ActionListener () {public void actionPerformed (endgültige actionEvent e) {System.exit (0); }}); // Ende von AddActionListener getContentPane (). add (panel); setDefaultCloseOperation (jframe.exit_on_close); }} /** * Client -Chat -Fenster * * @author yaolin */Public Class Chatroomview erweitert JFrame Implements View {private statische endgültige long serialversionuid = -451583117289054818l; public static final String listUSrlist = "ListUSrList"; public static Final String Chattabbed = "Chatzabbed"; privat statischer boolean create = false; private chatroomaction action = new ChatroomAction (); private jlist <string> listUSrlist = null; private jtabbedpane chattabbed = null; @Override public view create () {if (! Create) {init (); Create = true; } zurückgeben; } public container container () {create (); return getContentPane (); } @Override public JComponent getComponent (String Key) {create (); Switch (Schlüssel) {case ListUSRLIST: Return ListUSRLIST; Case Chattabbed: Rückkehr in Chatzabbed; } return null; } @Override public void display () {setVisible (true); } @Override public void tRash () {dispose (); } public void init () {settitle (i18n.text_app_name); SetSize (800, 600); setResizable (falsch); setLocationRelativeto (null); setLayout (neuer BorderLayout ()); add (createChatpanel (), BorderLayout.Center); add (createSrlistView (), borderLayout.east); setDefaultCloseOperation (jframe.exit_on_close); } private jComponent createChatpanel () {// Dateiauswahl endgültig jFilechoser filechooser = new JFilechoOser (); JPanel Panel = new Jpanel (new BorderLayout ()); // Center Chattabbed = new JtabbedPane (); chattabbed.addtab (constantValue.to_all, resultholder.get (constantValue.to_all) .getScrollpane ()); panel.Add (chattabbed, borderLayout.Center); // South Jpanel South = New Jpanel (New BorderLayout ()); // South - Datei JPanel Middle = new JPanel (New BorderLayout ()); Middle.Add (New Jlabel (), BorderLayout.Center); // nur für die Polsterung jbutton btnUpload = new Jbutton (i18n.btn_send_file); Middle.Add (BtnUpload, BorderLayout.East); South.Add (Middle, BorderLayout.North); // South - textArea endgültig jtextArea tasend = new JTextArea (); tasend.setCaretcolor (color.blue); Tasend.Setmargin (neue Einfügungen (10, 10, 10, 10)); tasend.setRows (10); South.Add (Tasend, BorderLayout.Center); // South - Btn Jpanel booth = new Jpanel (new BorderLayout ()); boden.add (new Jlabel (), borderLayout.Center); // nur für die Polsterung jbutton btnsend = new Jbutton (i18n.btn_send); boden.add (btnsend, borderLayout.east); South.Add (unten, BorderLayout.South); btnupload.addactionListener (new ActionListener () {public void actionPerformed (endgültig ActionEvent e) {if (! constantValue.to_all.equals (chattabbed.gettitleat (chattabbed.GetAnteisedIndex ()) {int returnval = fileChoser.ShowoShopend. JFILECHOOSER.Approve_Option) {Datei Datei = filechoser.getSelectedFile (); }}}}); btnsend.addactionListener (new actionListener () {public void actionPerformed (endgültig actionEvent e) {if (stringutil.isnotempy (tasend.getteText ()) {action.send.send (chattabbed. }}}); Panel.Add (South, BorderLayout.South); Rückgabepanel; } private jComponent createUSrListView () {listUSrlist = new jlist <string> (); listUSrlist.setBorder (neuer Lineborder (color.Blue)); listUSrlist.setListData (neuer String [] {constantValue.to_all}); listUSrlist.setFixedCellWidth (200); listUSrlist.setFixedCellHeight (30); ListUSrlist.AddlistSelectionListener (neue listSelectionListener () {@Override public void Valuechanged (listSelectionEvent e) {// Chat mit if (chattabbed.Indexoftab (listUSrlist.getSelectedValue) == -1 && listusrlist.getSelectedValue ()! ! ListUSrlist.getSelectedValue (). Equals (ClientHolder.getClient (). getfrom ())) {chattabbed.addtab (listusrlist.getSelectedValue (), resultHolder.get (listUSrlist.getSelectedValue ()). GetCrollpane ()); chattabbed.setSelectedIndex (chattabbed.Indexoftab (ListUSrlist.GetSelectedValue ()); return listUsrlist; }}[RegisterandLoginaction.java, ChatroomAction.java]
Hier wird die UI -Ereignisverarbeitung durch Aktion behandelt, die einfach die UI -Design- und Ereignisreaktion trennt. Die Ereignisse des RegisterandLoginView werden von RegisterandLoginaction behandelt, und die Ereignisse des Chatroomviews werden von ChatroomAction behandelt. Die spezifische Implementierung ist wie folgt:
public class RegisterandLoginaction {public void HandleGister (String -Benutzername, String -Passwort) {if (stringutil.isempty (Benutzername) || StringUtil.isempty (Passwort)) {return; } RegisterMessage Message = new RegisterMessage () .SetUnername (Benutzername) .SetPassword (Passwort); Message.SetFrom (Benutzername); Sendhelper.send (ClientHolder.getClient (). Getocket (), Nachricht); } public void Handlelogin (String -Benutzername, String -Passwort) {if (stringutil.isempty (Benutzername) || Stringutil.isempty (Passwort)) {return; } LoginMessage message = new LoginMessage () .SetUnername (Benutzername) .SetPassword (Passwort); Message.SetFrom (Benutzername); Sendhelper.send (ClientHolder.getClient (). Getocket (), Nachricht); }} Es gibt zwei weitere Klassen für UI -Design, nämlich Resultholder und Ergebniswrapper. Ergebniswrapper und Resultholder dienen nur zum Erstellen und Speichern von Chat -Registerkarten. Die spezifische Implementierung ist wie folgt:
public class resultWrapper {private jScrollPane Scrollpane; private jtextarea textarea; public resultWrapper (JscrollPane Scrollpane, jtextArea textarea) {this.scrollpane = scrollpane; this.textarea = textArea; } public JScrollPane GetCrollPane () {return scrollpane; } public void setScrollPane (jScrollpane scrollpane) {this.scrollpane = scrollpane; } public jTextArea getTextArea () {return textArea; } public void setTextArea (jTextArea textarea) {this.textarea = textArea; }} public class ResultHolder {private statische Karte <String, resultWrapper> listresultwrapper = new HashMap <String, resultWrapper> (); public static void put (Stringschlüssel, Ergebniswrapper -Wrapper) {listresultwrapper.put (Schlüssel, Wrapper); } public static resultWrapper get (String -Schlüssel) {resultwrapper wrapper = listresultwrapper.get (Key); if (Wrapper == null) {Wraper = create (); Put (Schlüssel, Wrapper); } return Wrapper; } private static resultWrapper create () {jTextArea resultTextArea = new jTextArea (); resultTextArea.SetedEble (false); resultTextArea.setBorder (neuer Lineborder (color.Blue)); JScrollPane scrollpane = new JScrollPane (resultTextArea); scrollpane.sethorizontalscrollbarpolicy (ScrollPaneConstants.Horizontal_ScrollBar_Never); scrollpane.setverticalScrollBarpolicy (ScrollPaneConstants.vertical_ScrollBar_as_Needed); Resultwrapper wrapper = neuer resultwrapper (scrollpane, resultTextarea); Wrapper zurückkehren; }} Der letzte ist gegeben, der Eintrag, auf den der Kunde ausführt:
/** * * @author yaolin * */public class niloaychat {public static void main (String [] args) {view v = router.getView (Register undLoginView.class) .Create (); try {v.display (); Client Client = new client (new defaultCallback ()); Client.Start (); ClientHolder.SetClient (Client); } catch (ioException e) {joptionpane.showMessagedialog (v.Container (), e.getMessage ()); }}} Demo -Download -Adresse: Demo
Das obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, es wird für das Lernen aller hilfreich sein und ich hoffe, jeder wird Wulin.com mehr unterstützen.