測試的時候要把所有的代碼放在同壹個項目下,因為客戶端可以對服務器使用同壹個POJO,裏面有壹些包錯誤,刪除就好了。
服務器代碼,即服務器門戶程序:
導入Java . io . buffered reader;
導入Java . io . file;
導入Java . io . io exception;
導入Java . io . inputstreamreader;
導入Java . io . object output stream;
導入Java . io . printwriter;
導入Java . net . server socket;
導入Java . net . socket;
導入Java . util . date;
導入Java . util . hashset;
公共類聊天室服務器{
私有服務器套接字ss;
私有HashSet & ltSocket & gtallSockets
private UserDao dao
公共聊天室服務器(){
嘗試{
ss =新服務器套接字(9999);
allSockets = new HashSet & ltSocket & gt();
Dao = new UserDaoForTextFile(new File(" d:/stu/user . txt "));
} catch (IOException e) {
e . printstacktrace();
}
}
public void startService()拋出IOException{
while(true){
socket s = ss . accept();
allSockets.add
新的ChatRoomServerThread。start();
}
}
類ChatRoomServerThread擴展線程{
私有套接字s;
公共聊天室服務器線程(套接字){
this.s = s
}
公共無效運行(){
//1,獲取Socket的輸入流並打包。
//2、從輸入流中循環讀取壹行數據。
//3、每讀取壹行數據,判斷該行是否為退出命令?
//4,如果是退出命令,從集合中刪除當前套接字,關閉當前套接字,跳出循環。
//5,如果不是退出命令,那麽轉發model.getCurrentUser()的註銷信息。getName()發送給所有在線客戶端。
//循環通過allSockets集合獲取每個套接字的輸出流,並將消息寫入流中。
BufferedReader br = null
String str = null
嘗試{
br =新的BufferedReader(新的InputStreamReader
。getInputStream()));
while((str=br.readLine())!=null ){
if(str . index of(" % EXIT % " = = 0){
allSockets.remove
//向其他客戶端發送XXX退出消息。
sendmessage toall client(str . split(":)[1]+"離開聊天室!");
s . close();
打破;
} else if(str . index of(" % log in % " = = 0){
string userName = str . split(":)[1];
string password = str . split(":)[2];
User user=dao.getUser(用戶名,密碼);
object output stream OOS = new object output stream(s . get output stream());
oos.writeObject(用戶);
OOS . flush();
如果(用戶!=null){
sendmessagetoallclient(user . getname()+"進入聊天室!");
}
str = null
}
if(str!=null){
sendMessageToAllClient(str);
}
}
} catch(異常e) {
e . printstacktrace();
}
}
公共void sendMessageToAllClient(字符串消息)引發IOException{
Date Date = new Date();
system . out . println(s . getine address()+":"+message+" \ t["+date+"]");
for(套接字溫度:所有套接字){
PrintWriter pw = new PrintWriter(temps . get output stream());
pw . println(message+" \ t["+date+"]");
pw . flush();
}
}
}
公共靜態void main(String[] args) {
嘗試{
新聊天室服務器()。startService();
} catch (IOException e) {
e . printstacktrace();
}
}
}
客戶代碼:
***總共4個:
1:進入程序:
公共類聊天室客戶端{
私有ClientModel模型;
公共聊天室客戶端(){
//String hostName = joptionpane . showinputdialog(null,
//"請輸入服務器主機名:");
// String portName = JOptionPane
// .showInputDialog(null,“請輸入端口號:“);
//固定服務器IP和端口
model = new client model(" 127 . 0 . 0 . 1 ",integer . parse int(" 9999 "));
model . create socket();
新的LoginFrame(模型)。show me();
}
公共靜態void main(String[] args) {
new chatroom client();
}
}
2.登錄後顯示界面:
導入Java . awt . borderlayout;
導入Java . awt . event . action event;
導入Java . awt . event . action listener;
導入Java . awt . event . window adapter;
導入Java . awt . event . window event;
導入Java . io . buffered reader;
導入Java . io . io exception;
導入Java . io . printwriter;
導入javax . swing . jbutton;
導入javax . swing . jframe;
導入javax . swing . jlabel;
導入javax . swing . joptionpane;
導入javax . swing . jpanel;
導入javax . swing . jscrollpane;
導入javax . swing . jtextarea;
導入javax . swing . jtextfield;
公共類ClientMainFrame擴展JFrame{
私有JTextArea區域;
私有JTextField字段;
私有JLabel標簽;
私有JButton按鈕;
私有ClientModel模型;
公共客戶端主機(){
超級("聊天室客戶端v 1.0 ");
area=new JTextArea(20,40);
field = new JTextField(25);
button = new JButton(" send ");
label = new JLabel();
JScrollPane JSP = new JScrollPane(area);
this.add(jsp,BorderLayout。中心);
JPanel panel = new JPanel();
panel.add(標簽);
panel.add(字段);
panel.add(按鈕);
this.add(panel,BorderLayout。南);
add eventhandler();
}
公共客戶端大型機(ClientModel模型){
this();
this.model = model
label . settext(model . getcurrentuser()。getName());
}
public void addEventHandler(){
action listener lis = new SendEventListener();
button . addactionlistener(lis);
field . addactionlistener(lis);
this . addwindowlistener(new window adapter(){
public void window closing(window event arg 0){
Intop = jooptionpane。showconfirmdiary (null,“您確定要退出聊天室嗎?”,“確認退出”,JOptionPane。YES _ NO _ OPTION);
if(op==JOptionPane。是_選項){
PrintWriter pw = model . get output stream();
if(model.getCurrentUser()。getName()!=null){
pw . println(" % EXIT % "+model . getcurrentuser()。getName());
pw . flush();
}
嘗試{
thread . sleep(200);
} catch(異常e) {
}
system . exit(0);
}
}
});
}
public void showMe(){
this . pack();
this . set visible(true);
this.setLocation(300,300);
this . setdefaultcloseoperation(JFrame。什麽都不做(ON CLOSE);
新的ReadMessageThread()。start();
}
類SendEventListener實現ActionListener{
public void action performed(action event e){
String str=field.getText()。trim();
if(str . equals(" "){
Joptionpane。showmessagedialog (null,“不能發送空消息!”);
返回;
}
PrintWriter pw = model . get output stream();
pw . println(model . getcurrentuser()。getName()+":"+str);
pw . flush();
field . settext(" ");
}
}
類ReadMessageThread擴展線程{
公共無效運行(){
while(true){
嘗試{
buffered reader br = model . getinputstream();
string str = br . readline();
area . append(str+" \ n ");
} catch (IOException e) {
}
}
}
}
}
3.登錄界面:
導入Java . awt . color;
導入Java . awt . dimension;
導入Java . awt . font;
導入Java . awt . point;
導入Java . awt . rectangle;
導入Java . awt . event . action event;
導入Java . awt . event . action listener;
導入Java . awt . event . window adapter;
導入Java . awt . event . window event;
導入Java . io . io exception;
導入Java . io . inputstream;
導入Java . io . objectinputstream;
導入Java . io . printwriter;
導入javax . swing . jbutton;
導入javax . swing . jframe;
導入javax . swing . jlabel;
導入javax . swing . joptionpane;
導入javax . swing . jpanel;
導入javax . swing . jpasswordfield;
導入javax . swing . jtextfield;
公共類LoginFrame擴展JFrame {
private static final long serialVersionUID = 1L;
private JPanel jContentPane = null;
private JLabel lab 1 = null;
private JLabel lab2 = null
private JLabel lab3 = null
private JTextField username field = null;
private JPasswordField password field = null;
private JButton log in button = null;
private JButton register button = null;
private JButton cancel button = null;
private ClientModel模型= null
/**
*此方法初始化userNameField
*
* @return javax.swing.JTextField
*/
private JTextField get username field(){
if (userNameField == null) {
username field = new JTextField();
userNameField.setSize(新維度(171,33));
userNameField.setFont(新字體("對話框",字體。平原,18));
userNameField.setLocation(新點(140,70));
}
返回用戶名字段;
}
/**
*此方法初始化passwordField
*
* @ return javax . swing . jpasswordfield
*/
private JPasswordField getPasswordField(){
if (passwordField == null) {
password field = new JPasswordField();
passwordField.setSize(新維度(173,30));
passwordField.setFont(新字體("對話框",字體。平原,18));
passwordField.setLocation(新點(140,110));
}
返回passwordField
}
/**
*此方法初始化loginButton
*
* @return javax.swing.JButton
*/
私有JButton getLoginButton() {
if (loginButton == null) {
log in button = new JButton();
loginButton.setLocation(新點(25,180));
log in button . settext(" log in ");
loginButton.setSize(新維度(75,30));
}
返回登錄按鈕;
}
/**
*此方法初始化cancelButton
*
* @return javax.swing.JButton
*/
私有JButton getCancelButton() {
if (cancelButton == null) {
cancel button = new JButton();
cancelButton.setLocation(新點(270,180));
cancel button . settext(" cancel ");
cancelButton.setSize(新維度(75,30));
}
返回取消按鈕;
}
/**
*顯示接口的方法,其中調用addEventHandler()方法向組件添加事件偵聽器。
*
*/
public void showMe(){
this . setdefaultcloseoperation(JFrame。什麽都不做(ON CLOSE);
this . set visible(true);
this.setLocation(300,200);
add eventhandler();
}
/**
*此方法用於向組件添加事件監聽。
*
*/
public void addEventHandler(){
action listener log in listener = new LoginEventListener();
log in button . addactionlistener(log in listener);
password field . addactionlistener(log in listener);
cancel button . addactionlistener(new action listener(){
public void action performed(action event e){
嘗試{
model.getSocket()。close();
} catch (IOException e1) {
e 1 . printstacktrace();
}
system . exit(0);
}
});
this . addwindowlistener(new window adapter(){
public void window closing(window event arg 0){
嘗試{
model.getSocket()。close();
} catch (IOException e1) {
e 1 . printstacktrace();
}
system . exit(0);
}
});
}
/**
*這個內部類用於監控登錄事件。
* @作者管理員
*
*/
LoginEventListener類實現ActionListener{
public void action performed(action event e){
//?登錄代碼
//1,判斷用戶名和密碼是否為空。
//2,從clientmodel,PrintWriter獲取輸出流。
//3、向服務器發送登錄請求。
//pw . println(" % log in %:userName:password ");
//4,從socket獲取對象輸入流,從流中讀取壹個對象。
//5.如果讀取的對象為空,則顯示登錄失敗消息。
//6,如果讀取的對象不為空,則將其轉換為用戶對象,並將。
//將clientmodel的currentUser對象設置為此對象。
//7、銷毀當前窗口,打開主界面窗口。
字符串userName = userName field . gettext();
char[]c = password field . get password();
string password = string . value of(c);
if(userName = = null | | userName . equals(" "){
joptionpane . showmessagedialog(null,“用戶名不能為空”);
返回;
}
if(password = = null | | password . equals(" "){
joptionpane . showmessagedialog(null,“密碼名不能為空”);
返回;
}
PrintWriter pw = model . get output stream();
pw . println(" % log in % "+userName+":"+password);
pw . flush();
嘗試{
InputStream is = model.getSocket()。getInputStream();
system . out . println(" is "+is . getclass());
ObjectInputStream ois =新的ObjectInputStream(is);
object obj = ois . read object();
if(obj!= null){
用戶user =(用戶)obj
如果(用戶!= null){
model.setCurrentUser(用戶);
log in frame . this . dispose();
新的客戶端主機(型號)。show me();
}
}
否則{
Joptionpane。顯示消息對話框(空,“用戶名或密碼錯誤,請重新輸入”);
username field . settext(" ");
password field . settext(" ");
返回;
}
} catch(異常e1) {
e 1 . printstacktrace();
}
}
}
公共靜態void main(String[] args) {
新的LoginFrame()。show me();
}
/**
*這是默認的構造函數
*/
公共LoginFrame(ClientModel模型){
this();
this.model = model
}
公共LoginFrame(){
super();
initialize();
}
public ClientModel getModel() {
退貨模式;
}
public void set model(client model model){
this.model = model
}
/**
*此方法初始化此
*
* @返回void
*/
私有void initialize() {
this.setSize(362,267);
this . setcontentpane(getJContentPane());
This.setTitle("達內聊天室-用戶登錄");
}
/**
*此方法初始化jContentPane
*
* @return javax.swing.JPanel
*/
私有JPanel getJContentPane() {
if (jContentPane == null) {
lab 3 = new JLabel();
Lab3.setText("秘密代碼:");
lab3.setSize(新維度(80,30));
lab3.setFont(新字體(“對話框”,字體。粗體,18));
lab3.setLocation(新點(50,110));
lab 2 = new JLabel();
Lab2.setText("用戶名:");
lab2.setSize(新維度(80,30));
lab 2 . settooltiptext(" ");
lab2.setFont(新字體(“對話框”,字體。粗體,18));
lab2.setLocation(新點(50,70));
lab 1 = new JLabel();
lab1.setBounds(新矩形(54,12,245,43));
lab1.setFont(新字體(“對話框”,字體。粗體,24));
lab1.setForeground(新顏色(0,0,204));
Lab1.setText("聊天室-用戶登錄");
jContentPane = new JPanel();
jcontentpane . set layout(null);
jContentPane.add(lab1,null);
jContentPane.add(lab2,null);
jContentPane.add(lab3,null);
jcontentpane . add(get username field(),null);
jcontentpane . add(getPasswordField(),null);
jcontentpane . add(getLoginButton(),null);
jcontentpane . add(getCancelButton(),null);
}
返回jContentPane
}
}
4.客戶端管理套接字類
導入Java . io . buffered reader;
導入Java . io . io exception;
導入Java . io . inputstreamreader;
導入Java . io . printwriter;
導入Java . net . socket;
/**
*該類定義了客戶端的全局參數,如套接字、當前用戶、流對象等。
*
*/
公共類ClientModel {
私用插座插座;
私人用戶currentUser
private BufferedReader br
私人版畫家pw;
私有字符串主機名;
專用int端口;
公共套接字getSocket() {
返回插座;
}
public ClientModel(字符串主機名,int端口){
super();
this.hostName = hostName
this.port = port
}
公共用戶getCurrentUser() {
返回currentUser
}
public void setCurrentUser(User currentUser){
this . current user = current user;
}
公共同步套接字createSocket(){
if(socket==null){
嘗試{
socket =新套接字(主機名,端口);
}catch (IOException e) {
e . printstacktrace();
返回null
}
}
返回插座;
}
public synchronized buffered reader getInputStream(){
if (br==null) {
嘗試{
br =新的BufferedReader(新的InputStreamReader(套接字
。getInputStream()));
} catch (IOException e) {
e . printstacktrace();
返回null
}
}
返回br;
}
公共同步PrintWriter getOutputStream(){
if (pw==null) {
嘗試{
pw = new PrintWriter(socket . get output stream());
} catch (IOException e) {
e . printstacktrace();
返回null
}
}
返回pw;
}
公共同步void closeSocket(){
如果(插座!=null){
嘗試{
br . close();
pw . close();
socket . close();
} catch (IOException e) {
e . printstacktrace();
}
}
socket = null
br = null
pw = null
}
}
以下是工具和POJO類:
用戶類別:
導入Java . io . serializable;
公共類用戶實現可序列化{
private static final long serial version uid = 1986 l;
private int id
私有字符串名稱;
私有字符串密碼;
私人字符串電子郵件;
公共用戶(){}
公共用戶(字符串名稱、字符串密碼、字符串電子郵件){
super();
this.name = name
this.password =密碼;
this.email = email
}
公共用戶(字符串名稱、字符串密碼){
super();
this.name = name
this.password =密碼;
}
public int getId() {
返回id;
}
public void setId(int id) {
this.id = id
}
公共字符串getName() {
返回名稱;
}
public void setName(字符串名){
this.name = name
}
公共字符串getPassword() {
返回密碼;
}
public void setPassword(字符串密碼){
this.password =密碼;
}
公共字符串getEmail() {
回復郵件;
}
public void setEmail(字符串電子郵件){
this.email = email
}
公共字符串toString(){
返回id+":"+姓名+":"+密碼+":"+電子郵件;
}
}
DAO,用於在本地讀取配置文件。
界面:
公共接口UserDao {
public boolean addUser(用戶User);
公共用戶getUser(字符串用戶名,字符串密碼);
}
實現類:
導入Java . io . buffered reader;
導入Java . io . file;
導入Java . io . file inputstream;
導入Java . io . file output stream;
導入Java . io . io exception;
導入Java . io . inputstreamreader;
導入Java . io . printwriter;
公共類UserDaoForTextFile實現UserDao{
私有文件userFile
public UserDaoForTextFile(){
}
public UserDaoForTextFile(File File){
this.userFile = file
如果(!file.exists()){
嘗試{
file . create new file();
} catch (IOException e) {
e . printstacktrace();
}
}
}
公共同步布爾addUser(用戶user) {
FileInputStream fis = null
BufferedReader br = null
int lastId = 0;
嘗試{
fis =新文件輸入流(用戶文件);
br = new BufferedReader(新的InputStreamReader(fis));
String str = null
String lastLine = null
while((str=br.readLine())!= null){
//獲取最後壹行值
lastLine = str
if(str . split(":)[1]。equals(user . getname()){
返回false
}
}
if(lastLine!=空)
lastId = integer . parse int(last line . split(":)[0]);
}catch(異常e){
e . printstacktrace();
}最後{
如果(br!=null)請嘗試{ br . close();}catch(IOException e){}
如果(fis!=null)請嘗試{ fis . close();}catch(IOException e){}
}
FileOutputStream fos = null
PrintWriter pw = null
嘗試{
fos = new file output stream(user file,true);
pw =新的PrintWriter(fos);
user . setid(lastId+1);
pw.println(用戶);
pw . flush();
返回true
}catch(異常e){
e . printstacktrace();
}最後{
如果(pw!=null)請嘗試{ pw . close();}catch(異常e){}
如果(fos!=null)請嘗試{ fos . close();}catch(IOException e){}
}
返回false
}
公共同步用戶getUser(字符串用戶名,字符串密碼){
FileInputStream fis = null
BufferedReader br = null
String str = null
用戶user = null
嘗試{
fis =新文件輸入流(用戶文件);
br = new BufferedReader(新的InputStreamReader(fis));
while((str = br.readLine())!= null){
string[]s = str . split(":");
if(username . equals(s[1])& amp;& amppassword.equals(s[2])){
User = new User();
user . setid(integer . parse int(s[0]));
user . set name(s[1]);
user . set password(s[2]);
user . set email(s[3]);
}
}
}catch(IOException e){
e . printstacktrace();
}最後{
如果(br!=null)請嘗試{ br . close();}catch(IOException e){}
如果(fis!=null)請嘗試{ fis . close();}catch(IOException e){}
}
返回用戶;
}
}
配置文件格式為:
Id序列號:用戶名:密碼:電子郵件地址
1:yawin:034437:yawin @ 126 . com
2:周jg:034437:周@126.com