Servlet/JSP로 사용자 관리 시스템 구현하기 과정 - 3
JSP/Servlet과JSP로 사용자 관리 시스템 구현

Servlet/JSP로 사용자 관리 시스템 구현하기 과정 - 3

반응형

Servlet/JSP로 사용자 관리 시스템 구현하기 과정 


강의 링크 : https://www.slipp.net/wiki/pages/viewpage.action?pageId=25526852


큰 홈페이지 틀을 만들었던 지난 시간에 이어서, 이번 시간에는 실제 로그인에 필요한 유저의 값들을 어떻게 저장하고 활용하는지 알아보도록 하겠습니다.


회원가입 창에서 볼 수 있듯이, 가입에 필요한 정보는 아이디, 비밀번호, 이름, 이메일 총 4가지입니다.


이 정보를 저장할 User 클래스와 데이터베이스 클래스를 만들도록 합시다.

(추후에 유지보수를 위해서 각 클래스는 다른 패키지로 저장하는 것이 좋습니다.)


우선 완성된 코드들은 아래와 같습니다.



User.java

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
package net.slipp.user;
 
import net.slipp.db.Database;
 
public class User {
    private String userId;
    private String password;
    private String name;
    private String email;
    
    public User(String userId, String password, String name, String email) {
        super();
        this.userId = userId;
        this.password = password;
        this.name = name;
        this.email = email;
    }
    
    public String getUserId() {
        return userId;
    }
    
    public String getPassword() {
        return password;
    }
    
    public String getName() {
        return name;
    }
 
    public String getEmail() {
        return email;
    }
    public boolean matchPassword(String newPassword) {
        
        return this.password.equals(newPassword);
    }
    public static boolean login(String userId, String password) throws UserNotFoundException, PasswordMismatchException {
        User user = Database.findByUserId(userId);
        
        if(user == null){
            throw new UserNotFoundException();
        }
        
        if(!user.matchPassword(password)){
            throw new PasswordMismatchException();
        }
        
        return true;
    }
 
    @Override
    public String toString() {
        return "User [userId=" + userId + ", password=" + password + ", name=" + name + ", email=" + email + "]";
    }
 
 
}
 
cs


User 클래스에서 아이디, 비밀번호, 이름, 이메일을 저장할 변수를 만들어줍니다.


생성자를 만들어주고, 변수에 대해 각각 나중에 값을 받아올 get함수도 만듭니다. 


(해당 클래스에서 작성 중에 오른쪽 마우스 클릭 - source를 들어가면 getter and setter를 만들 수 있는 기능이 있습니다. 여기서 getter만 지정하고 필요한 변수를 체크한 뒤 finish하면 자동으로 생성해주는 편리한 기능을 이용할 수 있습니다!)


오버라이드한 toString 메소드는, 제대로 값을 받아오는 지 확인하기 위해서 만들어놨습니다.


그리고 boolean형으로 만들어진 두 함수는 아래와 같습니다.


public boolean matchPassword(String newPassword) {
        
        return this.password.equals(newPassword);
    }
    public static boolean login(String userId, String password) throws UserNotFoundException, PasswordMismatchException {
        User user = Database.findByUserId(userId);
        
        if(user == null){
            throw new UserNotFoundException();
        }
        
        if(!user.matchPassword(password)){
            throw new PasswordMismatchException();
        }
        
        return true;
    }


matchPassword는 로그인을 할 때 패스워드가 맞는지 확인하는 것이고, login은 아이디와 패스워드를 가져와 제대로 입력됐는지 확인하는 메소드입니다. 


오류가 났을 때는 각각 조건문에서 throw로 예외처리를 던져주면서 이에 맞는 에러를 표시하도록 만들어준건데 이는 login에 대한 jsp 파일을 살펴보면서 다시 설명하도록 하겠습니다.




Database.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package net.slipp.db;
 
import java.util.HashMap;
import java.util.Map;
 
import net.slipp.user.User;
 
public class Database {
    private static Map<String, User> users = new HashMap<String, User>(); 
 
    public static void addUser(User user){
        System.out.println("user : " + user);
        users.put(user.getUserId(), user);
    }
 
    public static User findByUserId(String userId) {
        // TODO Auto-generated method stub
        return users.get(userId);
    }
}
 
cs


데이터베이스는 map과 hashmap으로 User의 데이터를 가져오는 걸 확인할 수 있습니다.


기본적으로 java에서 map은 key와 value로 구성되어 있습니다. 우리는 User에서 2개 이상의 변수를 가지고 있기 때문에 value 값으로 하나의 변수가 아닌 User 클래스를 넣어 가져오는 것을 볼 수 있습니다. (필요한 변수가 많을 때는 이처럼 클래스나 구조체로도 map을 통해 가져올 수 있습니다.)



데이터베이스 클래스에서는 static으로 두가지 메소드를 만들었습니다.



public static User findByUserId(String userId) {
        // TODO Auto-generated method stub
        return users.get(userId);
    }


다음으로 작성된 findByUserId 메소드는, 로그인 시 아이디를 체크하기 위한 것입니다. 이는 로그인 체크할 때 사용되는데 유저의 Id의 값을 가져와 존재하는 아이디인지 확인하는 역할을 합니다. 로그인 체크 기능을 확인할 때 한번 더 언급하도록 하고 넘어가겠습니다.




public static void addUser(User user){
        System.out.println("user : " + user);
        users.put(user.getUserId(), user);
}


회원가입을 통해 user가 생성되면, 이 addUser 함수를 추가해 값을 저장하도록 하고 있습니다.

user를 출력하는 문장은, 자동으로 user 클래스에 있는 toString 함수를 실행시킵니다. 이는 eclipse의 콘솔 창을 통해서 회원가입된 정보가 출력되는 모습을 확인할 수 있습니다.


 

이처럼 회원가입을 완료할 때 마다, 콘솔창에 toString 메소드 출력 결과가 나타납니다.


이어서 hashmap에 put을 통해 user의 아이디를 key로, user의 전체 내용을 value로 저장하는 모습을 볼 수 있습니다.




그렇다면 이 함수는 어디서 적용해야 할까요? 

form에서 입력한 회원가입 창은 완료 버튼을 누르면 action을 통해 form_action.jsp로 전송됩니다. 따라서 이 곳에서 활용해야 합니다.


form_action.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
    
<%@ page import="net.slipp.user.User" %>
<%@ page import="net.slipp.db.Database" %>
 
<% 
    request.setCharacterEncoding("UTF-8");
    response.setContentType("text/html;charset=UTF-8"); // 한글 깨지지 않도록
 
    String userId = request.getParameter("userId");
    String password = request.getParameter("password");
    String name = request.getParameter("name");
    String email = request.getParameter("email");
 
    User user = new User(userId, password, name, email);
    Database.addUser(user);
    
    response.sendRedirect("/"); // 메인페이지로 다시 이동
%>
 
cs


User 클래스와 Database 클래스를 사용하려면, page import를 통해 해당 패키지명을 설정하면 됩니다.


String 변수를 만들고, 각 User가 가진 변수를 request.getParameter를 통해 값을 가져옵니다.



이제 이 값을 기존에 만들어두었던 User와 Database 클래스를 이용할 차례입니다!


 User user = new User(userId, password, name, email);
 Database.addUser(user);


User 클래스로 가져온 변수 값을 통해 생성자를 만듭니다.

그리고 addUser 메소드로 데이터베이스에 이 값을 넣어주도록 합니다.


이제 이 값을 저장해뒀기 때문에 서버가 재시작되지 않는 한 로그인할 시 적용할 수 있습니다.

(실제로 홈페이지를 구현하려면, 서버가 꺼져도 유저 데이터 값을 유지시켜야 합니다. 따라서 실제 데이터베이스를 이용할 것이지만, 지금은 흐름을 알기위한 과정이라고 생각하면 됩니다!)


마지막으로 response.sendRedirect는 해당 location으로 이동하도록 만들어줍니다. "/"로 지정하면서 home 메인 화면으로 바로 넘어갈 수 있도록 구현되어있습니다.


즉, form에서 회원가입 내용을 모두 작성하고 가입버튼을 누르면 form_action으로 넘어와 입력된 값을 데이터베이스에 저장한 후 다시 메인화면 페이지를 보여주는 과정을 나타낸다고 정리할 수 있겠습니다!




이제 로그인 화면을 구성해봅시다~


login.jsp

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
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
 
<%@ include file="../commons/_head.jspf" %>
 
</head>
<body>
    <%@ include file="../commons/_top.jspf" %>
 
    <div class="container">
        <div class="row">
            <div class="span12">
                <section id="typography">
                <div class="page-header">
                    <h1>로그인</h1>
                </div>
                
                <form class="form-horizontal" action="login_action.jsp" method="post">
                    <%
                        Object errorMessage = request.getAttribute("errorMessage");
                        if(errorMessage != null){
                    %>
                    <div class="control-group">
                        <label class="error"><%= errorMessage %></label>
                    </div>
                    <%    
                        }
                    %>
                    
                    <div class="control-group">
                        <label class="control-label" for="userId">사용자 아이디</label>
                        <div class="controls">
                            <input type="text" name="userId" value="" />
                        </div>
                    </div>
                    <div class="control-group">
                        <label class="control-label" for="password">비밀번호</label>
                        <div class="controls">
                            <input type="password" id="password" name="password" placeholder="">
                        </div>
                    </div>
                    <div class="control-group">
                        <div class="controls">
                            <button type="submit" class="btn btn-primary">로그인</button>
                        </div>
                    </div>
                </form>
            </div>
        </div>
    </div>
</body>
</html>
cs


아이디와 비밀번호를 입력하고 로그인하는 간단한 페이지입니다.


이 중에 에러가 발생했을 시 표시해주는 코드는 아래와 같습니다.

<%
                        Object errorMessage = request.getAttribute("errorMessage");
                        if(errorMessage != null){
                    %>
                    <div class="control-group">
                        <label class="error"><%= errorMessage %></label>
                    </div>
                    <%    
                        }
                    %>


이를 통해 로그인에 실패하는 에러가 발생하면, 로그인 창에서 바로 문구가 출력되는 모습을 볼 수 있습니다. 에러메시지를 구현하는 과정을 잠시후 살펴본 후 다시 설명하도록 하겠습니다.



login을 완료하면 action을 통해 login_action.jsp로 이동합니다.


login_action.jsp

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
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
    
<%@ page import="javax.servlet.RequestDispatcher" %> 
 
<%@ page import="net.slipp.user.User" %>
<%@ page import="net.slipp.db.Database" %>
<%@ page import="net.slipp.user.UserNotFoundException"%>
<%@ page import="net.slipp.user.PasswordMismatchException"%>
 
<% 
    request.setCharacterEncoding("UTF-8");
    response.setContentType("text/html;charset=UTF-8"); // 한글 깨지지 않도록
 
    String userId = request.getParameter("userId");
    String password = request.getParameter("password");
    
    try{
        User.login(userId, password);
        session.setAttribute("userId", userId);
        
        response.sendRedirect("/"); // 메인페이지로 다시 이동
    } catch(UserNotFoundException e){
        request.setAttribute("errorMessage""존재하지 않는 사용자입니다. 다시 로그인 하세요.");
        RequestDispatcher rd = request.getRequestDispatcher("login.jsp");
        rd.forward(request, response);
    } catch(PasswordMismatchException e){
        request.setAttribute("errorMessage""비밀번호가 틀렸습니다. 다시 로그인 하세요.");
        RequestDispatcher rd = request.getRequestDispatcher("login.jsp");
        rd.forward(request, response);
    }
    
%>
cs


하나씩 차근차근 살펴볼게요. 

로그인에서 사용된 유저 아이디와 비밀번호를 request.getParameter를 통해 받아오고 있습니다.


이제 try catch문을 통해, 로그인 값이 들어오는 과정을 작성합니다.


catch문은 로그인 과정에서 발생할 수 있는 오류들을 나타내고 있습니다.

현재 로그인 값은 session을 이용해서 정보를 저장하고 있는데요. 기본적으로 User 클래스에서 boolean으로 생성한 login 메소드를 통해 아이디와 비밀번호를 매개변수로 받은 후, 이상이 없으면 sendRedirect로 다시 메인화면으로 이동하는 try 코드를 볼 수 있습니다.


이때 catch를 통해서 두 가지 오류를 만들었습니다. 첫째는 존재하지 않는 아이디를 입력했을 때, 둘째는 아이디는 존재하지만 비밀번호가 틀렸을 때를 보여주고 있습니다. 


에러 발생으로 catch문이 실행되면, 각자 설정된 errorMessage가 만들어집니다. Request에 있는 Dispatcher를 통해서 forward 메소드를 통해 login.jsp로 다시 보내는 모습을 볼 수 있습니다.



다시 login.jsp의 에러메시지 출력 부분을 볼게요.

<%
                        Object errorMessage = request.getAttribute("errorMessage");
                        if(errorMessage != null){
                    %>
                    <div class="control-group">
                        <label class="error"><%= errorMessage %></label>
                    </div>
                    <%    
                        }
                    %>


catch문에서 실행된 에러메시지가 forward로 넘어와 저장됩니다.


조건문을 통해 error가 없으면 그냥 넘어가지만, 에러 발생 시 <%= %> 구문으로 출력을 나타내주고 있습니다.


 

이처럼 에러가 발생하면 노란색 구문으로 login.jsp 화면에서 에러메시지가 표시되는걸 볼 수 있습니다.




우리가 이 에러가 적용되는 메소드는 User 클래스에서 login으로 생성했습니다. 다음은 아까 이전에 그냥 넘어갔던 User.java 코드의 일부분입니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
    public static boolean login(String userId, String password) throws UserNotFoundException, PasswordMismatchException {
        User user = Database.findByUserId(userId);
        
        if(user == null){
            throw new UserNotFoundException();
        }
        
        if(!user.matchPassword(password)){
            throw new PasswordMismatchException();
        }
        
        return true;
    }
 
cs


user 패키지 안에 UserNotFoundException과 PasswordMismatchException 클래스를 만들어 놓고, 로그인 시 입력되는 아이디와 비밀번호를 함수의 매개변수로 가져와 데이터베이스의 findByUserId를 통해서 존재하는 아이디인지 비교하는 과정을 거치고 있습니다.


이어서 조건문을 통해 아이디 자체가 없는 것과, 비밀번호가 틀린것을 만들어준 형태인 것을 이제 이해할 수 있게 됩니다!





아이디와 비밀번호를 알맞게 작성하면, 다시 메인화면으로 이동하게 됩니다. 화면 위의 메뉴바는 아래와 같이 변경될 것입니다.



기존의 로그인과 회원가입 메뉴가, 로그인 성공 후 로그아웃과 개인정보수정으로 변경된 모습을 볼 수 있습니다!


로그인을 취소하는 로그아웃 구현은 매우매우 간단합니다.



logout.jsp

1
2
3
4
5
6
7
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
 
<%
    session.removeAttribute("userId");
 
    response.sendRedirect("/");
%>
cs


간단히 session으로 아이디값을 제거한 후 메인화면으로 이동만 해주면 됩니다.




혹시 로그인이 되어있지 않은 화면과 로그인 성공 후 화면의 메뉴바가 어떻게 변경되는지 궁금할 수도 있는데요.


이는 _top.jspf의 아래와 같은 코드를 보면 됩니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 <%
     Object userId = session.getAttribute("userId");
 %>
              <li><a href="/">Home</a></li>
<%
    if (userId == null) {
%>
              <li><a href="/login.jsp">로그인</a></li>
              <li><a href="/form.jsp">회원가입</a></li>
<%
    } else {
%>                               
              <li><a href="/logout.jsp">로그아웃</a></li>
              <li><a href="">개인정보수정</a></li>   
<%
    }
%>    
cs


유저의 아이디 값을 받아온 후, id가 null로 없으면 로그인과 회원가입 메뉴를 출력하고 id 값이 존재하면 else문에 존재하는 로그아웃과 개인정보수정 메뉴를 출력하는 것을 알 수 있습니다.







지금까지 메인 홈페이지에서 회원가입을 하고, 로그인 과정을 통해 아이디나 비밀번호가 다를 시 오류메시지를 출력하는 것을 구현해냈습니다! 뿌듯


또한 로그아웃으로 다시 원 상태로 복귀 또한 가능합니다. 앞으로는 개인정보수정도 폼을 만들어 수정해야 하는 부분이 남아있습니다.



다음으로 진행될 강의의 제목은 JSP와 서블릿의 역할 분리입니다.

지금 우리의 코드는 JSP에도 자바 코드를 너무 많이 작성하고 있는 모습을 볼 수 있는데요. 왠지 jsp에서 보기 힘든 부분을 서블릿으로 역할을 나누어 효율적으로 관리하는 방법을 배우지 않을까 예상이 됩니다.


또 강의를 듣고 이어서 포스팅을 하겠습니다~!


반응형