이안의 평일코딩

JAVA - 채팅 프로그램 본문

Back-end/Java

JAVA - 채팅 프로그램

이안92 2020. 8. 4. 16:11
반응형

2020.08.03(월)

 

 

com.sist.client

ClientMainFrame

package com.sist.client;
// 윈도우 => JFrame
// 윈도우와 관련된 클래스를 읽어온다 
import javax.swing.*;
import javax.swing.text.Document;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;

import com.sist.common.Function;

import java.awt.*; // Color,Layout
import java.awt.event.*;// interface
/*
 *    재사용 
 *      = 상속 (is-a) : 기존의 클래스를 변경해서 사용
 *      public class ClientMainFrame extends JFrame
 *                   ===============
 *                    JFrame의 기능을 전체 가지고 온다 
 *      class A
 *      {
 *         O X W
 *      }
 *      class B extends A
 *      {
 *          O X W
 *      }
 *      = 포함 (has-a) : 기존의 클래스를 변경없이 사용
 *      public class ClientMainFrame
 *      {
 *          JFrame f=new JFrame();
 *      }
 *      
 */
import java.io.*;
import java.net.*;
import java.util.*;
/*
 *    1. 사용자가 서버에 요청 
 *    2. 서버에서 들어오는 응답을 받아서 출력 (쓰레드) => 자동화 
 */
public class ClientMainFrame extends JFrame implements ActionListener,
MouseListener,Runnable{
    // 윈도우 크기 결정  => 생성자에서 사용  ==> 291 page
	JLabel title=new JLabel("영화 예매  & 추천 프로그램",JLabel.CENTER);
	MenuForm mf=new MenuForm();
	ChatForm cf=new ChatForm();
	DetailForm df=new DetailForm();
	Login login=new Login();
	ControllPanel cp;
	int curpage=1;
	int totalpage=16;
	// 네트워크 관련 프로그램 
	Socket s; // 연결 기계 
	OutputStream out; // 서버로 요청값 전송 => 로그인,채팅 문자열 , 종료 ....
	BufferedReader in; // 서버로부터 값을 받아오는 클래스  ==> 쓰레드 
	public ClientMainFrame()
	{
		cp=new ControllPanel(this);
		// 새로운 창 => 현재 실행중인 윈도우창을 전송 
		/*
		 *   클래스에서 생성자 사용 => 선언이 아니라 => 구현할때 
		 *   예)
		 *       데이터베이스 : 오라클연결 
		 *       네트워크 : 셋팅 => IP,PORT => 핸드폰 (개통)
		 *       웹 : 쿠키에서 값읽기 => 지동로그인 
		 */
		title.setFont(new Font("굴림체",Font.BOLD,55));
		//title.setOpaque(true);
		//title.setBackground(Color.magenta);
		setLayout(null);// JFrame (BorderLayout) 사용자 정의로 배치 => null
		title.setBounds(10, 15, 1570, 100);
		// 추가 => add()
		add(title);
		// 메뉴 배치
		mf.setBounds(10, 120, 100, 300 );
		add(mf);
		// 채팅폼 
		cf.setBounds(115, 760, 1465, 200);
		add(cf);
		// 출력화면 
		cp.setBounds(115, 120, 1465, 635);
		add(cp);
		setSize(1600, 1000);
		//setVisible(true);
		setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);// X버튼 클릭시 종료
		
		mf.b1.addActionListener(this);
		mf.b2.addActionListener(this);
		mf.b5.addActionListener(this);
		
		cp.ff.b1.addActionListener(this);// 이전
		cp.ff.b2.addActionListener(this);// 다음
		
		df.b2.addActionListener(this);// 목록
		
		cp.lf.b1.addActionListener(this);
		cp.lf.b2.addActionListener(this);
		cp.lf.b3.addActionListener(this);
		cp.lf.b4.addActionListener(this);
		cp.lf.b5.addActionListener(this);
		cp.lf.b6.addActionListener(this);
		cp.lf.tf.addActionListener(this);
		
		
		// 로그인 처리 
		login.b1.addActionListener(this);
		login.b2.addActionListener(this);
		
		// 종료 
		mf.b7.addActionListener(this);
		
		// 채팅 
		cf.tf.addActionListener(this);
		
		/*
		 * for(int i=0;i<10;i++) { cp.ff.mc[i].addMouseListener(this); }
		 */
		
	}
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
        // 생성자는 호출시에 반드시  => new 생성자()
		UIManager.setLookAndFeel("com.jtattoo.plaf.mcwin.McWinLookAndFeel");
		new ClientMainFrame();
	}
	public static Image getImage(ImageIcon ii,int w,int h)
    {
    	Image dimg = ii.getImage().getScaledInstance(w, h,
    	        Image.SCALE_SMOOTH);
    	return dimg;
    }
	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		if(e.getSource()==mf.b1)
		{
			cp.card.show(cp, "FF");
		}
		else if(e.getSource()==mf.b2)
		{
			cp.card.show(cp, "LF");
		}
		else if(e.getSource()==mf.b5)
		{
			cp.card.show(cp, "NF");
		}
		else if(e.getSource()==df.b2)
		{
			cp.card.show(cp, "FF");
		}
		else if(e.getSource()==cp.ff.b1)// 이전버튼
		{
			if(curpage>1)
			{
				curpage--;
				cp.ff.p.removeAll();// JPanel의 모든 기능을 삭제
				cp.ff.moviePrint(curpage);
				cp.ff.repaint();
				cp.ff.p.validate();//JPanel의 원래 기능을 재배치
			}
			
		}
		else if(e.getSource()==cp.ff.b2)// 다음버튼
		{
			if(curpage<totalpage)
			{
				curpage++;
				cp.ff.p.removeAll();
				cp.ff.moviePrint(curpage);
				cp.ff.repaint();
				cp.ff.p.validate();
			}
		}
		else if(e.getSource()==cp.lf.b1)
		{
			cp.lf.movieAllData(1);
		}
		else if(e.getSource()==cp.lf.b2)
		{
			cp.lf.movieAllData(2);
		}
		else if(e.getSource()==cp.lf.b3)
		{
			cp.lf.movieAllData(3);
		}
		else if(e.getSource()==cp.lf.b4)
		{
			cp.lf.movieAllData(4);
		}
		else if(e.getSource()==cp.lf.b5)
		{
			cp.lf.movieAllData(5);
		}
		else if(e.getSource()==cp.lf.b6 || e.getSource()==cp.lf.tf)
		{
			// 1. 입력된 값 읽기
			String ss=cp.lf.tf.getText();
			if(ss.length()<1)
			{
				JOptionPane.showMessageDialog(this, "검색어를 입력하세요");
				cp.lf.tf.requestFocus();
				return; // 메소드 종료 
			}
			cp.lf.movieFindData(ss);
		}
		
		else if(e.getSource()==login.b1)
		{
			String id=login.tf1.getText();
			if(id.length()<1)// ID가 입력하지 않을 경우
			{
				JOptionPane.showMessageDialog(this, "아이디를 입력하세요");
				login.tf1.requestFocus();
				return;
			}
			
			String name=login.tf2.getText();
			if(name.length()<1)
			{
				JOptionPane.showMessageDialog(this, "대화명을 입력하세요");
				login.tf2.requestFocus();
				return;
			}
			
			String sex="";
			if(login.rb1.isSelected())
				sex="남자";
			else
				sex="여자";
			
			// 서버로 입력받은 데이터 전송 
			try
			{
				// 연결  => 서버에 대한 정보를 가지고 있다 
				s=new Socket("localhost",3355);
				// 송수신 위치 확인
				in=new BufferedReader(new InputStreamReader(s.getInputStream()));
				out=s.getOutputStream();
				
				// 로그인 요청 (서버로 전송되는 부분)
				out.write((Function.LOGIN+"|"+id+"|"+name+"|"+sex+"\n").getBytes());
			}catch(Exception ex){}
			    
			    //서버에서 전송하는 데이터를 읽어서 출력 
			    new Thread(this).start();
			    // run()의 위치 확인 ==> 자신의 클래스안에 존재 => (this)
		}
		else if(e.getSource()==login.b2)
		{
			System.exit(0);
		}
		else if(e.getSource()==cf.tf)// 채팅 
		{
			String color=cf.box.getSelectedItem().toString();
			String msg=cf.tf.getText();
			if(msg.length()<1)
				return;
			// 데이터를 서버로 전송 
			try
			{
				out.write((Function.CHAT+"|"+msg+"|"+color+"\n").getBytes());
			}catch(Exception ex){}
			
			    cf.tf.setText("");
		}
		else if(e.getSource()==mf.b7)
		{
			try
			{
				out.write((Function.EXIT+"|\n").getBytes());
			}catch(Exception ex) {}
		}
		
	}
	@Override
	public void mouseClicked(MouseEvent e) {
		// TODO Auto-generated method stub
		for(int i=0;i<10;i++)
		{
			if(e.getSource()==cp.ff.mc[i])
			{
				if(e.getClickCount()==2)
				{
					int a=(i+1)+((curpage*10)-10);
					//JOptionPane.showMessageDialog(this, "mno="+a);
					//System.out.println(a);
					df.detailPrint(a);
					//cp.card.show(cp,"DF");
					df.setVisible(true);
					break;
				}
			}
		}
	}
	@Override
	public void mousePressed(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void mouseReleased(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void mouseEntered(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void mouseExited(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		// 서버에서 들어오는 데이터를 받아서 처리 
		try
		{
			while(true)
			{
				String msg=in.readLine();
				System.out.println("server=>"+msg);
				StringTokenizer st=
						  new StringTokenizer(msg,"|");
				int protocol=Integer.parseInt(st.nextToken());
				switch(protocol)
				{
				   case Function.MYLOG:
				   {
					   setTitle(st.nextToken());
					   login.setVisible(false);// 로그인창
					   setVisible(true);// 영화창 (Main) 
				   }
				   break;
				   case Function.LOGIN:
				   {
					   // 테이블에 출력 
					   String[] data= {
						  st.nextToken(), // id
						  st.nextToken(), // name
						  st.nextToken() // sex
					   };
					   cf.model.addRow(data);
				   }
				   break;
				   case Function.CHAT:
				   {
					     initStyle();
					     append(st.nextToken(),st.nextToken());
				   }
				   break;
				   case Function.EXIT:
				   {
					   String id=st.nextToken();
					   for(int i=0;i<cf.model.getRowCount();i++)
					   {
						   String mid=cf.model.getValueAt(i,0).toString();
						   if(id.equals(mid))
						   {
							   cf.model.removeRow(i);
							   break;
						   }
					   }
				   }
				   break;
				   case Function.MYEXIT:
				   {
					   dispose();// 윈도우 메모리 해제 
					   System.exit(0);// 프로그램 종료 
				   }
				   break;
				}
			}
		}catch(Exception ex) {}
	}
    public void initStyle()
    {
    	Style def=StyleContext.getDefaultStyleContext().getStyle(StyleContext.DEFAULT_STYLE);
    	Style red=cf.ta.addStyle("red", def);
    	StyleConstants.setForeground(red, Color.red);
    	
    	Style blue=cf.ta.addStyle("blue", def);
    	StyleConstants.setForeground(blue, Color.blue);
    	
    	Style green=cf.ta.addStyle("green", def);
    	StyleConstants.setForeground(green, Color.green);
    	
    	Style yellow=cf.ta.addStyle("yellow", def);
    	StyleConstants.setForeground(yellow, Color.yellow);
    	
    	Style gray=cf.ta.addStyle("gray", def);
    	StyleConstants.setForeground(gray, Color.gray);
    	
    	Style cyan=cf.ta.addStyle("cyan", def);
    	StyleConstants.setForeground(cyan, Color.cyan);
    }
    public void append(String msg,String color)
    {
    	try
    	{
    		Document doc=cf.ta.getDocument();
    		doc.insertString(doc.getLength(), msg+"\n", cf.ta.getStyle(color));
    	}catch(Exception ex) {}
    }
}

 

ChatForm

package com.sist.client;
import java.awt.Color;
// 1465, 200
import javax.swing.*;
import javax.swing.table.*;
public class ChatForm extends JPanel{
   JTextPane ta;
   JTextField tf;
   JComboBox box;
   JTable table;
   DefaultTableModel model;
   JButton b1,b2;
   public ChatForm()
   {
	   //setBackground(Color.yellow);
	   setLayout(null);
	   ta=new JTextPane();
	   ta.setEditable(false);
	   JScrollPane js=new JScrollPane(ta);
	   js.setBounds(10, 15, 850, 140);
	   add(js);
	   tf=new JTextField();
	   tf.setBounds(10, 160, 740, 30);
	   add(tf);
	   
	   box=new JComboBox();
	   box.addItem("black");
	   box.addItem("red");
	   box.addItem("blue");
	   box.addItem("green");
	   box.addItem("gray");
	   box.addItem("yellow");
	   box.addItem("cyan");
	   
	   box.setBounds(755, 160, 105, 30);
	   add(box);
	   
	   String[] col={"ID","대화명","성별"};
	   String[][] row=new String[0][3];
	   model=new DefaultTableModel(row,col);
	   table=new JTable(model);
	   JScrollPane js1=new JScrollPane(table);
	   js1.setBounds(865, 15, 500, 135);
	   add(js1);
	   
	   JPanel p=new JPanel();
	   b1=new JButton("정보보기");
	   b2=new JButton("쪽지보내기");
	   p.add(b1);
	   p.add(b2);
	   p.setBounds(865, 155, 500, 35);
	   add(p);
	   
   }
}

 

Login

package com.sist.client;
import javax.swing.*;
import java.awt.*;
public class Login extends JFrame{
    JLabel la1,la2,la3;
    JTextField tf1,tf2;
    JRadioButton rb1,rb2;
    JButton b1,b2;
    public Login()
    {
    	la1=new JLabel("ID",JLabel.RIGHT);
    	la2=new JLabel("대화명",JLabel.RIGHT);
    	la3=new JLabel("성별",JLabel.RIGHT);
    	
    	tf1=new JTextField();
    	tf2=new JTextField();
    	
    	rb1=new JRadioButton("남자");
    	rb2=new JRadioButton("여자");
    	ButtonGroup bg=new ButtonGroup();
    	bg.add(rb1); bg.add(rb2);
    	rb1.setSelected(true);
    	
    	b1=new JButton("로그인");
    	b2=new JButton("취소");
    	
    	// 배치 
    	setLayout(null);
    	la1.setBounds(10, 15, 60, 30);
    	tf1.setBounds(75, 15, 150, 30);
    	
    	la2.setBounds(10, 50, 60, 30);
    	tf2.setBounds(75, 50, 150, 30);
    	
    	la3.setBounds(10, 85, 60, 30);
    	rb1.setBounds(75, 85, 70, 30);
    	rb2.setBounds(150, 85, 70, 30);
    	
    	JPanel p=new JPanel();
    	p.add(b1);p.add(b2);
    	
    	p.setBounds(10, 120, 215, 35);
    	
    	// 윈도우 추가
    	add(la1);add(tf1);
    	add(la2);add(tf2);
    	add(la3);add(rb1);add(rb2);
    	add(p);
    	
    	// 윈도우 크기
    	setSize(250, 200);
    	setVisible(true);
    }
	/*
	 * public static void main(String[] args) { new Login(); }
	 */
}

 

 

com.sist.common

Function

package com.sist.common;

public class Function {
   public static final int LOGIN=100;// 로그인 된 사람
   public static final int MYLOG=110;// 로그인 하는 사람 
   //로그인 
   public static final int CHAT=200;
   //채팅 
   public static final int EXIT=300;// 남아 있는 사람
   public static final int MYEXIT=310;// 나가는 사람 처리 
   //나가기 
}

 

 

com.sist.server

Server

package com.sist.server;
import java.util.*;

import com.sist.common.Function;

import java.net.*;
import java.io.*;
public class Server implements Runnable{
    // 서버에서 실행된 Scoket
	ServerSocket ss;
	final int PORT=3355;// 1024~65535
	// 클라이언트 정보를 저장 
	Vector<Client> waitVc=new Vector<Client>();// ArrayList,LinkedList
	// 서버 가동 
	public Server()
	{
		try
		{
			ss=new ServerSocket(PORT);
			// bind(): 개통   listen(): 접속시까지 대기 
			System.out.println("Server Start...");
		}catch(Exception ex){}
	}
	
	// 클라이언트가 접속시마다 처리 기능 
	public void run()
	{
		try
		{
			while(true)
			{
			    Socket s=ss.accept();
				  // Socket => 발신자 정보를 가지고 있다 (IP,PORT)
				  /*
				  *   접속하면 => 쓰레드를 생성해서 클라이언트마다 통신을 다르게 할 수 있게 만든다 
				  */
				  // 쓰레드와 연결 => Socket만 연결하면 한사람하고만 통신이 가능 
				Client client=new Client(s);
				client.start(); // 통신을 시작하라~~
			}
		}catch(Exception ex){}
	}
	// 통신이 가능하게 만든다 
	class Client extends Thread
	{
		// 클라이언트의 정보 수집
		Socket s;
		// 송신,수신
		OutputStream out;
		BufferedReader in;
		// 클라이언트의 기본 정보 
		String id,name,sex;
		public Client(Socket s)
		{
			// 변수는 지역변수 우선순위  
			// 변수명 ==> 지역변수,매개변수 => 멤버변수(멤버변수 사용 => this.변수명)
			try
			{
			  this.s=s; // Connection(오라클)
			  // 클라이언트와 연결 
			  out=s.getOutputStream(); // PreparedStatement => SQL
			  // 클라이언트에 응답을 전송 (값)
			  in=new BufferedReader(new InputStreamReader(s.getInputStream()));
			  // 클라이언트의 요청값을 받을 경우에 사용 // ResultSet => 결과값 받기 
			  /*
			   *    out=s.getOutputStream(); => HttpServletResponse
			   *    in=new BufferedReader    => HttpServletRequest
			   */
			}catch(Exception ex){}
		}
		// 통신 
		public void run()
		{
			try
			{
				while(true)
				{
					String msg=in.readLine();
					System.out.println("client=>"+msg);
					// 클라이언트 요청한 데이터 
					StringTokenizer st=new StringTokenizer(msg,"|");
					int protocol=Integer.parseInt(st.nextToken());
					// 100|id|name|sex
					switch(protocol)
					{
						case Function.LOGIN:
						{
							id=st.nextToken();
							name=st.nextToken();
							sex=st.nextToken();
							
							messageAll(Function.LOGIN+"|"+id+"|"+name+"|"+sex);
							// LOGIN 테이블에 출력 
							// 추가 
							waitVc.add(this);
							// 화면 변경 
							// 로그인 ==> 대기실 
							messageTo(Function.MYLOG+"|"+id);
							// MYLOG 로그인창을 종료 => 대기실을 실행 
							// 이미 접속한 사람들의 정보 받기
							for(Client user:waitVc)
							{
								messageTo(Function.LOGIN+"|"
										+user.id+"|"+user.name+"|"+user.sex);
							}
						}
						break;
						case Function.CHAT:
						{
							messageAll(Function.CHAT+"|["+name+"]"+st.nextToken()+"|"+st.nextToken());
						}
						break;
						case Function.EXIT:
						{
							String mid=id;
							messageAll(Function.EXIT+"|"+mid);
							// EXIT => 대기실 테이블에서 id를 제거 
							// 제거 
							for(Client user:waitVc)
							{
								if(user.id.equals(id))
								{
									messageTo(Function.MYEXIT+"|");
									waitVc.remove(user);
									in.close();
									out.close();
									//통신을 중단한다
									break;
								}
							}
						}
						break;
					}
					
				}
			}catch(Exception ex) {}
		}
		// 전체적으로 메세지 전송
		// synchronized 동기화 프로그램 
		public void messageAll(String msg)
		{
			for(Client user:waitVc)
			{
				try
				{
				    user.messageTo(msg);	
				}catch(Exception ex)
				{
					waitVc.remove(user);
				}
			}
			
		}
		// 개인적으로 메세지 전송 
		public void messageTo(String msg)
		{
			try
			{
				out.write((msg+"\n").getBytes());
				// 인코딩 ==> 디코딩 ==> UTF-8
			}catch(Exception ex) {}
		}
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
        Server server=new Server();// 서버 가동 
        new Thread(server).start();// 접속시까지 기다려라 
	}

}
반응형
Comments