티스토리 뷰


이번 포스팅에서는

앞서 설계한 회원가입을 이용해서

실제 프로그램에 접속하기 위한

로그인 기능을 구현해보도록 하겠습니다.


==============================================================================


Rhythm Game : Login





1. Rhythm Game : ClientUI.java


먼저 ClienUI에서 로그인 버튼을 눌렀을 때 호출할 리스너를 정의합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package client;
 
import java.awt.event.ActionListener;
...
 
public class ClientUI extends JFrame{
    
    ...
 
    private void addListeners() {
        
        ...
 
        ActionListener blgh = new BtLoginHandler(this);
        pnLogin.btlogin.addActionListener(blgh);
    }
 
    ...
}
 
cs





2. Rhythm Game : BtLoginHandler.java


 ClientUI의 로그인버튼에 리스너를 정의했다면 해당 리스너가 작동할 클래스를 설계해야합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package handler;
 
import java.awt.event.ActionEvent;
 
 ...
 
public class BtLoginHandler implements ActionListener{
 
    ClientUI ui;
    public BtLoginHandler(ClientUI c) {
        ui = c;
    }
 
    @Override
    public void actionPerformed(ActionEvent e) {
        // 입력한 아이디와 비밀번호를 서버로 전송 =============================
        String nick = ui.pnLogin.tfid.getText().trim();
        String pass = String.valueOf(ui.pnLogin.tfpw.getPassword()).trim();
        ui.net.sendLoginRequest(nick, pass);
        // =================================================================
    }
}
cs






3. Rhythm Game : ClientNetwork.java


 사용자가 입력한 아이디와 비밀번호를 통해 리스너 호출까지 완료되었다면 이제 ClientNetwork에서 서버로 TCP를 통해 넘겨주면 됩니다.

서버로 넘겨줄 데이터는 join#id#pw의 형태로 넘겨주게 되고 서버로 부터 요청에 따른 결과값을 얻게 된다면 결과 값에 따라 동작하게 됩니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package client;
 
import java.io.IOException;
...
 
public class ClientNetwork extends Thread {
    
    ...
 
    private String nick;    // 사용자의 id를 저장하기 위한 변수
 
    ...
    
    // 로그인 요청
    public void sendLoginRequest(String nick, String pass) {
        this.nick = nick;
        String resp = null;
        System.out.println("[client] request : ");
 
        // 아이디와 비밀번호의 공백 체크 ===========================================
        if (nick.trim().equals(""|| pass.trim().equals("")) {
            JOptionPane.showMessageDialog(ui, "아이디와 비밀번호를 입력하세요.");
            return;
        }
        // =======================================================================
 
        synchronized (oos) {
            try {
                // 서버로 요청 =========================================
                oos.writeObject("join#" + nick + "#" + pass);
 
                // 서버로부터 결과 값 읽어옴
                resp = (String) ois.readObject();
                System.out.println("[client] response : " + resp);
 
                // 결과 값에  ui 제어.
                String[] data = resp.split("#");
                if (data[0].equals("true")) {
                    System.out.println("come");
                    ui.pnLogin.tfid.setText("");
                    ui.pnLogin.tfpw.setText("");
                    ui.setSize(800800);
                    ui.setTitle("Drop the beat!! - Wating Room");
                    ui.setLocationRelativeTo(null);
                    ui.setContentPane(ui.pnRoom);
                    ui.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
                    sendStateRoomRequest();
                    sendMessageStateRequest();
                } else {
                    ui.pnLogin.tfid.setText("");
                    ui.pnLogin.tfpw.setText("");
                    JOptionPane.showMessageDialog(ui, data[1]);
                }
 
            } catch (ClassNotFoundException | IOException e) {
                System.out.println("[client] network error " + e.toString());
            }
        }
    }
    
    ...
    
}
cs






4. Rhythm Game : PersonalServer.java


 회원가입에서와 마찬가지로 로그인할 때는 클라이언트로부터 join#~ 의 형태로 데이터가 날라오기때문에 '#'으로 문자열을 구분하여 데이터를 판단합니다.


로그인하기 위해 accountPool 변수에 login() 메소드를 정의해서 인자로 아이디, 비밀번호와 로그인을 시도하는 socketAddress를 넘겨줍니다.

로그인의 성공 / 실패 / 실패 원인에 대한 결과가 문자열로 넘어오게 되고, 이 결과를 나중에 사용하기 편하게 user 변수에 저장해둡니다.


이렇게 나온 result를 다시 TCP를 통해 클라이언트에게 전송하게 됩니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package server;
 
import java.io.IOException;
 
...
 
public class PersonalServer extends Thread {
    
    ...
 
    private Account user;        //  현재 계정 객체 저장
    
    ...
 
    @Override
    public void run() {
        String[] command = null;
        while(socket.isConnected()) {
            
            ...
 
            switch(command[0]) {
                
                ...
 
                case "join":            // 로그인
                    String result = accountPool.login(command[1], command[2], socket.getRemoteSocketAddress());
                    user = accountPool.getAccountMap().get(command[1]);
                    sendToClient(result);
            }
        }
    }
}
 
cs






5. Rhythm Game : UserAccountPool.java


 이제 실질적으로 accountPool에서 로그인처리가 되도록 기능을 정의하면 됩니다.


전달된 아이디, 비밀번호, SocketAddress 3개의 인자를 가지고 로그인 동작을 진행하게 되는데 순서는 다음과 같습니다.


1. 아이디가 회원가입되어 있는 상태인지 확인합니다.

2. 현재 접속중인 아이디인지 확인합니다.

3. 아이디와 비밀번호가 일치하는지 확인합니다.

4. 성공이라면 현재 유저에 해당 계정을 저장하고 해당 유저의 계정에 SocketAddress를 저장합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package server;
 
import java.io.File;
...
 
public class UserAccountPool {
    
    ...
    
    public String login(String id, String pass, SocketAddress sa) {        // 로그인 
        if(accountMap.containsKey(id)) {
            if(!currentUser.contains(new Account(id, """"))) {
                if(accountMap.get(id).getPass().equals(pass)) {
                    currentUser.add(accountMap.get(id));
                    accountMap.get(id).setSocketAddress(sa);
                    return "true";
                }else {
                    return "false#비밀번호가 일치하지 않습니다.";
                }
            } else {
                return "false#이미 접속중인 아이디입니다.";
            }
        } else {
            return "false#존재하지 않는 아이디입니다.";
        }
    }
    
    ...
 
}
 
cs



 다음과 같이 설계한다면 서버에서 클라이언트로 넘어가는 데이터는 #으로 구분되어 String 형태로 넘어가게 됩니다.

 '#'으로 구분되어 첫번째 인자는 성공 / 실패의 결과, 두번째 인자는 실패의 원인이 넘어가게 됩니다.





## 회원가입 기능에 대한 클래스 동작 흐름.

(Client) LoginPanel에서의 로그인 버튼 호출 -> (Client) 버튼에 저장된 리스너 호출 -> (Client) 클라이언트에서 서버로 요청

 -> (Server) 로그인처리에 대한 결과를 다시 클라이언트에게 전송 -> (Client) 서버로부터 넘어온 결과에 대한 동작 처리


 로그인 성공시 -> RoomPanel로 이동

 로그인 실패시 -> 로그인 실패에 대한 원인을 다이얼로그로 출력


공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함