● 관련문서 :


EJB는 '구조가 복잡한 대규모 분산 객체 환경'을 쉽게 구현하기 위해서 등장한 기술이다. 따라서 EJB를 사용하기 전에, 프로젝트가 분산 객체 환경을 필요로 하는지에 대한 고려가 반드시 필요하며 분산 객체 환경이 필요없는 경우에는 EJB를 사용해야할 필요가 없다고 해도 과언이 아니다. 하지만 EJB를 사용하면 시스템의 무조건적인 향사잉 있을 것이라는 잘못된 지식 떄문에 EJB가 등장한 초기에는 EJB 프로젝트를 무조건 사용하는 경우도 많았다.


EJB는 내부적으로, 분산 환경에 맞도록 동작하기 위해서 추가적인 과부하(OverHead)가 많이 발생한다. 그렇기 때문에 분산 객체 환경이 필요없는 경우에, EJB를 사용하게 되면 속도도 느리게 되고 비용도 많이 발생시킨다. 즉, EJB를 사용하려면 왜 분산 환경이 필요한지에 대한 확실한 이해가 필요하다.


분산 환경은 일반적으로, 비지니스 로직과 사용자 인터페이스를 분리시킴으로써 로직의 재활용성을 높이고 시스템 구조에 대한 유연성을 높이기 위해 필요하며, 로직의 재활용성과 시스템의 구조에 대한 유연성은 대규모 시스템일수록 중요하다. 즉, 대규모 시스템은 분산 환경을 필요로 하며 분산 환경을 쉽게 구축하도록 하기 위해서 EJB를 사용하는 것이다.


EJB를 현장에서 사용하려면 다음과 같은 내용을 반드시 알아야 한다.


  1. EJB는 속도를 높이려고 사용하는 것이 아니다. EJB는 분산 객체를 쉽게 구축하고 시스템의 유연성을 높이기 위해 만들어진 것이다. 분산 환경을 쉽게 구축하고 시스템의 유연성을 높이기 위해서 만들어진 것이다. 분산 환경을 쉽게 구축하고 시스템의 유연성을 높인다는 것은 속도와는 반비례한다. 그 이유는 분산 환경과 유연성을 높이기 위해 추가적인 과부하가 발생하기 때문이다.
  2. EJB는 안정적이다. EJB를 사용한다는 것은 EJB를 운용하기 위한 프레임워크(Framework-위키백과)를 사용한다는 의미다. EJB를 운용하는 프레임워크는 웹 프로그램과 EJB가 수행할 업무를 효율적으로 분산시켜주며 효율적으로 일이 분산됨으로써 시스템은 안정적으로 동작한다.
  3. EJB는 배우기 쉽다. 대신에, EJB를 쉽게 배우려면 자바 기본 프로그래밍, RMI, JSP/서블릿에 대한 내용을 알고 있어야 한다는 가정이 필요하다. EJB를 공부해보면 알겠지만 EJB 명세만 암기하더라도 EJB를 사용해서 쉽게 개발할 수 있다.
  4. EJB는 사용하기가 쉽지 않다. EJB는 앞서 말한 것처럼 배우기는 쉽다. 그렇다고 사용하기도 쉽다는 의미는 아니다. EJB를 잘못 사용할 경우 더 큰 문제점이 발생하기 떄문이다. EJB를 잘 사용하려면 분산 환경과 EJB의 특징에 대한 확실한 이해가 필요하다.

이 글은 스프링노트에서 작성되었습니다.

서블릿을 실행하려면 서블릿 소스의 작성과 컴파일, web.xml 파일의 수정과 같은 여러 작업이 이뤄져야한다.

 

1.서블릿 파일 작성

  1. package examples; // package로 지정
    import java.io.*;
    import javax.servlet.*;
    import javax.servlet.http.*;

    public class HelloWorldServlet extends HttpServlet {
        public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
            response.setContentType("text/html; charset=euc-kr");
            PrintWriter out = response.getWriter();
            out.println("<html>");
            out.println("<head><title>안녕하세요, Hello</title></head>");
            out.println("<body>안녕하세요. <br>Hello!! world!!!</body>");
            out.println("</html>");
        }
    }

 

2.setEnv.com 파일 실행

setEnv.cmd(Path 설정할 경우 setenv 만 실행해도 됨)

 

3.서블릿 파일 컴파일

  1. javac -d ../classes HelloworldServlet.java

 

4.web.xml 수정

  1. <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
    <web-app>
        <servlet>
            <servlet-name>helloworld</servlet-name>
            <servlet-class>examples.HelloWorldServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>helloworld</servlet-name>
            <url-pattern>/hello</url-pattern>
        </servlet-mapping>

    </web-app>

 

5.서블릿 실행

<servlet-mapping 요소 안에 지정한 것처럼 http://localhost:7001/hello로 요쳥하면 된다.

HelloWorldServlet.JPG

... ㅡㅅ-);; Eclipse에서 서블릿 실행할 때보다 더 귀찮다.... 흠냠...

이 글은 스프링노트에서 작성되었습니다.

작업파일 : miniProject(090612)_VideoShop_RMI.zip


서버용 인터페이스 : Server.java

  • 클라이언트에서 사용하는 메소드 정의
  1. /*-------------------------------------------------------------------------------------------
     *  작성일 : 2009년 6월 10일 ~ 6월 12일(2박 3일), 미니프로젝트 비디오샵 프로그램
     *     작성목적 : RMI 기능을 이용한 비디오샵 프로그램을 개발하여 RMI 와 콜백 기능을 익힌다.
     *  작성자 : 김지헌 (Honeymon, iammine@korea.com)
     * 
     *  프로그램 구성 :
     *  
     *  - 인터페이스 : Server.java, Client.java
     *  - 실행파일 : ServerImpl.java, ClientImpl.java
     * 
     *  주의사항 :
     *  
     *  - 컴파일 후, 실행파일들은 RMIC에 등록작업을 해주어야 한다.
     *  - 클라이언트 실행시 2개의 파라메터(who = 접속자, server = DB Table 명)를 필요로 한다.
     *      ex) java ClientImpl 양재 client3
     *  - 서버와 클라이언트 간에 주고받는 자료는 Vector로 구성된다.
     --------------------------------------------------------------------------------------------*/
    import java.rmi.*;
    import java.util.Vector;

    public interface Server extends Remote {
        // 공지사항 관련 메소드
        public void showNoticeDB() throws RemoteException;
        public Vector noticeTitle() throws RemoteException;
        public Vector noticeContent() throws RemoteException;
        public void broadcastNotice() throws RemoteException;
       
        //인기비디오 관련 메소드
        public void showFavoriteVideoDB() throws RemoteException;
        public Vector favoriteTitle() throws RemoteException;
        public Vector broadcastFavoriteContent() throws RemoteException;
       
        //신작 비디오 관련 메소드
        public void showNewVideoDB() throws RemoteException;
        public Vector newTitle() throws RemoteException;
        public Vector newContent() throws RemoteException;
        public void broadcastNewVideo() throws RemoteException; // 신작비디오(본사 등록시 실행)
       
        // 각 지점의 로그인 관리
        public void register(Client client, String name) throws RemoteException;
        public void unregister(Client client, String name) throws RemoteException;   
       
    }

 

원격객체 : ServerImpl.java

  • RMI 등록되고 실행되고 있으면, 원격접속 클라이언트들에게 관련한 작업들 처리해줌
  1. /*-------------------------------------------------------------------------------------------
     *  작성일 : 2009년 6월 10일 ~ 6월 12일(2박 3일), 미니프로젝트 비디오샵 프로그램
     *     작성목적 : RMI 기능을 이용한 비디오샵 프로그램을 개발하여 RMI 와 콜백 기능을 익힌다.
     *  작성자 : 김지헌 (Honeymon, iammine@korea.com)
     * 
     *  프로그램 구성 :
     *  
     *  - 인터페이스 : Server.java, Client.java
     *  - 실행파일 : ServerImpl.java, ClientImpl.java
     * 
     *  주의사항 :
     *  
     *  - 컴파일 후, 실행파일들은 RMIC에 등록작업을 해주어야 한다.
     *  - 클라이언트 실행시 2개의 파라메터(who = 접속자, server = DB Table 명)를 필요로 한다.
     *      ex) java ClientImpl 양재 client3
     *  - 서버와 클라이언트 간에 주고받는 자료는 Vector로 구성된다.
     --------------------------------------------------------------------------------------------*/
    import java.awt.BorderLayout;
    import java.awt.CardLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import java.rmi.Naming;
    import java.rmi.RemoteException;
    import java.rmi.server.UnicastRemoteObject;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.ResultSetMetaData;
    import java.sql.Statement;
    import java.util.Enumeration;
    import java.util.Vector;

    import javax.swing.JButton;
    import javax.swing.JComboBox;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JPasswordField;
    import javax.swing.JScrollPane;
    import javax.swing.JTabbedPane;
    import javax.swing.JTable;
    import javax.swing.JTextField;
    import javax.swing.SingleSelectionModel;
    import javax.swing.event.ChangeEvent;
    import javax.swing.event.ChangeListener;
    import javax.swing.table.DefaultTableModel;

    public class ServerImpl extends UnicastRemoteObject implements Server, ActionListener {
        private String url = "jdbc:oracle:thin:@61.103.103.184:1521:cjedu";
        private String user = "scott";
        private String passwd = "tiger";
        private DefaultTableModel nmodel, newmodel, fmodel, lmodel;
        private Vector ntitle = new Vector();
        private Vector ncontent = new Vector();
        private Vector newtitle = new Vector();
        private Vector newcontent = new Vector();
        private Vector ftitle = new Vector();
        private Vector fcontent = new Vector();
        private Vector ltitle = new Vector();
        private Vector lcontent = new Vector();
        private Vector clientList = new Vector();
        private JTextField ntfield, listTitleTfield, listGenreTfield;
        private JButton nwrite, nedit, ndel, listInsert, listDelete, fbutton;
        private JComboBox listcbox;
        private String who = "관리자";
       
        Connection con;
        Statement stat;
        private JTable ntable;
        private JTextField numtfield;
        private JPasswordField pw;
        private JButton login;
        private JTextField idt;
        private CardLayout card;
        private JPanel cpane;
        private JTable ltable;
       
       
        public ServerImpl() throws RemoteException  {
            database();
            makeGui();
           
           
            //창이 닫힐 경우 자원들을 종료하는 Listner
    /*        addWindowListener(new WindowAdapter() {
                public void windowClosing(WindowEvent x){
                   try {
                   Window w = (Window)x.getSource();
                   w.setVisible(false);
                   w.dispose();//화면에 썼던 자원을 해지하는것.
                
                     close();
                   System.exit(0); //프로세스 종료
                   }catch(Exception e){}
                  }
             });*/
        }
       
        //DB연결관련 처리
        public  void database(){
            try {
                Class.forName("oracle.jdbc.driver.OracleDriver");
                con = DriverManager.getConnection( url, user, passwd );
                stat = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
            } catch( Exception e) {
                e.printStackTrace();
            }
        }
       
        public void makeGui() throws RemoteException{
            JFrame frame = new JFrame("Fun Video Company");
            frame.pack();
            frame.setDefaultCloseOperation(3);
            frame.setSize(800,800);
            frame.setVisible(true);       
            final JTabbedPane tab = new JTabbedPane();
            frame.add(tab);
           

            //noticePanel
            nmodel = new DefaultTableModel();
            ntable = new JTable(nmodel);
            JScrollPane nspane = new JScrollPane(ntable);
            //nmodel.setDataVector(dataVector, columnIdentifiers);
           
            ntable.addMouseListener(new MouseAdapter() {
                public void mouseClicked(MouseEvent m){
                    int row = ntable.getSelectedRow();
                    Vector in = (Vector)ncontent.elementAt(row);
                    numtfield.setText((String)in.elementAt(0));
                    ntfield.setText((String)in.elementAt(1));
                }
            });
            //DB 연동해주기.
            showNoticeDB();       
            JLabel numlabel = new JLabel("번호");
            numtfield = new JTextField(3);
            JLabel nlabel = new JLabel("내용");
            ntfield = new JTextField(30);
            nwrite = new JButton("작성");
            ndel = new JButton("삭제");
            nwrite.addActionListener(this);
            ndel.addActionListener(this);
           
            JPanel noticePanel = new JPanel();
            noticePanel.add(numlabel);
            noticePanel.add(numtfield);
            noticePanel.add(nlabel);
            noticePanel.add(ntfield);
            noticePanel.add(nwrite);
            noticePanel.add(ndel);
                   
            JPanel notice = new JPanel();
            notice.setLayout(new BorderLayout());
            notice.add(nspane, "Center");
            notice.add(noticePanel, "South");
           

           
            //newVideo Panel
            newmodel = new DefaultTableModel();
            JTable newtable = new JTable(newmodel);
            JScrollPane newspane = new JScrollPane(newtable);
            //newmodel.setDataVector(dataVector, columnIdentifiers);
            showNewVideoDB();
           
            JPanel newVideo = new JPanel();
            newVideo.setLayout(new BorderLayout());
            newVideo.add(newspane, "Center");
           
           
            //favoriteVideo Panel
            fmodel = new DefaultTableModel();
            JTable ftable = new JTable(fmodel);
            JScrollPane fspane = new JScrollPane(ftable);
            //fmodel.setDataVector(dataVector, columnIdentifiers);
           
            JPanel favoritePanel = new JPanel();
            favoritePanel.setLayout(new BorderLayout());
            fbutton = new JButton("집계");
            fbutton.addActionListener(this);
            favoritePanel.add(fbutton, "East");
           
            JPanel favoriteVideo = new JPanel();
            favoriteVideo.setLayout(new BorderLayout());
            favoriteVideo.add(fspane, "Center");
            favoriteVideo.add(favoritePanel, "South");
           
           
            //listVideo Panel
            lmodel = new DefaultTableModel();
            ltable = new JTable(lmodel);
            JScrollPane lspane = new JScrollPane(ltable);
            //lmodel.setDataVector(dataVector, columnIdentifiers);
            showListVideoDB("servervideo");
            ltable.addMouseListener(new MouseAdapter() {
                public void mouseClicked(MouseEvent m){
                    int row = ltable.getSelectedRow();
                    Vector in = (Vector)lcontent.elementAt(row);
                    listTitleTfield.setText((String)in.elementAt(1));
                    listGenreTfield.setText((String)in.elementAt(2));   
                }
            });
           
            JPanel listPanel = new JPanel();
            String data[] = {"본사","양재", "강남", "논현"};
            listcbox = new JComboBox(data);
            listcbox.addActionListener(this);
            JLabel listTitle = new JLabel("제목");
            listTitleTfield = new JTextField(30);
            JLabel listGenre = new JLabel("장르");
            listGenreTfield = new JTextField(10);
            listInsert = new JButton("추가");
            listInsert.addActionListener(this);
            listDelete = new JButton("삭제");
            listDelete.addActionListener(this);
           
            listPanel.add(listcbox);
            listPanel.add(listTitle);
            listPanel.add(listTitleTfield);
            listPanel.add(listGenre);
            listPanel.add(listGenreTfield);
            listPanel.add(listInsert);
            listPanel.add(listDelete);
           
            JPanel listVideo = new JPanel();
            listVideo.setLayout(new BorderLayout());
            listVideo.add(lspane, "Center");
            listVideo.add(listPanel, "South");
           
                   
            //tab.add() 1. notice, 2.newViedo 3.favoriteVideo 4.ListVideo
            tab.add(notice,"공지사항");
            tab.add(newVideo,"신작비디오");
            tab.add(favoriteVideo, "인기비디오");
            tab.add(listVideo, "비디오목록");
         
              
             tab.getModel().addChangeListener(
                new ChangeListener() {
                   public void stateChanged(ChangeEvent e) {
                   SingleSelectionModel model = (SingleSelectionModel) e.getSource();
                   if(model.getSelectedIndex() == tab.getTabCount()-1) {
                   }
                   }
                }
             );
            
        }
       
        // ------------------------------------------------------------------------------------------- //   
        // ---------------------   showNoticeDB() : 공지사항 관련 출력부 ----------------------------- //
       
        public void showNoticeDB() throws RemoteException {
            ncontent.clear();
            ntitle = noticeTitle();
            ncontent = noticeContent();
            nmodel.setDataVector(ncontent, ntitle);
        }
       
        public Vector noticeTitle() throws RemoteException {
            String sql = "SELECT num as 번호, content as 내용, writer as 작성자, TO_CHAR(indate, 'YYYY / MM / DD') as 작성일 FROM notice ORDER BY num desc";
            try {
                ntitle.clear();
                ResultSet rs = stat.executeQuery(sql);
                ResultSetMetaData rsmd = rs.getMetaData();
                int count = rsmd.getColumnCount();
                ntitle.clear();
                for ( int i = 1 ; i <= count ; i++){
                    String t = rsmd.getColumnName(i);
                    ntitle.add(t);               
                }
           
            } catch( Exception e) {
                e.printStackTrace();
            }
            return ntitle;
        }
       
        public Vector noticeContent() throws RemoteException {
            String sql = "SELECT num, content, writer, TO_CHAR(indate, 'YYYY / MM / DD') FROM notice ORDER BY num desc";
            try {
                ResultSet rs = stat.executeQuery(sql);
                ResultSetMetaData rsmd = rs.getMetaData();
                int count = rsmd.getColumnCount();
                ncontent.clear();
                while( rs.next() ){
                    Vector in = new Vector();
                    in.add(rs.getString(1));
                    in.add(rs.getString(2));
                    in.add(rs.getString(3));
                    in.add(rs.getString(4));
                    ncontent.add(in);
                }
                rs.close();
            } catch( Exception e) {
                e.printStackTrace();
            }   
            return ncontent;
        }
       
        // ---------------------   showNoticeDB() : 공지사항 관련 출력부 ----------------------------- //
        // ------------------------------------------------------------------------------------------- //
       
       
       
        // ------------------------------------------------------------------------------------------- //
        // ---------------------    showNewVideoDB() : 신작 비디오 관련 출력부 ----------------------- //
       
        public void showNewVideoDB(){
            newtitle.clear();
            newcontent.clear();
            newtitle = newTitle();
            newcontent = newContent();
            newmodel.setDataVector(newcontent, newtitle);
        }

        public Vector newTitle(){
            newtitle.clear();
            String sql = "SELECT id as 번호, title as 제목, sgroup as 장르, TO_CHAR(indate, 'YYYY / MM / DD') as 입고일 FROM servervideo ORDER BY indate desc";
            try {
                ResultSet rs = stat.executeQuery(sql);
                ResultSetMetaData rsmd = rs.getMetaData();
                int count = rsmd.getColumnCount();
                newtitle.clear();
                for ( int i = 1; i <= count; i++ ){
                    String t = rsmd.getColumnName(i);
                    newtitle.add(t);
                }   
            } catch ( Exception e ){
                e.printStackTrace();
            }
           
            return newtitle;
        }
       
        //신작 비디오의 기준은 입고일 14일 이내의 작품들 : 기간 설정변수 int limitday
        public Vector newContent(){
            newcontent.clear();
            int limitday = 14;
            String sql = "SELECT id as 번호, title as 제목, sgroup as 장르, TO_CHAR(indate, 'YYYY / MM / DD') as 입고일 FROM servervideo WHERE indate > sysdate - " + limitday + "ORDER BY indate desc";
            try {
                ResultSet rs = stat.executeQuery(sql);
                ResultSetMetaData rsmd = rs.getMetaData();
                int count = rsmd.getColumnCount();
                while( rs.next() ){
                    Vector in = new Vector();
                    for ( int i = 1; i <= count; i++){
                        in.add(rs.getString(i));
                    }
                    newcontent.add(in);
                }
            } catch ( Exception e ) {
                e.printStackTrace();
            }       
            return newcontent;
        }
        // ---------------------    showNewVideoDB() : 신작 비디오 관련 출력부 ----------------------- //
        // ------------------------------------------------------------------------------------------- //
       

       
        // ------------------------------------------------------------------------------------------- //
        // ---------------------    showFavoriteVideo() : 인기 비디오 관련 출력부 -------------------- //
        // ------------------- 집계버튼 클릭시 접속된 모든 클라이언트에 영향을 끼침 ------------------ //
        public void showFavoriteVideoDB() throws RemoteException  {
            ftitle.clear();
            ftitle = favoriteTitle();
            fcontent = favoriteContent();
            fmodel.setDataVector(fcontent, ftitle);
        }
       
        public Vector favoriteTitle()throws RemoteException{
            ftitle.clear();
            ftitle.add("번호");
            ftitle.add("제목");
            ftitle.add("장르");
            ftitle.add("지점");
            return ftitle;
        }

        public Vector favoriteContent() throws RemoteException{
            System.out.println("집계 자료를 요청받았음");
            fcontent = broadcastFavoriteContent();
            System.out.println("집계자료 반납, 가져!!");
            return fcontent;
        }
        // ---------------------    showFavoriteVideo() : 인기 비디오 관련 전체 출력부 -------------------- //   
        // ------------------------------------------------------------------------------------------- //
       
        // ------------------------------------------------------------------------------------------- //
        // -------------------    showListVideoDB() : 비디오 리스트 관련 출력부 ------------------------ //   
        public void showListVideoDB(String shop){
            lcontent.clear();
            ltitle.clear();
            ltitle = listTitle(shop);
            lcontent = listContent(shop);
            lmodel.setDataVector(lcontent, ltitle);
        }
       
        public Vector listTitle(String shop){
            if ( shop == "servervideo"){
               
                String sql = "SELECT id as 번호, title as 제목, sgroup as 장르, TO_CHAR(indate, 'YYYY / MM / DD') as 입고일 FROM servervideo ORDER BY indate desc";
                try {
                    ResultSet rs = stat.executeQuery(sql);
                    ResultSetMetaData rsmd = rs.getMetaData();
                    int count = rsmd.getColumnCount();
                    ltitle.clear();
                    for ( int  i = 1 ; i <= count ; i++ ){
                        String t = rsmd.getColumnName(i);
                        ltitle.add(t);
                    }
                } catch ( Exception e ){
                    e.printStackTrace();
                }
               
            } else {
               
                String sql = "SELECT id as 번호, name as 제목, genre as 장르, rentcount as 대여횟수, state as 대여상태 FROM "+ shop +" ORDER BY rentcount desc";
                try {
                    ResultSet rs = stat.executeQuery(sql);
                    ResultSetMetaData rsmd = rs.getMetaData();
                    int count = rsmd.getColumnCount();
                    for ( int  i = 1 ; i <= count ; i++ ){       
                        String t = rsmd.getColumnName(i);
                        ltitle.add(t);
                    }   
                } catch ( Exception e ){
                    e.printStackTrace();
                }       
               
            }
            return ltitle;
        }
       
        public Vector listContent(String shop){
            if ( shop == "servervideo") {
                String sql = "SELECT id as 번호, title as 제목, sgroup as 장르, TO_CHAR(indate, 'YYYY / MM / DD') as 입고일 FROM " + shop + " ORDER BY indate desc";
                try {
                    ResultSet rs = stat.executeQuery(sql);
                    ResultSetMetaData rsmd = rs.getMetaData();
                    int count = rsmd.getColumnCount();
                    lcontent.clear();
                    while( rs.next() ){
                        Vector in = new Vector();
                        for (int i = 1; i <= count; i++ ){
                            in.add(rs.getString(i));
                        }
                        lcontent.add(in);
                    }
                    rs.close();
                } catch( Exception e) {
                    e.printStackTrace();
                }   
            } else {
                String sql = "SELECT id as 번호, name as 제목, genre as 장르, rentcount as 대여횟수, state as 대여상태 FROM "+ shop +" ORDER BY rentcount desc";
                try {
                    ResultSet rs = stat.executeQuery(sql);
                    ResultSetMetaData rsmd = rs.getMetaData();
                    int count = rsmd.getColumnCount();
                    lcontent.clear();
                    while( rs.next() ){
                        Vector in = new Vector();
                        for (int i = 1; i <= count; i++ ){
                            in.add(rs.getString(i));
                        }
                        lcontent.add(in);
                    }
                    rs.close();
                } catch( Exception e) {
                    e.printStackTrace();
                }   
            }
            return lcontent;
        }
        // -------------------    showListVideoDB() : 비디오 리스트 관련 출력부 ------------------------ //   
        // ------------------------------------------------------------------------------------------- //
       
        public void broadcastNotice() throws RemoteException{
            synchronized(clientList){
                Enumeration e = clientList.elements();
                while(e.hasMoreElements()) {
                    Client c = (Client)e.nextElement();
                    c.showNoticeDB();
                }
                showNoticeDB();
            }
           
        }
        public void broadcastNewVideo() throws RemoteException{
            synchronized(clientList){
                Enumeration e = clientList.elements();
                while(e.hasMoreElements()){
                    Vector in = new Vector();
                    Client c = (Client)e.nextElement();
                    c.showNewVideoDB();
                }
            }
        }
       
        // ---------------------    showFavoriteVideo() : 인기 비디오 관련 전체 출력부 -------------------- //   
        // ------------------------------------------------------------------------------------------- //
       
        public Vector broadcastFavoriteContent() throws RemoteException{
            fcontent.clear();
            synchronized(clientList){
                Enumeration e = clientList.elements();
                while(e.hasMoreElements()) {
                    Client c = (Client)e.nextElement();
                    fcontent.add(c.sendfavoriteContent());
                }                   
            }
            synchronized(clientList){
                Enumeration e = clientList.elements();
                while(e.hasMoreElements()) {
                    Client c = (Client)e.nextElement();
                    c.showFavoriteVideoDB(fcontent);
                }                   
            }
            System.out.println("집계처리 완료");
            fmodel.setDataVector(fcontent, ftitle);
            return fcontent;
        }

        public synchronized void register(Client client, String name) throws RemoteException{
            clientList.add(client);
            System.out.println(name + "지점이 접속하였습니다.");
        }
       
        public synchronized void unregister(Client client, String name) throws RemoteException{
            clientList.removeElement(client);
            System.out.println(name + " 지점이 접속을 종료하였습니다.");
        }
       
        public void close(){
            try {
                stat.close();
                con.close();
            } catch ( Exception e ){
                e.printStackTrace();
            }
        }


       
        @Override
        public void actionPerformed(ActionEvent e) {
            Object o = e.getSource();
            if ( o == nwrite ){
                noticeInsert();
               
            } else if ( o == ndel ) {
                noticeDelete();
           
            }else if ( o == fbutton ){
                try {
                    //broadcastFavorite();
                    Vector v = broadcastFavoriteContent();
                    fmodel.setDataVector(v,ftitle );
                } catch (RemoteException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
            } else if ( o == listcbox ){
                listShopChange();
               
            } else if ( o == listInsert ){
                insertVideo(returnShop());
            } else if ( o == listDelete ){
                deleteVideo(returnShop());
                try {
                    broadcastNewVideo();
                } catch (RemoteException e1) {
                    e1.printStackTrace();
                }
            }
           
        }

        //notice 관련 Query 처리 : 서버는 추가/삭제 자유롭게, 지점은 추가만 가능
        // 서버, 지점 공지사항 추가 가능 가능
        public void noticeInsert(){
            int num = incrementNum("notice");
            String sql = "INSERT INTO notice VALUES(" + num + ", '" + ntfield.getText() + "', sysdate, '" + who + "')";
            try {
                stat.executeQuery(sql);
            } catch( Exception e ){
                e.printStackTrace();
            }
            ntfield.setText("");
            try {
                showNoticeDB();
                broadcastNotice();
            } catch ( Exception e ) {
                e.printStackTrace();
            }       
        //
        }

        // 서버에서만 공지사항 삭제 가능 가능
        public void noticeDelete(){
            String num = numtfield.getText();
            String sql = "DELETE notice WHERE num ='" + num + "'";
            try {
                stat.executeUpdate(sql);
            } catch ( Exception e ){
                e.printStackTrace();
            }
            ntfield.setText("");
            numtfield.setText("");
            try {
                showNoticeDB();
                broadcastNotice();
            } catch ( Exception e ) {
                e.printStackTrace();
            }
           
        }

        //------------------------ 서버에 접속한 클라이언트들 호출하기 ---------------------//   
        //--------------   listVideo 에서 추가 버튼 눌렀을 때 발생하는 이벤트 --------------//
        public void insertVideo(String shop){
            String sql = "";
            int id = incrementNum(shop);
            String name = listTitleTfield.getText();
            String genre = listGenreTfield.getText();
            if (shop == "servervideo" ){
                sql = "INSERT INTO " + shop + " VALUES(" + id + ",'" + name + "','" + genre + "',sysdate)";
            } else {
                sql = "INSERT INTO " + shop + " VALUES(" + id +", '" + name + "','" + genre +"',0,'대여가능')";
            }
            try {
                stat.executeUpdate(sql);
                showListVideoDB(shop);
                broadcastNewVideo();
                listTitleTfield.setText("");
                listGenreTfield.setText("");
            } catch ( Exception e ) {
                e.printStackTrace();
            }
       
        }

        //listVideo에서 삭제 버튼을 눌렀을 때 발생하는 이벤트
        public void deleteVideo(String shop){
            String sql = "";
            int id = incrementNum(shop);
            String name = listTitleTfield.getText();
            String genre = listGenreTfield.getText();
            if (shop == "servervideo" ){
                sql = "DELETE " + shop + " WHERE title = '" + name + "' AND sgroup = '" + genre +"'";
            } else {
                sql = "DELETE " + shop + " WHERE name = '" + name + "' AND genre = '" + genre + "'";
            }
            try {
                stat.executeUpdate(sql);
                showListVideoDB(shop);
                listTitleTfield.setText("");
                listGenreTfield.setText("");
            } catch ( Exception e ) {
                e.printStackTrace();
            }
        }

        //listvideo listcbox 값 변경시 발생되는 이벤트.
        public void listShopChange(){
            String shop = returnShop();
            showListVideoDB(shop);
        }

        public String returnShop(){
            String shop = (String)listcbox.getSelectedItem();
            if (shop == "본사"){
                shop = "servervideo";
            } else if ( shop == "강남") {
                shop = "client1";
            } else if ( shop == "논현") {
                shop = "client2";
            } else if ( shop == "양재"){
                shop = "client3";
            }
            return shop;
        }

        //DB 등록시 최고 번호가 반환됨(조회된 것 + 1);
        public int incrementNum(String table){
            String sql = "SELECT max(id) FROM " + table;
            int num=0;
            try {
                if( table == "notice") {
                    sql = "SELECT max(num) FROM " + table;
                }
                ResultSet rs = stat.executeQuery(sql);
                rs.next();
                num = rs.getInt(1);
            } catch ( Exception e ) {
                e.printStackTrace();
            }
            return num + 1 ;
        }

        public static void main(String args[]) {
            try {
                ServerImpl s = new ServerImpl();
                Naming.rebind("rmi://61.103.103.184/video",s);
                System.out.println("Fun Video Company Server is Ready!!");
            } catch ( Exception e ) {
                e.printStackTrace();
            }
        }
       
    }

 

인터페이스 : Client.java

  • 서버에서 사용할 클라이언트 메소드들 호출
  1. /*-------------------------------------------------------------------------------------------
     *  작성일 : 2009년 6월 10일 ~ 6월 12일(2박 3일), 미니프로젝트 비디오샵 프로그램
     *     작성목적 : RMI 기능을 이용한 비디오샵 프로그램을 개발하여 RMI 와 콜백 기능을 익힌다.
     *  작성자 : 김지헌 (Honeymon, iammine@korea.com)
     * 
     *  프로그램 구성 :
     *  
     *  - 인터페이스 : Server.java, Client.java
     *  - 실행파일 : ServerImpl.java, ClientImpl.java
     * 
     *  주의사항 :
     *  
     *  - 컴파일 후, 실행파일들은 RMIC에 등록작업을 해주어야 한다.
     *  - 클라이언트 실행시 2개의 파라메터(who = 접속자, server = DB Table 명)를 필요로 한다.
     *      ex) java ClientImpl 양재 client3
     *  - 서버와 클라이언트 간에 주고받는 자료는 Vector로 구성된다.
     --------------------------------------------------------------------------------------------*/
    import java.rmi.*;
    import java.util.Vector;

    public interface Client extends Remote {
        public void showNoticeDB() throws RemoteException;
        public Vector sendfavoriteContent() throws RemoteException;
        public void showFavoriteVideoDB(Vector v) throws RemoteException;
        public void showNewVideoDB() throws RemoteException;
        public void showListVideoDB(String shop) throws RemoteException;
    }

 

원격접속 클라이언트 : ClientImpl.java

  1. import java.awt.BorderLayout;
    import java.awt.Window;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    import java.rmi.*;
    import java.rmi.server.*;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.ResultSetMetaData;
    import java.sql.Statement;
    import java.util.Vector;

    import javax.swing.JButton;
    import javax.swing.JComboBox;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JPasswordField;
    import javax.swing.JScrollPane;
    import javax.swing.JTabbedPane;
    import javax.swing.JTable;
    import javax.swing.JTextField;
    import javax.swing.SingleSelectionModel;
    import javax.swing.event.ChangeEvent;
    import javax.swing.event.ChangeListener;
    import javax.swing.table.DefaultTableModel;

    public class ClientImpl implements Client, ActionListener {
        private String url = "jdbc:oracle:thin:@61.103.103.184:1521:cjedu";
        private String user = "scott";
        private String passwd = "tiger";
        private DefaultTableModel nmodel, newmodel, fmodel, lmodel;
        private Vector ntitle = new Vector();
        private Vector ncontent = new Vector();
        private Vector newtitle = new Vector();
        private Vector newcontent = new Vector();
        private Vector ftitle = new Vector();
        private Vector fcontent = new Vector();
        private Vector ltitle = new Vector();
        private Vector lcontent = new Vector();
        private JTextField ntfield, listTitleTfield, listGenreTfield;
        private JButton nwrite, nedit, ndel, listInsert, listDelete, fbutton, rent, receive;
        private JComboBox listcbox;
        private String server, selectNum, state, selectNo;
        private JTable ntable,ltable;
        private JTextField numtfield, idt;
        private JPasswordField pw;
        private JButton login;
        private JPanel cpane;
        private int rentcount;
        final String who;
        Server s;
       
        Connection con;
        Statement stat;
        private JButton retry;
       
           
        public ClientImpl(final String who, String server) throws RemoteException {
           
            try {
                UnicastRemoteObject.exportObject(this);
                s = (Server)Naming.lookup("rmi://61.103.103.184/video");
                s.register(this, who);
            } catch ( Exception e ) {
                e.printStackTrace();
            }
            this.who = who;
            this.server = server;
            database();
            makeGui();
           
           
        }
       

        //DB연결관련 처리
        public  void database(){
            try {
                Class.forName("oracle.jdbc.driver.OracleDriver");
                con = DriverManager.getConnection( url, user, passwd );
                stat = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
            } catch( Exception e) {
                e.printStackTrace();
            }
        }
       
        public void makeGui() throws RemoteException{
            JFrame frame = new JFrame(who + "점 Video SHOP");
            frame.pack();
            //frame.setDefaultCloseOperation(3);
            frame.setSize(800,800);
            frame.setVisible(true);       
            final JTabbedPane tab = new JTabbedPane();
            frame.add(tab);
            //창이 닫힐 경우 자원들을 종료하는 Listner
            frame.addWindowListener(new WindowAdapter() {
                public void windowClosing(WindowEvent x){
                   try {
                   Window w = (Window)x.getSource();
                   w.setVisible(false);
                   w.dispose();//화면에 썼던 자원을 해지하는것.
                   s.unregister(ClientImpl.this, who);
                     close();
                   System.exit(0); //프로세스 종료
                   }catch(Exception e){}
                  }
             });

           
            //noticePanel
            nmodel = new DefaultTableModel();
            ntable = new JTable(nmodel);
            JScrollPane nspane = new JScrollPane(ntable);
            //nmodel.setDataVector(dataVector, coflumnIdentifiers);
            //DB 연동해주기.
            ntable.addMouseListener(new MouseAdapter() {
                public void mouseClicked(MouseEvent m){
                    int row = ntable.getSelectedRow();
                    Vector in = (Vector)ncontent.elementAt(row);
                    numtfield.setText((String)in.elementAt(0));
                    ntfield.setText((String)in.elementAt(1));
                   
                }
            });
            showNoticeDB();
            JLabel numlabel = new JLabel("번호");
            numtfield = new JTextField(3);
            JLabel nlabel = new JLabel("내용");
            ntfield = new JTextField(30);
            nwrite = new JButton("작성");
            nwrite.addActionListener(this);
           
            JPanel noticePanel = new JPanel();
            noticePanel.add(numlabel);
            noticePanel.add(numtfield);
            noticePanel.add(nlabel);
            noticePanel.add(ntfield);
            noticePanel.add(nwrite);
                           
            JPanel notice = new JPanel();
            notice.setLayout(new BorderLayout());
            notice.add(nspane, "Center");
            notice.add(noticePanel, "South");
           

           
            //newVideo Panel
            newmodel = new DefaultTableModel();
            JTable newtable = new JTable(newmodel);
            JScrollPane newspane = new JScrollPane(newtable);
            //newmodel.setDataVector(dataVector, columnIdentifiers);
            showNewVideoDB();
           
            JPanel newVideo = new JPanel();
            newVideo.setLayout(new BorderLayout());
            newVideo.add(newspane, "Center");
           
           
            //favoriteVideo Panel
            fmodel = new DefaultTableModel();
            JTable ftable = new JTable(fmodel);
            JScrollPane fspane = new JScrollPane(ftable);
            //fmodel.setDataVector(dataVector, columnIdentifiers);
           
            JPanel favoritePanel = new JPanel();
            favoritePanel.setLayout(new BorderLayout());
            fbutton = new JButton("집계");
            fbutton.addActionListener(this);
            favoritePanel.add(fbutton, "East");
           
            JPanel favoriteVideo = new JPanel();
            favoriteVideo.setLayout(new BorderLayout());
            favoriteVideo.add(fspane, "Center");
            favoriteVideo.add(favoritePanel, "South");
           
           
            //listVideo Panel
            lmodel = new DefaultTableModel();
            ltable = new JTable(lmodel);
            JScrollPane lspane = new JScrollPane(ltable);
            //lmodel.setDataVector(dataVector, columnIdentifiers);
            showListVideoDB(server);
            ltable.addMouseListener(new MouseAdapter() {
                public void mouseClicked(MouseEvent m){
                    int row = ltable.getSelectedRow();
                    Vector in = (Vector)lcontent.elementAt(row);
                    selectNum = (String)in.elementAt(0);
                    rentcount  = Integer.parseInt((String)in.elementAt(3));
                    state = (String)in.elementAt(4);
                }
            });
           
            JPanel listPanel = new JPanel();
            rent = new JButton("대여");
            receive = new JButton("반납");
            retry = new JButton("다시 읽기");
            rent.addActionListener(this);
            receive.addActionListener(this);
            retry.addActionListener(this);
            listPanel.add(rent);
            listPanel.add(receive);
            listPanel.add(retry);
           
           
            JPanel listVideo = new JPanel();
            listVideo.setLayout(new BorderLayout());
            listVideo.add(lspane, "Center");
            listVideo.add(listPanel, "South");
           
                   
            //tab.add() 1. notice, 2.newViedo 3.favoriteVideo 4.ListVideo
            tab.add(notice,"공지사항");
            tab.add(newVideo,"신작비디오");
            tab.add(favoriteVideo, "인기비디오");
            tab.add(listVideo, "비디오목록");
         
              
             tab.getModel().addChangeListener(
                new ChangeListener() {
                   public void stateChanged(ChangeEvent e) {
                   SingleSelectionModel model = (SingleSelectionModel) e.getSource();
                   if(model.getSelectedIndex() == tab.getTabCount()-1) {
                   }
                   }
                }
             );
            
        }
       
        // ------------------------------------------------------------------------------------------- //   
        // ---------------------   showNoticeDB() : 공지사항 관련 출력부 ----------------------------- //
       
        public synchronized void showNoticeDB() throws RemoteException {
            ntitle = s.noticeTitle();
            ncontent = s.noticeContent();
            nmodel.setDataVector(ncontent, ntitle);
        }

        // ---------------------   showNoticeDB() : 공지사항 관련 출력부 ----------------------------- //
        // ------------------------------------------------------------------------------------------- //
       
       
       
        // ------------------------------------------------------------------------------------------- //
        // ---------------------    showNewVideoDB() : 신작 비디오 관련 출력부 ----------------------- //
       
        public synchronized void showNewVideoDB() throws RemoteException{
            try {
            newcontent.clear();
            newtitle.clear();
            newtitle = s.newTitle();
            newcontent = s.newContent();
            newmodel.setDataVector(newcontent, newtitle);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        // ------------------------------------------------------------------------------------------- //
        // ---------------------    showFavoriteVideo() : 인기 비디오 관련 출력부 -------------------- //

        public void showFavoriteVideoDB(Vector v) throws RemoteException  {
            //System.out.println("집계된 자료 가져가겠음");
        ftitle.clear();
        ftitle = s.favoriteTitle();
        //    System.out.println("집계제목 수신중");
        //    fcontent = s.favoriteContent();
        //    System.out.println("집계자료 전송중");
           
            fmodel.setDataVector(v, ftitle);
        }
       
       
        public Vector sendfavoriteContent()throws RemoteException  {
            fcontent.clear();
            String sql = "SELECT id, name, genre FROM " + server + " where rentcount = (SELECT max(rentcount) FROM " + server + ")";
            try {
                ResultSet rs = stat.executeQuery(sql);
                ResultSetMetaData rsmd = rs.getMetaData();
                int count = rsmd.getColumnCount();
                rs.next();
                           
                for ( int i = 1; i <= count ; i++ ){
                    fcontent.add(rs.getString(i));           
                }
                fcontent.add(who);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return fcontent;
        }
       
        // ---------------------    showFavoriteVideo() : 인기 비디오 관련 출력부 -------------------- //   
        // ------------------------------------------------------------------------------------------- //
       
       
       
       
        // ------------------------------------------------------------------------------------------- //
        // -------------------    showListVideoDB() : 비디오 리스트 관련 출력부 ------------------------ //   
        public void showListVideoDB(String shop){
            lcontent.clear();
            ltitle.clear();
            ltitle = listTitle(shop);
            lcontent = listContent(shop);
            lmodel.setDataVector(lcontent, ltitle);
        }
       
        public Vector listTitle(String shop){
            String sql = "SELECT id as 번호, name as 제목, genre as 장르, rentcount as 대여횟수, state as 대여상태 FROM "+ shop +" ORDER BY rentcount desc";
                try {
                    ResultSet rs = stat.executeQuery(sql);
                    ResultSetMetaData rsmd = rs.getMetaData();
                    int count = rsmd.getColumnCount();
                    for ( int  i = 1 ; i <= count ; i++ ){
                        Vector in = new Vector();
                        String t = rsmd.getColumnName(i);
                        in.add(t);
                        ltitle.add(in);
                    }   
                } catch ( Exception e ){
                    e.printStackTrace();
                }       
            return ltitle;
        }
       
        public Vector listContent(String shop){
            String sql = "SELECT id as 번호, name as 제목, genre as 장르, rentcount as 대여횟수, state as 대여상태 FROM "+ shop +" ORDER BY rentcount desc";
                try {
                    ResultSet rs = stat.executeQuery(sql);
                    ResultSetMetaData rsmd = rs.getMetaData();
                    int count = rsmd.getColumnCount();
                    lcontent.clear();
                    while( rs.next() ){
                        Vector in = new Vector();
                        for (int i = 1; i <= count; i++ ){
                            in.add(rs.getString(i));
                        }
                        lcontent.add(in);
                    }
                    rs.close();
                } catch( Exception e) {
                    e.printStackTrace();
                }   
            return lcontent;
        }
        // -------------------    showListVideoDB() : 비디오 리스트 관련 출력부 ------------------------ //   
        // ------------------------------------------------------------------------------------------- //
       
       
       
        //notice 관련 Query 처리 : 서버는 추가/삭제 가능, 지점은 추가만 가능
        public void noticeInsert(){
            int num = incrementNum("notice");
            String sql = "INSERT INTO notice VALUES(" + num + ", '" + ntfield.getText() + "', sysdate, '" + who + "')";
            try {
                stat.executeQuery(sql);
            } catch( Exception e ){
                e.printStackTrace();
            }
            ntfield.setText("");
            try {
                s.broadcastNotice();
            } catch ( Exception e ) {
                e.printStackTrace();
            }
        }
       
        public int incrementNum(String table){
            String sql = "SELECT max(id) FROM " + table;
            int num=0;
            try {
                if( table == "notice") {
                    sql = "SELECT max(num) FROM " + table;
                }
                ResultSet rs = stat.executeQuery(sql);
                rs.next();
                num = rs.getInt(1);
            } catch ( Exception e ) {
                e.printStackTrace();
            }
            return num + 1 ;
        }
       
        public void close(){
            try {
                stat.close();
                con.close();
            } catch ( Exception e ){
                e.printStackTrace();
            }
        }
       
       
        //listVideo에서 대여 버튼을 눌렀을 때 발생하는 이벤트
        public void rentVideo(){
            if (state.equals("대여가능")){
                String sql = "UPDATE " + server + " SET state = '대여중', rentcount = "+ (rentcount + 1) +" WHERE id = "+ selectNum;
                try {
                    stat.executeUpdate(sql);
                    showListVideoDB(server);
                } catch ( Exception e ) {
                    e.printStackTrace();
                }
            }
           
        }

        //listVideo에서 반납 버튼을 눌렀을 때 발생하는 이벤트
        public void receiveVideo(){
            if (state.equals("대여중")){
                String sql = "UPDATE " + server +" SET state = '대여가능' WHERE id = "+ selectNum;
                try {
                    stat.executeUpdate(sql);
                    showListVideoDB(server);
                } catch ( Exception e ) {
                    e.printStackTrace();
                }
            }
        }
       


       
        @Override
        public void actionPerformed(ActionEvent e) {
            Object o = e.getSource();
            if ( o == nwrite ){
                noticeInsert();
                try {
                    s.broadcastNotice();
                } catch (Exception ex){
                    ex.printStackTrace();
                }
            }else if ( o == fbutton ){
                    try {
                        s.broadcastFavoriteContent();
                    } catch (RemoteException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
            } else if ( o == rent ){
                rentVideo();
            } else if ( o == receive ){
                receiveVideo();
            } else if ( o == retry ){
                showListVideoDB(server);
            }
           
           
        }
       
        public static void main(String args[]) {
            try {
                String who = args[0];
                String server = args[1];
                ClientImpl c = new ClientImpl(who, server);
            } catch ( Exception e ) {
                e.printStackTrace();
            }
        }   
    }

 

ServerImpl 실행화면

ClientImpl 실행화면

 

ServerImplFavoriteex.jpg ServerImplFavoriteUnex.jpg ServerImplList.jpg ServerImplListSelcect.jpg ServerImplNew.jpg

 

ServerImplNotice.jpg ClientImplFavorite.jpg ClientImplList.jpg ClientImplNew.jpg ClientImplNotice.jpg

 

 

 

 


제일 어려웠던 부분은, 인기비디오 목록 처리 부분.


처음에는 인기비디오 수집시, synchronized 처리로 인한 락이 걸리면서 작업이 중지되는 현상을 보였다.

이를 해결하기 위해 하나의 메소드 안에서 자료 수집과 뿌려주는 작업을 순차적으로 진행시키도록 하였다.


화면구성 자체는 간결하다.


추후에 유사한 작업을 진행할 때에는, 각 화면별 구성과 컴포넌트들의 이름을 기록하고 이를 구분하기 쉽도록 해야겠다.

스스로 해결하지 못해서, 선생님께 조언을 구했다. 어려울 때 도움을 요청할 수도 있겠지만, 스스로 깊게 사색하고,

문제점을 찾아 해결할 수 있는 능력을 길러보도록 하자. 너는 할 수 있다. ㅡㅅ-)b

이 글은 스프링노트에서 작성되었습니다.

  1. JTextArea display = new JTextArea();
                int row = display.getLineEndOffset(display.getLineCount());
                display.setCaretPosition(row);

 

 

javax.swing 클래스 JTextArea

getLineOfOffset

public int getLineOfOffset(int offset)  throws BadLocationException 

컴퍼넌트 텍스트의 오프셋(offset)를 행 번호로 변환합니다.

파라미터:
offset - 오프셋(offset) >= 0
반환값:
행 번호 >= 0
예외:
BadLocationException - 오프셋(offset)가 0 보다 작은 경우, 또는 문서의 길이보다 큰 경우

 

javax.swing.text 클래스 JTextComponent

setCaretPosition

public void setCaretPosition(int position)
TextComponent 의 텍스트 삽입 caret의 위치를 설정합니다. TextComponent 의 텍스트 삽입 caret의 위치를 설정합니다. caret는 변경을 추적하므로, 컴퍼넌트의 기본이 되는 텍스트가 변경와 이것도 이동하는 것에 주의해 주세요. 문서가 null 의 경우에는 아무것도 실시하지 않습니다. 위치는 0 으로 컴퍼넌트 텍스트의 길이와의 사이가 아니면 안되어, 그렇지 않은 경우는 예외가 throw 됩니다.

파라미터:
position - 위치
예외:
IllegalArgumentException - position 로 지정한 값이 0 미만, 또는 컴퍼넌트 텍스트보다 긴 경우

이 글은 스프링노트에서 작성되었습니다.

Server.java

  1. import java.rmi.*;

    public interface Server extends Remote{

        public void send(String msg) throws RemoteException;
        public void register(Client client, String name) throws RemoteException;   
        public void unregister(Client client, String name) throws RemoteException;   
    }

 

ServerImpl.java

  1. import java.rmi.server.*;
    import java.rmi.*;
    import java.util.*;

    public class ServerImpl extends UnicastRemoteObject implements Server {
        Vector clientList;

        public ServerImpl() throws RemoteException {
            super();
            clientList = new Vector();
        }

        public synchronized void register(Client client, String name) throws RemoteException {
            clientList.add(client);
            send(name + "님이 입장하셨습니다.");
        }

        public void send(String msg) throws RemoteException {
            synchronized(clientList) {
                Enumeration e = clientList.elements();
                while( e.hasMoreElements() ) {
                    Client c = (Client)e.nextElement();
                    c.back(msg);
                }
            }
        }

        public synchronized void unregister(Client client, String name) throws RemoteException {
            clientList.removeElement(client);
            send(name + "님이 퇴장하셨습니다.");
        }

        public static void main(String[] args) {
            try {
                ServerImpl s = new ServerImpl();
                Naming.rebind("rmi://61.103.103.184/chat", s);
                System.out.println("RMI Chat Server is ready.");
            } catch ( Exception e ) {
                e.printStackTrace();       
            }

        }
    }

 

Client.java

  1. import java.rmi.*;

    public interface Client extends Remote {
        public void back(String msg) throws RemoteException ;
    }

 

ClientImpl.java

  1. import java.awt.*;
    import java.awt.event.*;
    import java.rmi.Naming;
    import java.rmi.server.UnicastRemoteObject;

    import javax.swing.*;

    public class ClientImpl extends JFrame implements Client, ActionListener {
        JTextArea display, display2;
        JTextField input, id;
        JLabel label, nick;
        Server    server;
        JButton    register, close, enter, clear;
        String name, serverName;
        CardLayout card;
        JPanel npanel;
       
        public ClientImpl() {
            super("RMI 채팅");

            Container c = getContentPane();
            c.setLayout(new BorderLayout());

            display = new JTextArea();
            display.setEditable(false);
            JScrollPane spane = new JScrollPane(display);
            c.add(spane, "Center");

            npanel = new JPanel();
            card = new CardLayout();
            npanel.setLayout(card);

            label = new JLabel("대화명 : ");
            id = new JTextField(10);
            register = new JButton("등록");
            register.addActionListener(this);
            close = new JButton("종료");
            close.addActionListener(this);
            JPanel loginPanel = new JPanel();
           
            loginPanel.add(label);
            loginPanel.add(id);
            loginPanel.add(register);
            loginPanel.add(close);


            nick = new JLabel("즐팅!!");
            input = new JTextField(10);
            input.addActionListener(this);
            enter = new JButton("입력");
            enter.addActionListener(this);
            clear = new JButton("지우기");
            clear.addActionListener(this);
            JPanel chatPanel = new JPanel();

            chatPanel.add(nick);
            chatPanel.add(input);
            chatPanel.add(enter);
            chatPanel.add(clear);

            npanel.add(loginPanel, "login");
            npanel.add(chatPanel, "chat");
            c.add(npanel, "North");

            card.show(npanel, "login");   

            addWindowListener(new WindowAdapter() {
                public void windowClosing(WindowEvent e) {
                    setVisible(false);
                    if ( server != null ) {
                        try {
                            server.unregister(ClientImpl.this, name);
                        } catch ( Exception ee ) {
                            ee.printStackTrace();
                        }
                    }
                    dispose();
                    System.exit(0);
                }
            });
            setDefaultCloseOperation(EXIT_ON_CLOSE);
            setSize(400,500);
            setVisible(true);
        }
       
        private void connect(){
            try {
                UnicastRemoteObject.exportObject(this);
                server = (Server)Naming.lookup("rmi://61.103.103.184/chat");
                server.register(this, name);
            } catch ( Exception e ) {
                e.printStackTrace();
            }
        }
       
        public synchronized void back(String msg){
            try {
                display.append(msg + "\n");
            } catch (Exception e) {
                display.append(e.toString());
            }
        }
       
        public void actionPerformed(ActionEvent e){
            Object o = e.getSource();

            if ( o == register ) {
                name = id.getText().trim();
                card.next(npanel);
                connect();
                nick.setText(name+"님, 즐팅!!");
            } else if ( o == input || o == enter ) {
                try {
                    server.send(name + " : " + input.getText());
                    input.setText("");
                } catch ( Exception ex ) {
                    display.append(ex.toString());   
                }
            } else if ( o == clear ) {
                display.setText("");
            } else if ( o == close ) {
                System.exit(0);
            }

        }
       
        public static void main(String[] args)     {
            new ClientImpl();
        }
    }

첫 실행화면

ClientImplNickInput.JPG

대화명 입력 후 화면

ClientImplNickInputAfter.JPG

다른이가 입장하였을 경우의 화면

OtherUserEnter.JPG

유저가 퇴장하였을 때 화면

OtherUserGetOut.JPG  

이 글은 스프링노트에서 작성되었습니다.

+ Recent posts