ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • JDBC+DAO 활용한 회원 리스트 만들기
    framework/Spring 2018. 7. 30. 18:57
    반응형

    지난번에는 Servlet를 이용하여 회원 리스트를 만들어 보았다. 그 방법에서는 모든 코드를 서블릿 안에서 처리해야 하기 때문에 중복되는 코드가 많고 코드가 서로 섞이고 유지보수에 어려운 점이 많았다. 이번에는 DAO를 이용하여 Servlet을 분리해 보도록 하겠다.



    1) domain패키지와 Member클래스 생성



    우선 src/main/java 아래에 domain 패키지를 생성하고 패키지 아래에 Member 클래스를 만든다. Member 클래스는 자료를 저장하는 모델이 된다. Member 클래스의 코드는 아래와 같다.


    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
    package domain;
     
    public class Member {
     
        private String id;
        private String email;
        private String password;
     
        public String getId() {
            return id;
        }
     
        public void setId(String id) {
            this.id = id;
        }
     
        public String getEmail() {
            return email;
        }
     
        public void setEmail(String email) {
            this.email = email;
        }
     
        public String getPassword() {
            return password;
        }
     
        public void setPassword(String password) {
            this.password = password;
        }
    }
     
    cs



    2) DAO 패키지와 클래스를 만든다.


    DAO는 Data Access Object의 약자로 Database에 접근하는 객체를 의미한다. 지금은 Servlet에 섞여있는 코드를 분리해 DAO를 만들어 보자. 먼저 DAO 패키지와 클래스를 만든다.



    원래 Servlet 코드에 함께 포함된 부분은 다음과 같다.


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
                try {
                Class.forName("com.mysql.jdbc.Driver"); // mysql-jdbc driver를 로딩한다
                try (                                   // forName 안에 물리적 주소를 넣으면 클래스를 반환
                        Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/testdb"// mysqldb에 접속하는
                                "test""1111"); // Connection 객체를 만듭니다
                        PreparedStatement stmt = con.prepareStatement("select mid, email from member"); // sql 쿼리문을
                                                                                                             // 저장하는 객체
                        ResultSet rs = stmt.executeQuery();) { // 쿼리문을 전송해서 반환되는 값을
                                                               // 저장하는 resultset
                    while (rs.next()) { // resultset에 값이 있으면 반복문을 계속 수행한다
                        out.println("<tr>");
                        out.printf("    <td><a href='view?id=%s'>%s</a></td><td>%s</td>\n", rs.getString("mid"),
                                rs.getString("mid"), rs.getString("email"));
                        out.println("</tr>");
                    }
                }
            } catch (Exception e) {
                out.println("<p>목록 가져오기 실패!</p>");  //에러처리
                e.printStackTrace(out);
            }
    cs


    이 부분은 DAO로 분리해서 꺼낸다. DAO 클래스의 코드는 다음과 같다.


    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
    package dao;
     
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.util.ArrayList;
    import java.util.List;
     
    import domain.Member;
     
    public class MemberDao {
     
        private String jdbcUrl;
        private String username;
        private String password;
     
        // 생성자를 통해 Dao에 필요한 필드변수를 꽂아준다.
        public MemberDao(String jdbcUrl, String username, String password) {
            this.jdbcUrl = jdbcUrl;
            this.username = username;
            this.password = password;
     
            try {
                // 처음 객체가 생성될 때 드라이브를 로딩한다.
                Class.forName("com.mysql.jdbc.Driver");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
     
        public List<Member> selectList() throws Exception {
     
            try (
                    // mysqldb에 접속
                    Connection con = DriverManager.getConnection(jdbcUrl, username, password);
                    PreparedStatement stmt = con.prepareStatement("select mid, email from member");
                    ResultSet rs = stmt.executeQuery();) {
     
                List<Member> list = new ArrayList<>();
                while (rs.next()) {
                    // 이전 Servlet 버전에서 이 부분에서 바로 출력을 했으나
                    // DAO에서는 객체에 값을 집어넣어 리턴한다.
                    Member member = new Member();
                    member.setId(rs.getString("mid"));
                    member.setEmail(rs.getString("email"));
                    list.add(member);
                }
     
                return list;
            }
        }
    }
     
    cs



    3) servlet 부분 수정


    이제 servlet 부분도 수정해 줘야한다. MemberDao를 선언하고 생성자를 통해 필요한 값을 주입하는데 이를 의존성 주입이라고 하며 Spring에서 핵심적인 개념이다. 아래 코드를 보자.


    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
    package servlet;
     
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.util.List;
     
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
     
    import dao.MemberDao;
    import domain.Member;
     
    // @는 annotation을 뜻한다, annotation은 서버에 알려주는 역할을 한다.
    @WebServlet("/member/list"// "/member/list" 라는 요청이 URL로 오면 이 클래스를 실행한다.
    public class MemberList extends HttpServlet {
        // HttpServlet 클래스를 상속받으면 해당 클래스가 servlet으로 동작하게 한다
        // 상속받은 클래스에서 doGet 메서드를 오버라이드 해서 get요청을 받아서 처리한다.
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            response.setContentType("text/html;charset=UTF-8"); // characterset 을 utf8로 지정
     
            PrintWriter out = response.getWriter(); // 화면에 직접 html 코드를 출력하는 객체이다
            out.println("<!DOCTYPE html>"); // 여기서 작성된 태그는 버퍼에 저장되었다가
            out.println("<html>"); // 한번에 전송된다.
            out.println("<head>");
            out.println("<meta charset='UTF-8'>");
            out.println("<title>멤버 목록</title>");
            out.println("</head>");
            out.println("<body>");
            out.println("<h1>멤버 목록</h1>");
            out.println("<p><a href='add.html'>새회원</a></p>");
            out.println("<table border='1'>");
            out.println("<tr>");
            out.println("    <th>아이디</th><th>이메일</th>");
            out.println("</tr>");
     
            try {
                // memberDao 객체를 만들며 생성자에 주소와 아이디 비밀번호를 꽂아준다.
                MemberDao memberDao = new MemberDao("jdbc:mysql://localhost:3306/testdb""test""1111");
                List<Member> list = memberDao.selectList();
                // memberDao로부터 받은 객체 리스트를 출력한다.
                for (Member member : list) {
                    out.println("<tr>");
                    out.printf("    <td><a href='view?id=%s'>%s</a></td><td>%s</td>\n", member.getId(), member.getId(),
                            member.getEmail());
                    out.println("</tr>");
                }
            } catch (Exception e) {
                out.println("<p>목록 가져오기 실패!</p>"); // 에러처리
                e.printStackTrace(out);
            }
     
            out.println("</table>");
            out.println("</body>");
            out.println("</html>");
        }
    }
     
    cs


    위와같이 servlet클래스를 수정하면 아래와 같이 실행되는 것을 확인할 수 있다.




    4) ServletContextListener


    DAO를 만들어 db 접근 부분을 분리해 낸 것은 성공했지만 한가지 문제점이 남아있다. 바로 페이지를 호출할 때 마다 MemberDao 객체를 계속 생성한다는 것이다. 이렇게 하면 메모리의 낭비가 생길 뿐더러 각 객체마다 연결이 유지되어 여러개의 연결이 서로 충돌을 일으키는 경우가 생길 수 있다.


    이를 해결하기 위해 ServletContextListener를 도입한다. servletContext는 각 application마다 하나씩만 유지 되기 때문에 application이 끝날때까지 유지가 된다. 때문에 모든 사용자가 굥유하는 자원을 저장하기에 적합하다. ServletContext 보관소에 DAO 객체를 저장하면 한 번의 객체 생성으로 application 종료시까지 유지할 수 있다.


    src/main/java 아래 listener 패키지를 만들고 ContextLoaderListener 클래스를 생성한다.


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    package listener;
     
    import javax.servlet.ServletContext;
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    import javax.servlet.annotation.WebListener;
     
    import dao.MemberDao;
     
    @WebListener
    public class ContextLoaderListener implements ServletContextListener { //ServletContextListener를 상속한다.
     
        //contextInitialized 는 context가 시작될 때 수행되는 메서드이다.
        @Override
        public void contextInitialized(ServletContextEvent sce) {
            MemberDao memberDao = new MemberDao("jdbc:mysql://localhost:3306/testdb""test""1111");
            
            ServletContext sc = sce.getServletContext(); // ServletContext 객체를 받아서
            sc.setAttribute("memberDao", memberDao);     // memberDao 객체를 attribute에 추가해 준다.
        }
    }
     
    cs


    이후 servlet에 memberDao 생성 부분을 다음과 같이 변경한다.


    1
    2
    ServletContext sc = this.getServletContext(); //ServletContext에서 MemberDao를 받는다
    MemberDao memberDao = (MemberDao)sc.getAttribute("memberDao");

    cs




    이제 JDBC와 DAO를 활용한 회원 리스트를 완벽하게 만들었다.

    반응형
Designed by Tistory.